我正在构建一个从硬编码网址中获取数据的Android应用程序。
因为提取可能需要一段时间,所以我首先编写了一个支持回调的接口
public interface MyCallBack {
void data_received(String data);
}
在主要活动中,我实施了MyCallBack
public class MainActivity extends AppCompatActivity implments MyCallBack {
@Override
public void data_received(String data) {
Log.d("got data", data);
// do something useful with data...
}
public void btn_getData_clicked(View view) {
// a button is clicked, and fetching is started:
BackgroundWorker bw = new BackgroundWorker(this);
bw.execute("https://randomuser.me/api/");
// after this point, bw does not leave the heap,
// because BackgroundWorker keeps a reference to (this)
}
}
我想让我的代码在按下按钮时单独获取。 但是我也希望消耗/完成/已经调用的返回实例消失,然后离开堆,因为它们没有任何意义。
因此,在BackgroundWorker类中,我在调用接口方法后立即将调用者设置为null:
public class BackgroundWorker extends AsyncTask<String,Void,String> {
MyCallBack caller; // object to be called back when data arrives
private static int instances_counter = 0; // counts bw instances
BackgroundWorker(MyCallBack cb) {
caller = cb;
instances_counter ++;
Log.d("new bw object created", "current count: " + instances_counter );
}
@Override protected void finalize() throws Throwable {
instances_counter --;
Log.d("bw object destroyed","remaining count: " + instances_counter );
}
@Override String doInBackground(...) {...} // satisfy AsynTask
// and do the actual URL post/get stuff then forward the output
// to onPostExecute() method
@Override void onPostExecute(String s) {
// I can check if caller is null first, but you get the idea.
caller.data_received(s);
caller = null; // just so that this instance has no pointer to activity
}
}
现在,当我多次单击该按钮时,我可以逐个看到创建的对象。我每次都在活动中获取数据。
创建了D / new bw对象:当前计数:1
获得数据:{“结果”:[{“性别”:“女性”......
创建了新的bw对象:当前计数:2
获得数据:{“结果”:[{“性别”:“男性”......
创建了D / new bw对象:当前计数:3
获得数据:{“结果”:[{“性别”:“女性”......
创建了D / new bw对象:当前计数:4
获得数据:{“结果”:[{“性别”:“女性”......
创建了D / new bw对象:当前计数:5
获得数据:{“结果”:[{“性别”:“男性”......
但他们永远不会被摧毁。我担心我在某个地方发生了内存泄漏,而且我的应用程序因为我的内存管理不善而一度崩溃。
为什么这些实例没有被销毁?
答案 0 :(得分:1)
finalize
方法中的日志输出不是确定对象是否导致内存泄漏的正确方法。
可能引发疑虑的唯一部分是,您的AsyncTask
个实例不仅对任何回调都有强烈的参考,而且对您的整个Activity
都有强烈的参考。
仍然,Garbage Collector
训练有素无论如何都要处理循环引用,但我承认我不知道它是否会等到Activity
是gc'ed收集AsyncTask
也是如此,或者它会尽快收集。
在任何情况下,您都可以将Callback
引用包含在WeakReference<T>
private WeakReference<MyCallBack> caller; // object to be called back when data arrives
// ...
caller = new WeakReference<>(cb);
// ...
if (caller.get() != null)
// call callback
它应该给你一个重要的安全感,一旦需要内存就会收集任务。
但是我也希望消耗/完成/已经调用的后台实例消失,然后离开堆,因为它们没有任何意义。
老实说,这不是由你来决定的。