정적 내부 AsyncTask 클래스를 사용하는 방법
누출을 방지하기 위해 내부 클래스를 정적으로 만들 수 있습니다. 그러나 문제는 더 이상 활동의 UI보기 또는 멤버 변수에 액세스 할 수 없다는 것입니다. 에 대한 참조를 전달할 수 Context
있지만 동일한 메모리 누수 위험이 있습니다. (AsyncTask 클래스에 강한 참조가있는 경우 Android를 닫은 후에는 Android에서 Activity를 가비지 수집 할 수 없습니다.) 해결책은 Activity (또는 Context
필요한 것) 를 약하게 참조하는 것 입니다.
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;
}
}
}
노트
- 내가 아는 한,이 유형의 메모리 누수 위험은 항상 사실이지만 Android Studio 3.0에서만 경고가 표시되기 시작했습니다. 많은 주요
AsyncTask
튜토리얼은 여전히 다루지 않습니다 ( here , here , here 및 here 참조 ).
- 당신이
AsyncTask
최상위 클래스 라면 비슷한 절차를 따를 것 입니다. 정적 내부 클래스는 기본적으로 Java의 최상위 클래스와 동일합니다.
액티비티 자체는 필요하지 않지만 여전히 컨텍스트 (예 :)를 표시 Toast
하려는 경우 앱 컨텍스트에 대한 참조를 전달할 수 있습니다. 이 경우 AsyncTask
생성자는 다음과 같습니다.
private WeakReference<Application> appReference;
MyTask(Application context) {
appReference = new WeakReference<>(context);
}
- 이 경고를 무시하고 정적이 아닌 클래스를 사용한다는 몇 가지 주장이 있습니다. 결국 AsyncTask는 매우 짧은 수명 (최대 2 초)이며 활동이 완료되면 액티비티에 대한 참조를 해제합니다. 참조 이 와 이 .
- 훌륭한 기사 : 컨텍스트를 누출하는 방법 : 처리기 및 내부 클래스
코 틀린
Kotlin에서는 내부 클래스에 대한 키워드 를 포함시키지 마십시오inner
. 기본적으로 정적입니다.
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
}
}
}