Cách sử dụng lớp AsyncTask tĩnh bên trong
Để ngăn chặn rò rỉ, bạn có thể làm cho lớp bên trong tĩnh. Tuy nhiên, vấn đề với điều đó là bạn không còn có quyền truy cập vào các giao diện UI hoặc các biến thành viên của Activity. Bạn có thể chuyển tham chiếu đến Context
nhưng sau đó bạn có nguy cơ bị rò rỉ bộ nhớ tương tự. (Android không thể thu thập hoạt động sau khi đóng nếu lớp AsyncTask có tham chiếu mạnh đến nó.) Giải pháp là tạo một tham chiếu yếu đến Hoạt động (hoặc bất cứ điều gì Context
bạn cần).
public class MyActivity extends AppCompatActivity {
int mSomeMemberVariable = 123;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// start the AsyncTask, passing the Activity context
// in to a custom constructor
new MyTask(this).execute();
}
private static class MyTask extends AsyncTask<Void, Void, String> {
private WeakReference<MyActivity> activityReference;
// only retain a weak reference to the activity
MyTask(MyActivity context) {
activityReference = new WeakReference<>(context);
}
@Override
protected String doInBackground(Void... params) {
// do some long running task...
return "task finished";
}
@Override
protected void onPostExecute(String result) {
// get a reference to the activity if it is still there
MyActivity activity = activityReference.get();
if (activity == null || activity.isFinishing()) return;
// modify the activity's UI
TextView textView = activity.findViewById(R.id.textview);
textView.setText(result);
// access Activity member variables
activity.mSomeMemberVariable = 321;
}
}
}
Ghi chú
- Theo tôi biết, loại nguy hiểm rò rỉ bộ nhớ này luôn luôn đúng, nhưng tôi chỉ bắt đầu thấy cảnh báo trong Android Studio 3.0. Rất nhiều
AsyncTask
hướng dẫn chính ngoài kia vẫn không giải quyết được (xem ở đây , ở đây , ở đây và ở đây ).
- Bạn cũng sẽ làm theo một quy trình tương tự nếu
AsyncTask
là một lớp cấp cao nhất. Một lớp bên trong tĩnh về cơ bản giống như một lớp cấp cao nhất trong Java.
Nếu bạn không cần Hoạt động mà vẫn muốn Bối cảnh (ví dụ: để hiển thị a Toast
), bạn có thể chuyển tham chiếu đến ngữ cảnh ứng dụng. Trong trường hợp này, hàm AsyncTask
tạo sẽ trông như thế này:
private WeakReference<Application> appReference;
MyTask(Application context) {
appReference = new WeakReference<>(context);
}
- Có một số đối số ngoài kia để bỏ qua cảnh báo này và chỉ sử dụng lớp không tĩnh. Rốt cuộc, AsyncTask dự định sẽ tồn tại rất ngắn (một vài giây lâu nhất) và nó sẽ phát hành tham chiếu đến Hoạt động khi nó kết thúc. Xem cái này và cái này .
- Bài viết xuất sắc: Làm thế nào để rò rỉ bối cảnh: Người xử lý & Lớp học bên trong
Kotlin
Trong Kotlin chỉ không bao gồm inner
từ khóa cho lớp bên trong. Điều này làm cho nó tĩnh theo mặc định.
class MyActivity : AppCompatActivity() {
internal var mSomeMemberVariable = 123
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// start the AsyncTask, passing the Activity context
// in to a custom constructor
MyTask(this).execute()
}
private class MyTask
internal constructor(context: MyActivity) : AsyncTask<Void, Void, String>() {
private val activityReference: WeakReference<MyActivity> = WeakReference(context)
override fun doInBackground(vararg params: Void): String {
// do some long running task...
return "task finished"
}
override fun onPostExecute(result: String) {
// get a reference to the activity if it is still there
val activity = activityReference.get()
if (activity == null || activity.isFinishing) return
// modify the activity's UI
val textView = activity.findViewById(R.id.textview)
textView.setText(result)
// access Activity member variables
activity.mSomeMemberVariable = 321
}
}
}