2013-05-27 30 views
23

Tôi đang cố gắng tìm hiểu lý do tại sao AsyncTask của Android cung cấp thông số qua execute và tại sao việc truyền cho nhà xây dựng dường như không được thực hiện (trong tài liệu, ít nhất).Tôi có nên cung cấp thông số cho hàm tạo hoặc AsyncTask.execute (params) không?

Đây là cách mà dường như với tôi để làm cho ý nghĩa nhất (một cách tự nhiên, nhiệm vụ thực tế tôi đang làm việc với là nhiều hơn chỉ là một máy tính tổng hợp):

public class FooTask extends AsyncTask<Void, Integer, Long> { 
    private ProgressBar progressBar; 
    private int[] data; 

    public FooTask(ProgressBar progressBar, int... data) { 
     this.progressBar = progressBar; 
     this.data = data; 
    } 

    protected void onPreExecute() { 
     progressBar.setMax(data.length); 
     progressBar.setProgress(0); 
    } 

    protected Long doInBackground(Void... _) { 
     long sum = 0; 
     for (int i = 0; i < data.length; i++) { 
      sum += data[i]; 
      publishProgress(i); 
     } 
     return sum; 
    } 

    protected void onProgressUpdate(Integer... progress) { 
     progressBar.setProgress(progress[0]); 
    } 

    protected void onPostExecute(Long result) { 
     Log.i(TAG, "Sum: " + result); 
    } 
} 

này sẽ được sử dụng như sau:

new FooTask(progressBar, 1, 2, 3).execute(); 

Tuy nhiên, đây không phải là cách tài liệu thảo luận về việc thực hiện; nó sử dụng đối số cho execute(), như thế này (đưa đến sự khắc nghiệt của không sử dụng một constructor ở tất cả, nhưng vẫn còn sử dụng một lĩnh vực bởi vì nếu không nó sẽ là quá khủng khiếp):

public class FooTask extends AsyncTask<Object, Integer, Long> { 
    private ProgressBar progressBar; 
    private boolean isMaxSettingUpdate = true; 

    protected Long doInBackground(Object... params) { 
     progressBar = params[0]; 
     long sum = 0; 
     for (int i = 1; i < data.length; i++) { 
      sum += (int) data[i]; 
      publishProgress(i - 1, data.length); 
     } 
     return sum; 
    } 

    protected void onProgressUpdate(Integer... progress) { 
     progressBar.setMax(progress[1]); 
     progressBar.setProgress(progress[0]); 
    } 

    protected void onPostExecute(Long result) { 
     Log.i(TAG, "Sum: " + result); 
    } 
} 

Thi hành nhiệm vụ này sẽ xem xét thêm như thế này:

new FooTask().execute(progressBar, 1, 2, 3); 

Một lựa chọn khác tôi coi được đưa ra các thanh tiến trình để các nhà xây dựng và các dữ liệu vào thực hiện cuộc gọi, nhưng sau đó tôi vẫn không thể sử dụng onPreExecute như tôi không biết giá trị tối đa. (Tôi muốn sử dụng giá trị tối đa thực sự hơn là đặt giá trị tối đa tùy ý và tính tỷ lệ phần trăm ... có vẻ đẹp hơn.)

Số dư ở đâu? Tôi nên làm gì? Có bất kỳ điều gì sai bằng cách sử dụng hàm tạo không?

Trả lời

11

Tại sao các tài liệu thực hiện mọi thứ trong phương pháp có thể là kết quả của lựa chọn ví dụ của chúng. Thông thường, bạn có nhiều khả năng mở rộng AsyncTask của mình và chỉ sử dụng doInBackground(), chứ không phải hàm tạo.

Anyways, documentation states:

Memory năng quan sát


đảm bảo AsyncTask rằng tất cả các cuộc gọi callback được đồng bộ hóa trong đó một cách mà các hoạt động sau đây được an toàn mà không rõ ràng đồng bộ.

• Đặt trường thành viên trong hàm tạo hoặc onPreExecute() và tham chiếu chúng trong> doInBackground (Params ...).

• Đặt trường thành viên trong doInBackground (Params ...) và tham chiếu chúng trong onProgressUpdate (Progress ...) và onPostExecute (Result).

Điều này có nghĩa là bạn nên làm tốt với cả hai cách tiếp cận.

Và như một lưu ý phụ, tôi đã sử dụng một AsyncTask với hàm tạo tham số không có vấn đề, vì vậy tôi có thể sao lưu tài liệu nêu rõ.

Ngoài ra, đối với trường hợp cụ thể của bạn, trừ khi ProgressBar có giá trị tối đa khác nhau được đặt trước, giá trị mặc định phải là 100.Điều này có nghĩa là bạn có thể có hàm tạo của bạn chấp nhận chỉ trong ProgressBar và có doInBackground() chấp nhận trong dữ liệu (cũng phải là biến thành viên). Sau đó, khi cập nhật tiến trình, hãy làm

(progress[0]/data.length) * 100 

Nó sẽ không hoàn hảo và bạn có thể chuyển đổi thành gấp đôi nếu bạn muốn tăng độ chính xác, nhưng điều này sẽ làm cho mã dễ hiểu nhất.

+0

Bạn sẽ làm gì? Có thích hợp để vượt qua nó như thế không? –

+0

Vì bạn cần 'onPreExecute()', tôi sẽ đi với phương thức tiếp cận đầu tiên của hàm dựng, nó đáp ứng yêu cầu và dễ đọc hơn. Bạn sẽ phải xem ra cho những thay đổi định hướng mặc dù. Vì các Hoạt động/Phân đoạn được tạo lại, Nhiệm vụ của bạn sẽ giữ nguyên tham chiếu cũ của thanh tiến trình nếu điều đó xảy ra, do đó thanh không nên cập nhật cho người dùng. –

+0

Oh! Cho thấy tôi hiểu cách Android hoạt động trong nội bộ. Nó chưa bao giờ xảy ra với tôi để nghĩ khác hơn là họ sẽ là cùng một đối tượng trước và sau. Tôi thấy như vậy mà đi qua thanh tiến trình là * không * an toàn. Cảm ơn bạn đã xóa thông tin đó! –

2

Theo ý kiến ​​của tôi, nếu tôi muốn chuyển một số giá trị để khởi tạo giao diện người dùng, giống như ProgressBar bạn đã đề cập, tôi cần thực hiện trong OnPreExecute(). Và bởi vì OnPreExecute() không chấp nhận bất kỳ tham số nào, tôi thích đặt giá trị trong hàm tạo làm tham số. Nếu một số giá trị không liên quan đến giao diện người dùng, chỉ cần trong doInBackground, ví dụ: url tải xuống tệp, tôi sẽ chuyển chúng dưới dạng thông số thực thi. Vì vậy, trong một bản tóm tắt, nếu các giá trị là về giao diện người dùng, chuyển chúng vào hàm dựng, nếu các giá trị chỉ được sử dụng trong doInBackground, hãy chuyển chúng thành các tham số thực thi.

0

Nếu bạn muốn thực hiện công việc (yêu cầu tham số) trên luồng chính, bạn phải chuyển các tham số đó tới hàm tạo.

Mọi thứ bạn vượt qua .execute() sẽ được chạy trên chuỗi không đồng bộ.

Như buptcoder đã đề cập, chủ yếu là sẽ liên quan đến công cụ giao diện người dùng, nhưng cũng hoạt động đĩa/cơ sở dữ liệu có thể là chủ đề quan trọng

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