[解決済み】警告。この AsyncTask クラスは静的であるべきで、さもなければリークが発生する可能性があります。
質問
私のコードで以下のような警告が表示されます。
この AsyncTask クラスは static であるべきで、さもなければリークが発生する可能性があります (anonymous android.os.AsyncTask)
完全な警告は
この AsyncTask クラスは static であるべきで、さもなければリークが発生する可能性があります (anonymous android.os.AsyncTask) 静的なフィールドはコンテキストをリークします。 非静的な内部クラスは、その外部クラスへの暗黙の参照を持ちます。外側のクラスが例えばフラグメントやアクティビティである場合、この参照は、長く実行されるハンドラ/ローダ/タスクがアクティビティへの参照を保持することを意味し、ガベージコレクションを防ぐことができる。 同様に、アクティビティやフラグメントへの直接のフィールド参照は、これらの長く実行されるインスタンスから、リークを引き起こす可能性があります。 ViewModel クラスは、決して Views やアプリケーション以外の Contexts を指し示してはいけません。
これは私のコードです。
new AsyncTask<Void,Void,Void>(){
@Override
protected Void doInBackground(Void... params) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mAdapter.notifyDataSetChanged();
}
});
return null;
}
}.execute();
どうすれば修正できますか?
どのように解決するのですか?
静的なインナーAsyncTaskクラスを使用する方法
リークを防ぐために、内部クラスを静的にすることができます。しかし、その場合、ActivityのUIビューやメンバ変数にアクセスできなくなるという問題があります。への参照を渡すことができます。
Context
しかし、その場合、メモリリークの危険性があります。(AsyncTaskクラスがActivityを強く参照していると、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
チュートリアルはまだ対応していません( こちら , こちら , こちら そして こちら ). -
また
AsyncTask
はトップレベルクラスです。静的な内部クラスは、Javaでは基本的にトップレベルクラスと同じです。 -
アクティビティそのものは必要ないが、コンテキストは欲しいという場合(たとえば、アクティビティに
Toast
)、アプリのコンテキストへの参照を渡すことができます。この場合AsyncTask
のコンストラクタは次のようになります。private WeakReference<Application> appReference; MyTask(Application context) { appReference = new WeakReference<>(context); }
- この警告を無視して、非静的なクラスを使用するという議論もあります。結局のところ、AsyncTaskは非常に短命(長くても数秒)であることを意図しており、いずれにせよ終了するとActivityへの参照を解放することになります。参照 これ と これ .
- 優れた記事です。 コンテキストをリークする方法。ハンドラとインナークラス
コトリン
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
}
}
}
関連
-
[解決済み】react-native: コマンドが見つかりません。
-
[解決済み】Dalvikとdalvik-cacheとは何ですか?
-
[解決済み] 現在のテーマでスタイル 'coordinatorLayoutStyle' を見つけることができませんでした。
-
[解決済み] 設定 ':classpath' の依存関係をすべて解決できなかった。
-
[解決済み】onCreateOptionsMenu(Menu メニュー)とは何ですか?)
-
[解決済み】apkファイルのインストール中に「パッケージが破損しているようです」というエラーが発生する。
-
[解決済み】Couldn't load memtrack module Logcat Error
-
[解決済み] Androidでイメージビューの背景を透明に設定する
-
[解決済み] 匿名)内部クラスを使用することがリークセーフとなるのは、具体的にどのような場合ですか?
-
[解決済み】このHandlerクラスはstaticでなければリークが発生する可能性があります。IncomingHandler
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】Dalvikとdalvik-cacheとは何ですか?
-
[解決済み】onCreateOptionsMenu(Menu メニュー)とは何ですか?)
-
[解決済み】sendUserActionEvent()がnullである。
-
[解決済み】Android Studioで最新バージョンのgradleを使用する方法
-
[解決済み】Android 8:クリアテキストのHTTPトラフィックが許可されない
-
[解決済み】Couldn't load memtrack module Logcat Error
-
[解決済み] Android Studioで「URIが登録されていません」と報告されるのはなぜですか?[クローズド]
-
[解決済み] Gradleのエラーです。イベントディスパッチスレッドからの書き込みアクセスは、Android Studioでのみ許可されます。
-
[解決済み] Android Fragment onAttach() 非推奨
-
[解決済み] APKのインストール中にDELETE_FAILED_INTERNAL_ERRORエラーが発生する。