Là AsyncTask thực sự thiếu sót về mặt khái niệm hay tôi chỉ thiếu một cái gì đó?


264

Tôi đã điều tra vấn đề này trong nhiều tháng nay, đưa ra các giải pháp khác nhau cho nó, điều mà tôi không hài lòng vì tất cả chúng đều là những vụ hack lớn. Tôi vẫn không thể tin rằng một lớp học thiếu sót trong thiết kế đã đưa nó vào khuôn khổ và không ai nói về nó, vì vậy tôi đoán rằng tôi chỉ cần thiếu một cái gì đó.

Vấn đề là với AsyncTask. Theo tài liệu đó

"cho phép thực hiện các thao tác nền và xuất bản kết quả trên luồng UI mà không phải thao tác với các luồng và / hoặc trình xử lý."

Ví dụ sau đó tiếp tục cho thấy một số showDialog()phương thức mẫu mực được gọi trong onPostExecute(). Tuy nhiên, điều này dường như hoàn toàn phù hợp với tôi, bởi vì hiển thị hộp thoại luôn cần tham chiếu đến hợp lệ Contextvà AsyncTask không bao giờ phải giữ tham chiếu mạnh đến đối tượng ngữ cảnh .

Lý do rất rõ ràng: nếu hoạt động bị phá hủy sẽ kích hoạt nhiệm vụ thì sao? Điều này có thể xảy ra mọi lúc, ví dụ như vì bạn lật màn hình. Nếu tác vụ giữ tham chiếu đến bối cảnh đã tạo ra nó, bạn không chỉ giữ một đối tượng bối cảnh vô dụng (cửa sổ sẽ bị hủy và mọi tương tác UI sẽ không thành công ngoại lệ!), Bạn thậm chí có nguy cơ tạo ra một ngoại lệ bộ nhớ bị rò rỉ.

Trừ khi logic của tôi bị thiếu sót ở đây, điều này có nghĩa onPostExecute()là : hoàn toàn vô dụng, bởi vì phương pháp này có ích gì khi chạy trên luồng UI nếu bạn không có quyền truy cập vào bất kỳ ngữ cảnh nào? Bạn không thể làm bất cứ điều gì có ý nghĩa ở đây.

Một cách giải quyết khác là không chuyển các thể hiện ngữ cảnh cho AsyncTask, mà là một Handlerthể hiện. Điều đó hoạt động: vì một Handler liên kết lỏng lẻo bối cảnh và nhiệm vụ, bạn có thể trao đổi tin nhắn giữa chúng mà không gặp rủi ro rò rỉ (phải không?). Nhưng điều đó có nghĩa là tiền đề của AsyncTask, cụ thể là bạn không cần bận tâm đến trình xử lý, là sai. Nó cũng có vẻ giống như lạm dụng Handler, vì bạn đang gửi và nhận tin nhắn trên cùng một luồng (bạn tạo nó trên luồng UI và gửi qua nó trong onPostExecute () cũng được thực thi trên luồng UI).

Trên hết, ngay cả với cách giải quyết đó, bạn vẫn có một vấn đề là khi bối cảnh bị phá hủy, bạn không có hồ sơ về các nhiệm vụ mà nó đã bắn. Điều đó có nghĩa là bạn phải bắt đầu lại bất kỳ tác vụ nào khi tạo lại bối cảnh, ví dụ sau khi thay đổi hướng màn hình. Điều này là chậm và lãng phí.

Giải pháp của tôi cho vấn đề này (như được thực hiện trong thư viện Droid-Fu ) là duy trì ánh xạ của WeakReferences từ tên thành phần đến các thể hiện tại của chúng trên đối tượng ứng dụng duy nhất. Bất cứ khi nào AsyncTask được khởi động, nó sẽ ghi lại ngữ cảnh gọi trong bản đồ đó và trên mỗi cuộc gọi lại, nó sẽ tìm nạp phiên bản ngữ cảnh hiện tại từ ánh xạ đó. Điều này đảm bảo rằng bạn sẽ không bao giờ tham chiếu một trường hợp bối cảnh cũ bạn luôn có quyền truy cập vào một bối cảnh hợp lệ trong các cuộc gọi lại để bạn có thể thực hiện giao diện người dùng có ý nghĩa ở đó. Nó cũng không bị rò rỉ, bởi vì các tham chiếu yếu và bị xóa khi không còn trường hợp nào của một thành phần nhất định tồn tại nữa.

Tuy nhiên, đây là một cách giải quyết phức tạp và đòi hỏi phải phân lớp một số lớp thư viện Droid-Fu, làm cho cách tiếp cận này khá khó khăn.

Bây giờ tôi chỉ đơn giản muốn biết: Tôi chỉ thiếu ồ ạt một cái gì đó hay AsyncTask thực sự hoàn toàn thiếu sót? Kinh nghiệm của bạn làm việc với nó như thế nào? Làm thế nào bạn giải quyết những vấn đề này?

Cảm ơn vì đầu vào của bạn.


1
Nếu bạn tò mò, gần đây chúng tôi đã thêm một lớp vào thư viện lõi đánh lửa có tên IgnitedAsyncTask, bổ sung hỗ trợ truy cập ngữ cảnh an toàn loại trong tất cả các cuộc gọi lại bằng cách sử dụng mẫu kết nối / ngắt kết nối được Dianne nêu dưới đây. Nó cũng cho phép ném ngoại lệ và xử lý chúng trong một cuộc gọi lại riêng. Xem github.com/kaeppler/ignition-core/blob/master/src/com/github/ mẹo
Matthias

hãy xem cái này: gist.github.com/1393552
Matthias

1
Câu hỏi này có liên quan là tốt.
Alex Lockwood

Tôi thêm các tác vụ không đồng bộ vào một danh sách mảng và đảm bảo đóng tất cả chúng tại một điểm nhất định.
NightSkyCode

Câu trả lời:


86

Còn những thứ như thế này thì sao:

class MyActivity extends Activity {
    Worker mWorker;

    static class Worker extends AsyncTask<URL, Integer, Long> {
        MyActivity mActivity;

        Worker(MyActivity activity) {
            mActivity = activity;
        }

        @Override
        protected Long doInBackground(URL... urls) {
            int count = urls.length;
            long totalSize = 0;
            for (int i = 0; i < count; i++) {
                totalSize += Downloader.downloadFile(urls[i]);
                publishProgress((int) ((i / (float) count) * 100));
            }
            return totalSize;
        }

        @Override
        protected void onProgressUpdate(Integer... progress) {
            if (mActivity != null) {
                mActivity.setProgressPercent(progress[0]);
            }
        }

        @Override
        protected void onPostExecute(Long result) {
            if (mActivity != null) {
                mActivity.showDialog("Downloaded " + result + " bytes");
            }
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mWorker = (Worker)getLastNonConfigurationInstance();
        if (mWorker != null) {
            mWorker.mActivity = this;
        }

        ...
    }

    @Override
    public Object onRetainNonConfigurationInstance() {
        return mWorker;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mWorker != null) {
            mWorker.mActivity = null;
        }
    }

    void startWork() {
        mWorker = new Worker(this);
        mWorker.execute(...);
    }
}

5
Có, mActivity sẽ là! = Null, nhưng nếu không có tham chiếu nào đến cá thể Công nhân của bạn, thì mọi tham chiếu đó cũng sẽ bị loại bỏ rác. Nếu tác vụ của bạn chạy mãi mãi, thì dù sao bạn cũng bị rò rỉ bộ nhớ (nhiệm vụ của bạn) - chưa kể đến việc bạn đang làm cạn kiệt pin điện thoại. Ngoài ra, như đã đề cập ở nơi khác, bạn có thể đặt mActivity thành null trong onDestroy.
EboMike

13
Phương thức onDestroy () đặt mActivity thành null. Không quan trọng ai giữ tài liệu tham khảo cho hoạt động trước đó, bởi vì nó vẫn đang chạy. Và cửa sổ của hoạt động sẽ luôn có hiệu lực cho đến khi onDestroy () được gọi. Bằng cách đặt thành null ở đó, tác vụ async sẽ biết rằng hoạt động không còn hợp lệ. (. Và khi một thay đổi cấu hình, các hoạt động trước đó của onDestroy () được gọi và người tiếp theo của () chạy onCreate mà không cần bất kỳ tin nhắn trong vòng lặp chính xử lý giữa họ vì thế AsyncTask sẽ không bao giờ nhìn thấy một nhà nước không phù hợp)
hackbod

8
đúng, nhưng nó vẫn không giải quyết được vấn đề cuối cùng mà tôi đã đề cập: hãy tưởng tượng tác vụ tải xuống một cái gì đó từ internet. Sử dụng phương pháp này, nếu bạn lật màn hình 3 lần trong khi tác vụ đang chạy, nó sẽ được khởi động lại với mỗi lần xoay màn hình và mọi tác vụ ngoại trừ lần cuối ném đi kết quả của nó vì tham chiếu hoạt động của nó là null.
Matthias

11
Để truy cập trong nền, bạn cần phải đặt đồng bộ hóa phù hợp xung quanh mActivity xử lý thời gian chạy khi nó là null hoặc có luồng nền chỉ cần lấy Context.getApplicationContext () là một phiên bản toàn cầu duy nhất cho ứng dụng. Bối cảnh ứng dụng bị hạn chế trong những gì bạn có thể làm (chẳng hạn như UI như Dialog) và yêu cầu một số chăm sóc (người nhận đã đăng ký và ràng buộc dịch vụ sẽ bị bỏ lại mãi mãi nếu bạn không dọn sạch chúng), nhưng nói chung là phù hợp với mã không không bị ràng buộc với bối cảnh của một thành phần cụ thể.
hackbod

4
Điều đó cực kỳ hữu ích, cảm ơn Dianne! Tôi muốn tài liệu sẽ tốt như ở nơi đầu tiên.
Matthias

20

Lý do rất rõ ràng: nếu hoạt động bị phá hủy sẽ kích hoạt nhiệm vụ thì sao?

Tự phân tách các hoạt động từ AsyncTasktrong onDestroy(). Bằng tay liên kết lại các hoạt động mới vào AsyncTasktrong onCreate(). Điều này đòi hỏi một lớp bên trong tĩnh hoặc một lớp Java tiêu chuẩn, cộng với có lẽ 10 dòng mã.


Hãy cẩn thận với các tham chiếu tĩnh - Tôi đã thấy các đối tượng là rác được thu thập mặc dù có các tham chiếu mạnh đối với chúng. Có thể là tác dụng phụ của trình tải lớp của Android hoặc thậm chí là lỗi, nhưng tham chiếu tĩnh không phải là cách trao đổi trạng thái an toàn trong vòng đời hoạt động. Tuy nhiên, đối tượng ứng dụng là lý do tại sao tôi sử dụng nó.
Matthias

10
@Matthias: Tôi không nói sử dụng tài liệu tham khảo tĩnh. Tôi nói để sử dụng một lớp bên trong tĩnh. Có một sự khác biệt đáng kể, mặc dù cả hai đều có "tĩnh" trong tên của chúng.
CommonsWare


5
Tôi thấy - khóa của chúng ở đây là getLastNonConfigurationInstance (), chứ không phải lớp bên trong tĩnh. Một lớp bên trong tĩnh không giữ tham chiếu ngầm đến lớp bên ngoài của nó để nó tương đương về mặt ngữ nghĩa với một lớp công khai đơn giản. Chỉ là một cảnh báo: onRetainNonConfigurationInstance () KHÔNG được đảm bảo để được gọi khi một hoạt động bị gián đoạn (một gián đoạn cũng có thể là một cuộc gọi điện thoại), vì vậy, bạn cũng phải gửi Nhiệm vụ của mình vào onSaveInstanceState () giải pháp. Nhưng vẫn còn, ý tưởng tốt đẹp.
Matthias

7
Ừm ... onRetainNonConfigurationInstance () luôn được gọi khi hoạt động đang trong quá trình bị hủy và tạo lại. Nó không có ý nghĩa để gọi vào thời điểm khác. Nếu chuyển sang hoạt động khác xảy ra, hoạt động hiện tại bị tạm dừng / dừng, nhưng nó không bị hủy, do đó, tác vụ async có thể tiếp tục chạy và sử dụng cùng một hoạt động. Nếu nó kết thúc và hiển thị một hộp thoại, hộp thoại sẽ hiển thị chính xác như một phần của hoạt động đó và do đó không hiển thị cho người dùng cho đến khi họ quay lại hoạt động. Bạn không thể đặt AsyncTask trong Gói.
hackbod

15

Có vẻ như AsyncTasklà một chút nhiều hơn chỉ là thiếu sót về mặt khái niệm . Nó cũng không thể sử dụng bởi các vấn đề tương thích. Các tài liệu Android đọc:

Khi được giới thiệu lần đầu tiên, AsyncT task đã được thực thi ser seri trên một luồng nền đơn. Bắt đầu với DONUT, điều này đã được thay đổi thành một nhóm các luồng cho phép nhiều tác vụ hoạt động song song. Bắt đầu HONEYCOMB, các tác vụ quay trở lại được thực thi trên một luồng duy nhất để tránh các lỗi ứng dụng phổ biến do thực thi song song. Nếu bạn thực sự muốn thực thi song song, bạn có thể sử dụng executeOnExecutor(Executor, Params...) phiên bản của phương thức này với THREAD_POOL_EXECUTOR ; tuy nhiên, xem bình luận ở đó để cảnh báo về việc sử dụng nó.

Cả hai executeOnExecutor()THREAD_POOL_EXECUTORđược thêm vào API cấp 11 (Android 3.0.x, HONEYCOMB).

Điều này có nghĩa là nếu bạn tạo hai AsyncTaskgiây để tải xuống hai tệp, lần tải xuống thứ 2 sẽ không bắt đầu cho đến khi lần đầu tiên kết thúc. Nếu bạn trò chuyện qua hai máy chủ và máy chủ đầu tiên không hoạt động, bạn sẽ không kết nối với máy chủ thứ hai trước khi kết nối với máy chủ đầu tiên. (Tất nhiên trừ khi bạn sử dụng các tính năng API11 mới, nhưng điều này sẽ làm cho mã của bạn không tương thích với 2.x).

Và nếu bạn muốn nhắm mục tiêu cả 2.x và 3.0+, công cụ sẽ trở nên thực sự khó khăn.

Ngoài ra, các tài liệu nói:

Thận trọng: Một vấn đề khác bạn có thể gặp phải khi sử dụng luồng công nhân là khởi động lại bất ngờ trong hoạt động của bạn do thay đổi cấu hình thời gian chạy (chẳng hạn như khi người dùng thay đổi hướng màn hình), có thể phá hủy luồng công nhân của bạn . Để xem làm thế nào bạn có thể duy trì nhiệm vụ của mình trong một trong những lần khởi động lại này và cách hủy tác vụ đúng cách khi hoạt động bị hủy, hãy xem mã nguồn cho ứng dụng mẫu Kệ.


12

Có lẽ tất cả chúng ta, bao gồm cả Google, đang sử dụng sai AsyncTasktừ quan điểm MVC .

Một hoạt động là một Trình điều khiển và bộ điều khiển không nên bắt đầu các hoạt động có thể tồn tại lâu hơn Chế độ xem . Nghĩa là, AsyncT Nhiệm vụ nên được sử dụng từ Mô hình , từ một lớp không bị ràng buộc với vòng đời Hoạt động - hãy nhớ rằng Hoạt động bị hủy khi xoay vòng. (Đối với Chế độ xem , bạn thường không lập trình các lớp có nguồn gốc từ ví dụ android.widget.Button, nhưng bạn có thể. Thông thường, điều duy nhất bạn làm về Chế độ xem là xml.)

Nói cách khác, việc đặt các dẫn xuất AsyncTask trong các phương thức Hoạt động là sai. OTOH, nếu chúng ta không được sử dụng AsyncT task trong Hoạt động, AsyncTask sẽ mất đi tính hấp dẫn: nó từng được quảng cáo là một cách khắc phục nhanh chóng và dễ dàng.


5

Tôi không chắc chắn rằng bạn có nguy cơ bị rò rỉ bộ nhớ với tham chiếu đến ngữ cảnh từ AsyncTask.

Cách thông thường để triển khai chúng là tạo một cá thể AsyncTask mới trong phạm vi của một trong các phương thức của Activity. Vì vậy, nếu hoạt động bị hủy, thì một khi AsyncTask hoàn thành, nó sẽ không thể truy cập được và sau đó đủ điều kiện để thu gom rác? Vì vậy, tham chiếu đến hoạt động sẽ không thành vấn đề vì bản thân AsyncTask sẽ không xuất hiện.


2
đúng - nhưng nếu khối nhiệm vụ vô thời hạn thì sao? Nhiệm vụ có nghĩa là để thực hiện các hoạt động chặn, thậm chí có thể không bao giờ chấm dứt. Có bạn bị rò rỉ bộ nhớ của bạn.
Matthias

1
Bất kỳ công nhân nào thực hiện một cái gì đó trong một vòng lặp vô tận, hoặc bất cứ thứ gì chỉ khóa, ví dụ như trên một hoạt động I / O.
Matthias

2

Sẽ mạnh mẽ hơn khi giữ WeekReference cho hoạt động của bạn:

public class WeakReferenceAsyncTaskTestActivity extends Activity {
    private static final int MAX_COUNT = 100;

    private ProgressBar progressBar;

    private AsyncTaskCounter mWorker;

    @SuppressWarnings("deprecation")
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_async_task_test);

        mWorker = (AsyncTaskCounter) getLastNonConfigurationInstance();
        if (mWorker != null) {
            mWorker.mActivity = new WeakReference<WeakReferenceAsyncTaskTestActivity>(this);
        }

        progressBar = (ProgressBar) findViewById(R.id.progressBar1);
        progressBar.setMax(MAX_COUNT);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_async_task_test, menu);
        return true;
    }

    public void onStartButtonClick(View v) {
        startWork();
    }

    @Override
    public Object onRetainNonConfigurationInstance() {
        return mWorker;
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (mWorker != null) {
            mWorker.mActivity = null;
        }
    }

    void startWork() {
        mWorker = new AsyncTaskCounter(this);
        mWorker.execute();
    }

    static class AsyncTaskCounter extends AsyncTask<Void, Integer, Void> {
        WeakReference<WeakReferenceAsyncTaskTestActivity> mActivity;

        AsyncTaskCounter(WeakReferenceAsyncTaskTestActivity activity) {
            mActivity = new WeakReference<WeakReferenceAsyncTaskTestActivity>(activity);
        }

        private static final int SLEEP_TIME = 200;

        @Override
        protected Void doInBackground(Void... params) {
            for (int i = 0; i < MAX_COUNT; i++) {
                try {
                    Thread.sleep(SLEEP_TIME);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Log.d(getClass().getSimpleName(), "Progress value is " + i);
                Log.d(getClass().getSimpleName(), "getActivity is " + mActivity);
                Log.d(getClass().getSimpleName(), "this is " + this);

                publishProgress(i);
            }
            return null;
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
            if (mActivity != null) {
                mActivity.get().progressBar.setProgress(values[0]);
            }
        }
    }

}

Điều này tương tự như những gì chúng tôi lần đầu tiên làm với Droid-Fu. Chúng tôi sẽ giữ một bản đồ các tham chiếu yếu đến các đối tượng ngữ cảnh và sẽ tìm kiếm trong các cuộc gọi lại nhiệm vụ để có được tham chiếu gần đây nhất (nếu có) để chạy lại cuộc gọi lại. Tuy nhiên, cách tiếp cận của chúng tôi có nghĩa là có một thực thể duy trì ánh xạ này, trong khi cách tiếp cận của bạn thì không, vì vậy đây thực sự là đẹp hơn.
Matthias

1
Bạn đã xem RoboSpice chưa? github.com/octo-online/robospice . Tôi tin rằng hệ thống này thậm chí còn tốt hơn.
Snicolas

Mã mẫu trên trang đầu có vẻ như nó đang rò rỉ một tham chiếu ngữ cảnh (một lớp bên trong giữ một tham chiếu ngầm cho lớp bên ngoài.) Không thuyết phục !!
Matthias

@Matthias, bạn nói đúng, đó là lý do tại sao tôi đề xuất một lớp bên trong tĩnh sẽ giữ WeakReference trên Activity.
Snicolas

1
@Matthias, tôi tin rằng điều này bắt đầu lạc đề. Nhưng các trình tải không cung cấp bộ nhớ đệm ra khỏi hộp như chúng ta làm, hơn nữa, các trình tải có xu hướng dài dòng hơn lib của chúng ta. Trên thực tế, họ xử lý các con trỏ khá tốt nhưng đối với mạng, một cách tiếp cận khác, dựa trên bộ nhớ đệm và một dịch vụ phù hợp hơn. Xem neilgoodman.net/2011/12/26/õ phần 1 & 2
Snicolas

1

Tại sao không ghi đè onPause()phương thức trong Hoạt động sở hữu và hủy bỏ AsyncTasktừ đó?


nó phụ thuộc vào những gì nhiệm vụ đó đang làm. nếu nó chỉ tải / đọc một số dữ liệu, thì nó sẽ ổn thôi. nhưng nếu nó thay đổi trạng thái của một số dữ liệu trên một máy chủ từ xa thì chúng tôi muốn cung cấp cho tác vụ một khả năng để chạy đến cùng.
Vit Khudenko

@Arhimed và tôi lấy nó nếu bạn giữ luồng UI trong onPauseđó có tệ như cầm nó ở bất cứ nơi nào khác không? Tức là bạn có thể có được ANR?
Jeff Axelrod

chính xác. chúng tôi không thể chặn luồng UI (có thể là onPausehoặc không liên kết với người khác) vì chúng tôi có nguy cơ bị ANR.
Vit Khudenko

1

Bạn hoàn toàn đúng - đó là lý do tại sao một phong trào tránh sử dụng các tác vụ / bộ tải không đồng bộ trong các hoạt động để tìm nạp dữ liệu đang đạt được đà. Một trong những cách mới là sử dụng khung Volley về cơ bản cung cấp một cuộc gọi lại sau khi dữ liệu đã sẵn sàng - phù hợp hơn nhiều với mô hình MVC. Volley đã được phổ biến trong Google I / O 2013. Không hiểu tại sao nhiều người không biết về điều này.


cảm ơn vì điều đó ... tôi sẽ xem xét nó ... lý do tôi không thích AsyncTask là vì nó khiến tôi bị mắc kẹt với một bộ hướng dẫn trênPostExecute ... trừ khi tôi hack nó như sử dụng giao diện hoặc ghi đè lên nó mỗi lần Tôi cần nó.
carinlynchin

0

Cá nhân, tôi chỉ mở rộng Thread và sử dụng giao diện gọi lại để cập nhật giao diện người dùng. Tôi không bao giờ có thể khiến AsyncTask hoạt động bình thường mà không gặp sự cố FC. Tôi cũng sử dụng hàng đợi không chặn để quản lý nhóm thực thi.


1
Chà, lực lượng của bạn đóng có lẽ là do vấn đề tôi đã đề cập: bạn đã thử tham khảo một bối cảnh nằm ngoài phạm vi (tức là cửa sổ của nó đã bị phá hủy), điều này sẽ dẫn đến ngoại lệ khung.
Matthias

Không ... thực ra đó là vì hàng đợi được tích hợp sẵn trong AsyncTask. Tôi luôn luôn sử dụng getApplicationContext (). Tôi không gặp vấn đề với AsyncTask nếu chỉ có một vài thao tác ... nhưng tôi đang viết một trình phát đa phương tiện cập nhật ảnh bìa album ... trong thử nghiệm của tôi, tôi có 120 album không có nghệ thuật ... vì vậy, trong khi Ứng dụng của tôi đã không đóng tất cả các cách, asynctask đã bị lỗi ... vì vậy thay vào đó tôi đã xây dựng một lớp singleton với một hàng đợi quản lý các quy trình và cho đến nay nó hoạt động rất tốt.
androidworkz

0

Tôi nghĩ hủy bỏ hoạt động nhưng nó không.

Ở đây họ RTFMing về nó:

"" Nếu tác vụ đã bắt đầu, thì tham số mayInterrupt IfRasty xác định xem luồng thực thi tác vụ này có bị gián đoạn trong nỗ lực dừng tác vụ hay không. "

Điều đó không ngụ ý, tuy nhiên, các chủ đề là gián đoạn. Đó là một thứ Java, không phải là một thứ AsyncTask. "

http://groups.google.com/group/android-developers/browse_thread/thread/dcadb1bc7705f1bb/add136eb4949359d?show_docid=add136eb4949359d


0

Bạn sẽ tốt hơn khi nghĩ về AsyncTask như một thứ gì đó được kết hợp chặt chẽ hơn với Activity, Context, ContextWrapper, v.v ... Thật tiện lợi khi phạm vi của nó được hiểu đầy đủ.

Đảm bảo rằng bạn có chính sách hủy trong vòng đời của mình để cuối cùng nó sẽ được thu gom rác và không còn giữ tham chiếu đến hoạt động của bạn nữa và nó cũng có thể là rác được thu thập.

Nếu không hủy AsyncTask trong khi di chuyển khỏi Ngữ cảnh, bạn sẽ gặp phải rò rỉ bộ nhớ và NullPulumExceptions, nếu bạn chỉ cần cung cấp phản hồi như Toast một hộp thoại đơn giản thì một Bối cảnh ứng dụng của bạn sẽ giúp tránh được vấn đề NPE.

AsyncTask không tệ lắm nhưng chắc chắn có rất nhiều phép thuật đang diễn ra có thể dẫn đến một số cạm bẫy không lường trước được.


-1

Như để "kinh nghiệm làm việc với nó": đó là khả năng để giết chết quá trình cùng với tất cả AsyncTasks, Android sẽ tái tạo hoạt động ngăn xếp để người dùng sẽ không đề cập đến bất cứ điều gì.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.