Per 15/2/2012 saya belum menemukan penjelasan yang baik atau alasan mengapa ini tidak berhasil. Solusi terdekat adalah dengan menggunakan pendekatan Thread tradisional , tetapi mengapa menyertakan kelas yang tidak (tampaknya) berfungsi di Android SDK?
Evenin 'SO!
Saya memiliki subkelas AsyncTask:
// ParseListener had a callback which was called when an item was parsed in a
// RSS-xml, but as stated further down it is not used at all right now.
private class xmlAsync extends AsyncTask<String, RSSItem, Void> implements ParseListener
Itu dijalankan seperti ini:
xmlAsync xmlThread = new xmlAsync();
xmlThread.execute("http://www.nothing.com");
Sekarang subclass ini mengalami sedikit kesalahan. Sebelumnya itu melakukan beberapa xml-parsing, tetapi ketika saya perhatikan bahwa doInBackground () tidak dipanggil, saya melepasnya , baris demi baris, akhirnya berakhir hanya dengan ini:
@Override
protected Void doInBackground(String... params)
{
Log.v(TAG, "doInBackground");
return null;
}
Yang, untuk beberapa alasan, tidak mencatat apa pun. Namun, saya menambahkan ini:
@Override
protected void onPreExecute()
{
Log.v(TAG, "onPreExecute");
super.onPreExecute();
}
Dan baris itu memang dicatat saat menjalankan utas. Jadi entah bagaimana onPreExecute () dipanggil tetapi tidak doInBackground () . Saya memiliki AsyncTask lain yang berjalan di latar belakang pada saat yang sama yang berfungsi dengan baik.
Saat ini saya menjalankan aplikasi di emulator, SDK Versi 15, Eclipse, Mac OS X 10.7.2, dekat Kutub Utara.
EDIT:
@Override
protected void onProgressUpdate(RSSItem... values) {
if(values[0] == null)
{
// activity function which merely creates a dialog
showInputError();
}
else
{
Log.v(TAG, "adding "+values[0].toString());
_tableManager.addRSSItem(values[0]);
}
super.onProgressUpdate(values);
}
_tableManager.addRSSItem () sedikit banyak menambahkan baris ke SQLiteDatabase, diinisialisasi dengan konteks aktivitas. publishProgress () dipanggil oleh callback Interface ParseListener. Namun, karena saya bahkan tidak melakukan apa pun kecuali log.v di doInBackground () saya pertama kali menemukan ini bahkan tidak perlu untuk dimunculkan.
EDIT 2:
Baiklah, untuk memperjelas, ini adalah AsyncTask lainnya, yang dijalankan dalam aktivitas yang sama dan berfungsi dengan baik.
private class dbAsync extends AsyncTask<Void, RSSItem, Void>
{
Integer prevCount;
boolean run;
@Override
protected void onPreExecute() {
run = true;
super.onPreExecute();
}
@Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
run = true;
prevCount = 0;
while(run)
{
ArrayList<RSSItem> items = _tableManager.getAllItems();
if(items != null)
{
if(items.size() > prevCount)
{
Log.v("db Thread", "Found new item(s)!");
prevCount = items.size();
RSSItem[] itemsArray = new RSSItem[items.size()];
publishProgress(items.toArray(itemsArray));
}
}
SystemClock.sleep(5000);
}
return null;
}
@Override
protected void onProgressUpdate(RSSItem... values) {
ArrayList<RSSItem> list = new ArrayList<RSSItem>();
for(int i = 0; i < values.length; i++)
{
list.add(i, values[i]);
}
setItemsAndUpdateList(list);
super.onProgressUpdate(values);
}
@Override
protected void onCancelled() {
run = false;
super.onCancelled();
}
}
EDIT 3:
Sigh, maaf saya buruk dalam mengajukan pertanyaan. Tapi di sini adalah inisialisasi Tugas.
xmlAsync _xmlParseThread;
dbAsync _dbLookup;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
_dbLookup = new dbAsync();
_dbLookup.execute();
_xmlParseThread = new xmlAsync();
_xmlParseThread.execute("http://www.nothing.com", null);
}
Jawaban:
Solusi Matthieu akan bekerja dengan baik untuk sebagian besar orang, tetapi beberapa dapat menghadapi masalah; kecuali menggali banyak tautan yang disediakan di sini atau dari web, seperti penjelasan Anders Göransson . Saya mencoba meringkas beberapa bacaan lain di sini dan dengan cepat menjelaskan solusi jika executeOnExecutor masih berfungsi dalam satu utas ...
Perilaku
AsyncTask().execute();
telah berubah melalui versi Android. Sebelum tugas Donut (Android: 1.6 API: 4) dijalankan secara serial, dari Donut hingga Gingerbread (Android: 2.3 API: 9) tugas dijalankan secara paralel; sejak Honeycomb (Android: 3.0 API: 11) eksekusi dialihkan kembali ke sekuensial;AsyncTask().executeOnExecutor(Executor)
namun metode baru ditambahkan untuk eksekusi paralel.Dalam pemrosesan berurutan, semua tugas Async dijalankan dalam satu utas dan karenanya harus menunggu sebelum tugas sebelumnya berakhir. Jika Anda perlu segera menjalankan kode, Anda memerlukan tugas untuk diproses secara paralel di utas terpisah.
Dengan AsyncTask, eksekusi serial tidak tersedia antara versi Donut dan Honeycomb, sementara eksekusi paralel tidak tersedia sebelum Donut.
Untuk pemrosesan paralel setelah Donut: Periksa versi Build dan berdasarkan metode use .execute () atau .executeOnExecutor () itu. Kode berikut dapat membantu ...
AsyncTask<Void,Void,Void> myTask = new AsyncTask<Void,Void,Void>() { ... }; // ... your AsyncTask code goes here if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB) myTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); else myTask.execute();
NOTE:
Fungsi.executeOnExecutor()
memiliki pemeriksaan apakahtargetSdkVersion
proyek kurang dari atau sama denganHONEYCOMB_MR1
(Android: 2.1 API: 7) kemudian memaksa eksekutor untuk menjadiTHREAD_POOL_EXECUTOR
(yang menjalankan Tugas secara berurutan di pos Honeycomb).Jika Anda belum menentukan
targetSdkVersion
makaminSdkVersion
secara otomatis dianggap sebagaitargetSdkVersion
.Karenanya untuk menjalankan AsyncTask Anda secara paralel pada posting Honeycomb, Anda tidak dapat membiarkannya
targetSdkVersion
kosong.sumber
Anda harus memeriksa jawaban ini: https://stackoverflow.com/a/10406894/347565 dan tautan ke grup google yang disertakan.
Saya memiliki masalah yang sama dengan Anda, masih tidak jelas mengapa itu tidak berfungsi, tetapi saya mengubah kode saya seperti ini dan masalahnya hilang:
ASyncTask<Void,Void,Void> my_task = new ASyncTask<Void,Void,Void>() { ... }; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) my_task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, (Void[])null); else my_task.execute((Void[])null);
sumber
Anda dapat melakukannya dengan dua cara:
Cara 1 :
if(Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB) // Above Api Level 13 { asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } else // Below Api Level 13 { asyncTask.execute(); }
Jika cara 1 tidak berhasil untuk Anda, coba cara 2 .
Cara 2 :
int mCorePoolSize = 60; int mMaximumPoolSize = 80; int mKeepAliveTime = 10; BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<Runnable>(mMaximumPoolSize); Executor mCustomThreadPoolExecutor = new ThreadPoolExecutor(mCorePoolSize, mMaximumPoolSize, mKeepAliveTime, TimeUnit.SECONDS, workQueue); asyncTask.executeOnExecutor(mCustomThreadPoolExecutor);
Semoga ini bisa membantu Anda.
sumber
Saya memiliki masalah yang sama: tidak dapat mengeksekusi AsyncTask kedua setelah saya memanggil "mengeksekusi" pada yang pertama: doInBackground hanya dipanggil untuk yang pertama.
Untuk menjawab mengapa ini terjadi, periksa jawaban ini (perilaku berbeda tergantung pada SDK)
Namun, untuk kasus Anda, kendala ini dapat dihindari dengan menggunakan executeOnExecutor (tersedia mulai dari 3.0 yang berfungsi untuk saya menggunakan 4.0.3) tetapi waspadalah terhadap batasan ukuran dan antrian kumpulan Thread.
Bisakah Anda mencoba sesuatu seperti ini:
xmlAsync _xmlParseThread; dbAsync _dbLookup; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); _dbLookup = new dbAsync(); _dbLookup.execute(); _xmlParseThread = new xmlAsync(); _xmlParseThread.executeOnExecutor(_dbLookup.THREAD_POOL_EXECUTOR ,"http://www.nothing.com", null); }
Untuk pertanyaan pembaruan Anda: dijelaskan di dokumen Pada dasarnya hanya untuk menghindari semua masalah yang mungkin datang dari multithreading seperti intereferensi ....
sumber
Satu hal yang ingin saya ketahui, dan itu mungkin benar-benar memperbaiki masalah Anda, adalah di mana Anda membuat instance kelas Anda dan memanggil metode execute ()? Jika Anda membaca dokumentasi untuk AsyncTask, kedua operasi tersebut harus berlangsung di thread UI utama. Jika Anda membuat objek dan memanggil eksekusi dari beberapa utas lain, maka onPreExecute mungkin aktif, saya tidak 100% yakin di sini, tetapi utas latar belakang tidak akan dibuat dan dijalankan.
Jika Anda membuat instance AsyncTask dari thread latar belakang, atau beberapa operasi lain yang tidak berlangsung pada thread UI utama, Anda dapat mempertimbangkan untuk menggunakan metode: Activity.runOnUiThread (Runnable)
Anda memerlukan akses ke instance Activity yang sedang berjalan untuk memanggil metode itu, tetapi itu akan memungkinkan Anda menjalankan kode pada UI thread dari beberapa kode lain yang tidak berjalan di UI thread.
Harapan itu masuk akal. Beri tahu saya jika saya dapat membantu lebih lanjut.
David
sumber
Android itu Brutal! Saya tidak percaya ini, implementasi yang tidak stabil yang berubah dari hari ke hari. Suatu hari ini adalah satu utas, selanjutnya 5 utas lainnya adalah 128.
Ngomong-ngomong di sini ada hampir penurunan pengganti stok AsyncTask. Anda bahkan dapat menyebutnya AsyncTask jika Anda mau, tetapi untuk menghindari kebingungan, ini disebut ThreadedAsyncTask. Anda perlu memanggil executeStart () daripada menjalankan karena execute () sudah final.
/** * @author Kevin Kowalewski * */ public abstract class ThreadedAsyncTask<Params, Progress, Result> extends AsyncTask<Params, Progress, Result> { public AsyncTask<Params, Progress, Result> executeStart(Params... params){ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){ return executePostHoneycomb(params); }else{ return super.execute(params); } } @TargetApi(Build.VERSION_CODES.HONEYCOMB) private AsyncTask<Params, Progress, Result> executePostHoneycomb(Params... params){ return super.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params); } }
sumber
Saya tahu ini mungkin sangat terlambat untuk utas, tetapi ada alasan mengapa itu tidak akan berfungsi pada emulator Android nanti. Ketika asynctask diperkenalkan android hanya membiarkan Anda menjalankan satu per satu, kemudian beberapa saat kemudian, saya tidak yakin versi yang mana, mereka memungkinkan Anda untuk menjalankan beberapa asynctask sekaligus, ini menyebabkan masalah di banyak aplikasi, dan di Honeycomb + mereka kembali ke hanya memungkinkan satu asynctask dijalankan pada satu waktu. Kecuali Anda mengubah kumpulan utas secara manual. Harapan yang menjelaskan satu atau dua hal bagi orang-orang.
sumber
Saya pikir itu SDK. saya memiliki masalah yang sama, dan setelah mengubah sdk target dari 15 menjadi 11, semuanya bekerja dengan sempurna.
dengan sdk15, meskipun AsyncTask.Status sedang RUNNING, doInBackground tidak pernah dipanggil. Saya pikir itu ada hubungannya dengan utas ui sekalipun.
sumber
Berdasarkan jawaban Matthieu, di bawah kelas pembantu untuk mengeksekusi Anda
AsyncTask
dengan benar bergantung pada versi SDK untuk menghindari duplikasi kode dalam aplikasi Anda:import android.annotation.SuppressLint; import android.os.AsyncTask; import android.os.Build; public class AsyncTaskExecutor<Params, Progress, Result> { @SuppressLint("NewApi") public AsyncTask<Params, Progress, Result> execute(final AsyncTask<Params, Progress, Result> asyncTask, final Params... params){ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){ return asyncTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params); } else{ return asyncTask.execute(params); } } }
Contoh penggunaan:
public class MyTask extends AsyncTask<Void, Void, List<String>> {
...
final MyTask myTask = new MyTask(); new AsyncTaskExecutor<Void, Void, List<String>>().execute(myTask);
sumber