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ệ Context
và 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 Handler
thể 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 WeakReference
s 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ũ và 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.