Java WeakReference在方向更改后继续返回活动引用

Java WeakReference在方向更改后继续返回活动引用,java,android,android-asynctask,garbage-collection,weak-references,Java,Android,Android Asynctask,Garbage Collection,Weak References,我想在异步任务中使用WeakReference来避免内存泄漏。通过日志语句,我可以看到,如果我将活动留在back按钮上,那么从get方法返回的活动引用实际上是空的。 但是,当我旋转设备时,返回一个工作引用,这意味着我泄漏了内存。知道为什么会这样吗 更新:旋转设备并打开其他应用程序后,我一离开活动,它就开始显示null。是不是因为我的活动很简单,所以系统没有必要进行清理 public class MainActivity extends AppCompatActivity { privat

我想在异步任务中使用WeakReference来避免内存泄漏。通过日志语句,我可以看到,如果我将活动留在back按钮上,那么从
get
方法返回的活动引用实际上是空的。 但是,当我旋转设备时,返回一个工作引用,这意味着我泄漏了内存。知道为什么会这样吗

更新:旋转设备并打开其他应用程序后,我一离开活动,它就开始显示null。是不是因为我的活动很简单,所以系统没有必要进行清理

public class MainActivity extends AppCompatActivity {
    private ProgressBar progressBar;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        progressBar = findViewById(R.id.progress_bar);
    }

    public void startAsyncTask(View v) {
        ExampleAsyncTask exampleAsyncTask = new ExampleAsyncTask(this);
        exampleAsyncTask.execute(210);
    }

    private static class ExampleAsyncTask extends AsyncTask<Integer, Integer, String> {
        private WeakReference<MainActivity> activityReference;

        ExampleAsyncTask(MainActivity context) {
            activityReference = new WeakReference<>(context);
        }

        @Override
        protected void onPreExecute() {
            super.onPreExecute();

            MainActivity activity = activityReference.get();
            if (activity == null || activity.isFinishing()) {
                return;
            }

            activity.progressBar.setVisibility(View.VISIBLE);
        }

        @Override
        protected String doInBackground(Integer... integers) {
            for (int i = 0; i < integers[0]; i++) {
                publishProgress((i * 100) / integers[0]);
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }

            return "Finished";
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);

            MainActivity activity = activityReference.get();
            if (activity == null || activity.isFinishing()) {
                Log.i("activity", "activity = null");
                return;
            } else
                Log.i("activity", "activity not null");
            activity.progressBar.setProgress(values[0]);
        }

        @Override
        protected void onPostExecute(String s) {
            super.onPostExecute(s);

            MainActivity activity = activityReference.get();
            if (activity == null || activity.isFinishing()) {
                return;
            }

            activity.progressBar.setProgress(0);
            activity.progressBar.setVisibility(View.INVISIBLE);
            Toast.makeText(activity, s, Toast.LENGTH_SHORT).show();
        }
    }
}
public类MainActivity扩展了AppCompatActivity{
私人ProgressBar ProgressBar;
@凌驾
创建时受保护的void(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
progressBar=findViewById(R.id.progressBar);
}
公共无效startAsyncTask(视图五){
ExampleAyncTask ExampleAyncTask=新ExampleAyncTask(此);
exampleAyncTask.execute(210);
}
私有静态类示例AsyncTask扩展了AsyncTask{
私人财富参考活动参考;
示例AsyncTask(MainActivity上下文){
activityReference=新的WeakReference(上下文);
}
@凌驾
受保护的void onPreExecute(){
super.onPreExecute();
MainActivity=activityReference.get();
if(activity==null | | activity.isFinishing()){
返回;
}
activity.progressBar.setVisibility(View.VISIBLE);
}
@凌驾
受保护的字符串doInBackground(整数…整数){
对于(int i=0;i<整数[0];i++){
出版进度((i*100)/整数[0]);
试一试{
睡眠(1000);
}捕捉(中断异常e){
e、 printStackTrace();
}
}
返回“完成”;
}
@凌驾
受保护的void onProgressUpdate(整型…值){
super.onProgressUpdate(值);
MainActivity=activityReference.get();
if(activity==null | | activity.isFinishing()){
Log.i(“活动”,“活动=null”);
返回;
}否则
Log.i(“活动”,“活动不为空”);
activity.progressBar.setProgress(值[0]);
}
@凌驾
受保护的void onPostExecute(字符串s){
super.onPostExecute(s);
MainActivity=activityReference.get();
if(activity==null | | activity.isFinishing()){
返回;
}
activity.progressBar.setProgress(0);
activity.progressBar.setVisibility(View.INVISIBLE);
Toast.makeText(活动,s,Toast.LENGTH_SHORT).show();
}
}
}

销毁活动时,活动对象应符合垃圾收集的条件。这意味着,接下来的一些GC事件将释放活动持有的内存

您正在做一个假设,即GC必须在您执行方向更改后立即发生,这是不正确的。
WeakReference
确保的是,当下次GC试图清除内存时,它不会成为保存对象的理由。活动对象迟早会被GC清除,但它不会像您预期的那样立即发生

您可以利用
System.gc()
,它将启动同步gc事件,但不建议在正常情况下使用此方法


    System.gc();
    MainActivity activity = activityReference.get();
    // now `activity` should be null

我们可以看到您的活动代码和该活动的清单声明吗?该活动在屏幕旋转时创建和销毁。“活动”的java对象保持不变。WeakReference的目的是在“活动”被破坏时释放引用@RahulKumar所做的声明不正确:在方向更改后,将为新“活动”创建一个新的java对象。@azizbekian:谢谢你指出这一点。即使我这样尝试,它也不正确无效的我不明白。当我按下后退按钮时,它就工作了。我还试着运行了30秒,这意味着,您正在从其他地方保留对活动的引用。用于查找从何处开始。我一添加LeakCanary,它就开始工作(而不是显示通知)。当我移除它时,它停止工作。我不明白发生了什么我已经添加了完整的活动代码。我看不到我持有referenceUpdate的任何位置:如果我在旋转活动后离开活动,然后打开另一个应用程序,它将显示null。可能是因为在我的简单活动中没有必要清理系统而没有清理吗?我用一个强引用测试了它,然后相同的行为不显示为null。