我在代码中收到警告:
此的AsyncTask类应该是静态的或可能发生泄漏(匿名android.os.AsyncTask)
完整的警告是:
此的AsyncTask类应该是静态的或可能发生泄漏(匿名android.os.AsyncTask) 静态字段将泄漏上下文。非静态内部类具有对其外部类的隐式引用。如果该外部类例如是片段或活动,则此引用意味着长时间运行的处理程序/加载器/任务将保留对活动的引用,从而阻止其收集垃圾。同样,对来自这些较长时间运行的实例的活动和片段的直接字段引用可能会导致泄漏。 ViewModel类永远不应该指向视图或非应用程序上下文。
这是我的代码:
new AsyncTask<Void,Void,Void>(){
@Override
protected Void doInBackground(Void... params) {
runOnUiThread(new Runnable() {
@Override
public void run() {
mAdapter.notifyDataSetChanged();
}
});
return null;
}
}.execute();
我该如何纠正?
答案 0 :(得分:459)
为了防止泄漏,您可以使内部类静态。但问题是,您无法再访问Activity的UI视图或成员变量。您可以传入对Context
的引用,但之后会出现内存泄漏的相同风险。 (如果AsyncTask类具有强引用,则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;
}
}
}
AsyncTask
教程仍然没有处理它(请参阅here,here,here和here)。AsyncTask
是顶级课程,您也会遵循类似的程序。静态内部类与Java中的顶级类基本相同。如果您不需要Activity本身但仍需要Context(例如,显示Toast
),则可以传入对应用程序上下文的引用。在这种情况下,AsyncTask
构造函数将如下所示:
private WeakReference<Application> appReference;
MyTask(Application context) {
appReference = new WeakReference<>(context);
}
在Kotlin只为don't include the inner
keyword内部班级。这使其默认为静态。
我对Kotlin还不太擅长,所以如果可以改进我的代码,请更正下面的代码:
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
}
}
}
答案 1 :(得分:43)
非静态内部类包含对包含类的引用。当您将AsyncTask
声明为内部类时,它可能比包含Activity
类的时间长。这是因为对包含类的隐式引用。这样可以防止活动被垃圾收集,从而导致内存泄漏。
要解决您的问题,请使用静态嵌套类而不是匿名,本地和内部类,或使用顶级类。
答案 2 :(得分:19)
此AsyncTask
类应该是静态的,否则可能会发生泄漏,因为
Activity
被销毁时,AsyncTask
(static
或non-static
}仍在运行non-static
(AsyncTask
)类,则它将引用外部类(Activity
)。Garbage Collected
将释放它。如果对象未使用且Garbage Collected
无法释放它=>泄漏记忆 =&GT;如果AsyncTask
为non-static
,则Activity
将不会发布已销毁的事件=&gt;泄漏
将AsyncTask作为无泄漏的静态类后的更新UI解决方案
1)使用WeakReference
之类的@Suragch回答
2)发送并删除Activity
<{1}}
AsyncTask
引用
public class NoLeakAsyncTaskActivity extends AppCompatActivity {
private ExampleAsyncTask asyncTask;
@Override
protected void onCreate(Bundle savedInstanceState) {
...
// START AsyncTask
asyncTask = new ExampleAsyncTask();
asyncTask.setListener(new ExampleAsyncTask.ExampleAsyncTaskListener() {
@Override
public void onExampleAsyncTaskFinished(Integer value) {
// update UI in Activity here
}
});
asyncTask.execute();
}
@Override
protected void onDestroy() {
asyncTask.setListener(null); // PREVENT LEAK AFTER ACTIVITY DESTROYED
super.onDestroy();
}
static class ExampleAsyncTask extends AsyncTask<Void, Void, Integer> {
private ExampleAsyncTaskListener listener;
@Override
protected Integer doInBackground(Void... voids) {
...
return null;
}
@Override
protected void onPostExecute(Integer value) {
super.onPostExecute(value);
if (listener != null) {
listener.onExampleAsyncTaskFinished(value);
}
}
public void setListener(ExampleAsyncTaskListener listener) {
this.listener = listener;
}
public interface ExampleAsyncTaskListener {
void onExampleAsyncTaskFinished(Integer value);
}
}
}