静的内部AsyncTaskクラスの使用方法
リークを防ぐために、内部クラスを静的にすることができます。ただし、その問題は、アクティビティのUIビューやメンバー変数にアクセスできなくなることです。への参照を渡すことができContext
ますが、メモリリークの同じリスクが発生します。(AsyncTaskクラスがそれへの強い参照を持っている場合、Androidは閉じた後、アクティビティをガベージコレクションできません。)解決策は、アクティビティ(または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
世の中の主要なチュートリアルの多くは、まだそれを扱っていません(ここ、ここ、ここ、およびここを参照してください)。
AsyncTask
最上位クラスの場合も、同様の手順に従います。静的内部クラスは、Javaのトップレベルクラスと基本的に同じです。
アクティビティ自体は必要ないがコンテキスト(たとえば、を表示するToast
)が必要な場合は、アプリコンテキストへの参照を渡すことができます。この場合、AsyncTask
コンストラクターは次のようになります。
private WeakReference<Application> appReference;
MyTask(Application context) {
appReference = new WeakReference<>(context);
}
- この警告を無視し、非静的クラスを使用するだけの理由はいくつかあります。結局のところ、AsyncTaskは非常に短期間(最長で数秒)になるように設計されており、とにかく終了するとアクティビティへの参照を解放します。これとこれを見てください。
- 優れた記事:コンテキストをリークする方法:ハンドラーと内部クラス
コトリン
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
}
}
}