我的项目中有一个AsyncTask,并且有一条警告说:
此AsyncTask类应该是静态的,否则可能会发生泄漏(匿名 android.os.AsyncTask)少...(Ctrl + F1)静态字段将泄漏 上下文。非静态内部类隐式引用 他们的外部阶级。如果该外部类是例如Fragment或 活动,那么此引用意味着长期运行 处理程序/加载程序/任务将保存对活动的引用 防止收集垃圾。同样,直接场 引用这些长期运行的活动和片段 实例可能会导致泄漏。 ViewModel类永远不要指向 视图或非应用程序上下文。
这是包含此警报的代码:
ProgressDialog progressDialog;
AsyncTask<String,Void,Boolean> asyncTask = new AsyncTask<String, Void, Boolean>() {
@Override
protected void onPreExecute() {
super.onPreExecute();
progressDialog.setTitle("بارگذاری");
progressDialog.setMessage("در حال دریافت اطلاعات از پایگاه داده..");
progressDialog.setCancelable(false);
progressDialog.show();
}
@Override
protected Boolean doInBackground(String... strings) {
Cursor cursor = DataBase.getinfos(page,limit);
if (cursor.isAfterLast()){
return false;
}else {
for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) {
PropertyInfo propertyInfo = new PropertyInfo();
propertyInfo.setId(cursor.getInt(0));
propertyInfo.setAddress(cursor.getString(1));
propertyInfo.setDetails(cursor.getString(2));
propertyInfo.setOptions(cursor.getString(3));
propertyInfo.setMortgage_cost(cursor.getLong(4));
propertyInfo.setRent_cost(cursor.getLong(5));
propertyInfo.setOwner_name(cursor.getString(6));
propertyInfo.setUnits_per_floor(cursor.getInt(7));
propertyInfo.setCurrent_floor(cursor.getInt(8));
propertyInfo.setFloors_count(cursor.getInt(9));
propertyInfo.setRoom_count(cursor.getString(10));
propertyInfo.setOwner_phone(cursor.getString(11));
propertyInfo.setDocument_type(cursor.getString(12));
propertyInfo.setRequest_type(cursor.getString(13));
propertyInfo.setProperty_type(cursor.getString(14));
propertyInfo.setCost(cursor.getLong(15));
propertyInfo.setArea(cursor.getInt(16));
propertyInfo.setHouse_type(cursor.getString(17));
propertyInfo.setLocation(cursor.getString(19));
propertyInfo.setNoeMorajeKonande(cursor.getString(18));
propertyInfo.setShomareSafhe(cursor.getString(20));
propertyInfo.setDate(cursor.getString(21));
arrayList.add(propertyInfo);
lastRecivedDataSize++;
}
return true;
}
}
@Override
protected void onPostExecute(Boolean aBoolean) {
super.onPostExecute(aBoolean);
loading = aBoolean;
if (arrayList.isEmpty()) {
setContentView(R.layout.no_result);
} else {
mAdapter = new RecyclerInfoAdapter(arrayList, ShowAllDataActivity.this);
mAdapter.notifyDataSetChanged();
recyclerView.setAdapter(mAdapter);
recyclerView.scrollToPosition(pastVisiblesItems + visibleItemCount - 1);
page++;
}
progressDialog.dismiss();
}
};
asyncTask.execute();
有人知道这个问题吗?
答案 0 :(得分:1)
创建一个单独的类来实现AsyncTask,然后在您的活动中实例化它,然后运行execute方法。
答案 1 :(得分:1)
只是为了阐明ynsmtki在您的特定情况下的含义:您的asyncTask是在UI事件处理程序/回调方法中声明的(将其命名为onSomeUIEventHandler {},但它将产生自己的线程,并带有更长的范围引用,例如(1)progressDialog,(2)数据库,(3)propertyInfo,它们是泄漏警告的来源。
正如其他人指出的那样,直到IntelliJ在两年前部署(实际上是释放)了他们的KotlinT分析仪之前,这一直是一个安静的问题。直到最近(在AS v3.0 +中),分析器实际上提供了解决泄漏的有意义的提示,一直是一个难题。现在,它可以提供帮助,甚至可以通过IDE为您生成子类签名:
因此,您需要通过为它们指定上述三种getter()方法(即在扩展中使用的getDatabase(),getProgressDialog()和getPropertyInfo())为带有上述三个只读副本的异步任务线程执行()。因此asyncTask类:
static class HandleDBaseAsyncTask extends AsyncTask<Parameterized.Parameters,Process, Result>{
final PropertyInfo propertyInfo = getPropertyInfo();
final YourDatabaseClass Database = getDatabase();
final ProgressDialog progressDialog = getProgressDialog();
// Then finish off with your original
onPreExecute() {...}
doInBackground(){...}
onPostExecute(){...}
}
然后返回Dialog泄漏者的原始回调:
ProgressDialog progressDialog;
ProgressDialog getProgressDialog(){ return progressDialog;}
// and the same for other leakers
onSomeUIEventHandler{
HandleDBaseAsyncTask handleDBTask = new HandleDBaseAsyncTask();
handleDBTask.execute();
// ...
}
可能还有其他一些细微的地方要注意在任务的静态上下文中无法调用getter的实例方法的地方,因此您可以将它们设为静态,或将其单例容器(例如Activity或Context)传递到asyncTask块中,以使用那里的getters()克服编译器错误。
ParentContainer parent = getDialogContainer();
final ProgressDialog progressDialog = parent.getProgressDialog() // etc