2012-08-28 33 views
27

Tôi có 2 ASyncTask, một truy xuất giá trị từ httpPost và bản cập nhật khác một số thành phần của giao diện người dùng (bao gồm cả chế độ xem danh sách). Vấn đề là vì cả hai ASyncTask đều chia sẻ cùng một luồng nền, nếu opper mạng bắt đầu đầu tiên và chạy chậm (do kết nối mạng kém). Các chủ đề nền khác mất quá nhiều thời gian làm cho ứng dụng vô trách nhiệm.ASyncTask chặn người khác

Vì cả hai ASyncTask là độc lập nên khá là ngu ngốc để chờ người khác. Nó sẽ là asynctasks hợp lý hơn các lớp khác nhau sử dụng các chủ đề khác nhau, tôi có sai không?

Đọc tài liệu ASyncTask. Nói về việc sử dụng executeOnExecutor(), nhưng làm cách nào tôi có thể giải quyết điều đó ở cấp API thấp hơn 11?

Ở đây đi một ví dụ nhỏ mà tái tạo các "vấn đề"

 new Task1().execute(); 
     new Task2().execute(); 

Với

public class Task1 extends AsyncTask<Void, Void, Void> { 

    @Override 
    protected Void doInBackground(Void... params) { 
     GLog.e("doInBackground start 1"); 
     SystemClock.sleep(9000); 
     GLog.e("doInBackground end 1"); 
     return null; 
    } 

    @Override 
    protected void onPreExecute() { 
     GLog.e("onPreExecute 1"); 
     super.onPreExecute(); 
    } 

    @Override 
    protected void onPostExecute(Void result) { 
     GLog.e("onPostExecute 1"); 
     super.onPostExecute(result); 
    } 

} 

public class Task2 extends AsyncTask<Void, Void, Void> { 

    @Override 
    protected void onPreExecute() { 
     GLog.e("onPreExecute 2"); 
     super.onPreExecute(); 
    } 

    @Override 
    protected Void doInBackground(Void... params) { 
     GLog.e("doInBackground start 2"); 
     SystemClock.sleep(9000); 
     GLog.e("doInBackground end 2"); 
     return null; 
    } 

    @Override 
    protected void onPostExecute(Void result) { 
     GLog.e("onPostExecute 2"); 
     super.onPostExecute(result); 
    } 

} 
+0

Tại sao bạn có AsyncTask để cập nhật giao diện người dùng? Bạn cần phải thực hiện đồng bộ trên chuỗi Ii. Giao diện người dùng của bạn AsyncTask có làm gì khác trên luồng nền không? –

+0

Tôi sử dụng nó ví dụ để hiển thị một listview với các tin tức. Trong onPreExecute tôi hiển thị giao diện loading(), trong nền lấy thông tin từ Internet và trong onPostExecute gán adapter cho listview. Cách tiếp cận đó có đúng không? – Addev

+0

@Addev: Tại sao bạn không chỉ bắt đầu 'AsyncTask' thứ hai trong phương thức' onPostExecute (...) 'đầu tiên? Nếu những gì bạn cần là một trong những 'AsyncTask' dựa trên kết quả của khác thì bạn có hiệu quả có một yêu cầu đồng bộ và bạn không nên chạy hai hoạt động không đồng bộ song song. – Squonk

Trả lời

46

Đây là cách tôi xử lý này trong mã của tôi:

if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { 
    new MyAsyncTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 
} else { 
    new MyAsyncTask().execute(); 
} 

Và thay MyAsyncTask với số điện thoại của bạn Task1Task2 tương ứng. Về cơ bản thay đổi trong AsyncTask xuất hiện trong Honeycomb (xem tài liệu SDK Android here trong phần "Lệnh thực thi"), vì vậy trước đó, bạn khởi chạy nó như thường lệ, cho HC trở lên, sử dụng executeOnExecutor() nếu bạn không thích hành vi mới (không ai, tôi nghĩ rằng)

7

một cách hơi tổng quát hơn để làm điều này là để đưa hai phương pháp helper trong một lớp tiện ích như vậy:

class Utils { 

    @SuppressLint("NewApi") 
    public static <P, T extends AsyncTask<P, ?, ?>> void execute(T task, P... params) { 
     if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { 
      task.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params); 
     } else { 
      task.execute(params); 
     } 
    } 
} 

Sau đó, bạn có thể thực hiện nhiệm vụ với Utils.execute(mytask) hoặc Utils.execute(mytask, params) và nó sẽ chăm sóc thực thi chúng song song.

+0

Cảm ơn. Lưu ý cho hậu thế, đừng bận tâm cố gắng ghi đè lên 'AsyncTask.execute()' - bạn không thể; đó là 'cuối cùng'. – TalkLittle

+0

Ngoài ra phương pháp đầu tiên là không cần thiết và có thể thực sự gây ra hành vi bất ngờ ('params' có thể là' null' thay vì một mảng trống). Loại bỏ nó biên dịch/chạy tốt trên các thiết bị trước Honeycomb. – TalkLittle

+0

Nó không phải là không cần thiết, nó tiết kiệm gõ :) –

0

Vấn đề là mọi AsyncTask chạy trong cùng một ThreadPoolExecutor được mã hóa vào API. ThreadPoolExecutor này có thể tạo ra một số lượng WorkerThread khác nhau tùy thuộc vào phiên bản Android của bạn. Tôi không nhớ các phiên bản số nhưng ý tưởng là trong các phiên bản Android cũ hơn là 1 WorkerThread. Sau đó, nó được cập nhật thành 5 phiên bản sau. Và gần đây đã chuyển trở lại 1 lần nữa. Đây là lý do tại sao AsyncTask của bạn bị chặn. Chúng chạy trên cùng một WorkerThread và do đó chúng thực hiện tuần tự. Hãy thử sử dụng executeOnExecutor với THREAD_POOL_EXECUTOR để đạt được thực thi song song thực sự. Tuy nhiên, bạn chỉ có thể sử dụng điều này từ API 11.

Các vấn đề liên quan