使用 android 处理程序时如何解决有关内存泄漏的警告?

How can I resolve warnings about memory leaks when using android Handler?

我是初学者android。 我在学习 Thread 时使用的是 Handler。 顺便说一下,我在 android studio 中使用 Handler 来警告内存泄漏。 我搜索了很多不同的问题,但没有与我的情况相对应的部分。 如何解决使用处理程序时有关内存泄漏的警告?

public class HandlerActivity extends AppCompatActivity implements Runnable {

    ProgressBar pb;
    TextView txtRate;
    Button btnStart;
    static int value;

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

        pb = findViewById(R.id.pb);
        txtRate = findViewById(R.id.txtRate);
        btnStart = findViewById(R.id.btnStart);

        btnStart.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Thread th = new Thread(HandlerActivity.this);
                th.start();
            }
        });
    }

        Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            pb.setProgress(value);
            txtRate.setText("Process : " + value + "%");
        }
    };

    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            value = i;

            handler.sendEmptyMessage(0);

            try {
                Thread.sleep(100);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Toast.makeText(HandlerActivity.this, "Progress Done !", Toast.LENGTH_SHORT).show();
            }
        });
    }
}

基本上 TextView 或任何其他 View 持有代表相应 ActivityContext 对象的引用。当您在 Thread 中保留对任何 View 的强引用时,您不仅存储了 View 对象,而且还存储了一个代表 Activity 创建的 Context 对象它。现在,由于 Thread 与 Activity 生命周期无关,即使在 Activity 被销毁后,它们仍将继续 运行。如果是这种情况,Thread 将通过那个 View 对象持有一个被破坏的 Activity 的引用,从而造成内存泄漏。

上述问题可以通过存储View对象的弱引用来解决,以便GC在必要时对其进行垃圾回收。您可以通过以下方式消除内存泄漏:

public class HandlerActivity extends AppCompatActivity implements Runnable {
    WeakReference<ProgressBar> pb;
    WeakReference<TextView> txtRate;
    Button btnStart;
    static int value;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        ...
        pb = new WeakReference<>(findViewById(R.id.pb)); // you may require to cast findViewById() to ProgressBar
        txtRate = new WeakReference<>(findViewById(R.id.txtRate));  // you may require to cast findViewById() to TextView
        ...
    }

    Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if(pb.get()!=null) pb.get().setProgress(value);
            if(txtRate.get()!=null) txtRate.get().setText("Process : " + value + "%");
        }
    };

    @Override
    public void run() {
        for (int i = 1; i <= 100; i++) {
            // Its always recommended to check if activity is running and stop the thread if not running
            if(isFinishing() || isDestroyed()) {
                return;
            }
        }
    }
}

Roaim, Mark Keen 在他们的帮助下,我解决了这个问题并自己给出了完整的答案。感谢 Roaim、Mark Keen。

public class HandlerActivity extends AppCompatActivity implements Runnable {

ProgressBar pb;
TextView txtRate;
Button btnStart;
int value;

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

    pb = findViewById(R.id.pb);
    txtRate = findViewById(R.id.txtRate);
    btnStart = findViewById(R.id.btnStart);

    btnStart.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Thread th = new Thread(HandlerActivity.this);
            th.start();
        }
    });
}

private static class WeakHandler extends Handler {
    private final WeakReference<HandlerActivity> mWeakActivity;

    private WeakHandler(HandlerActivity AppCompatActivity) {
        mWeakActivity = new WeakReference<>(AppCompatActivity);
    }

    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        HandlerActivity _activity = mWeakActivity.get();

        if (_activity != null) {

            switch (msg.what) {
                case 0:
                    _activity.pb.setProgress(_activity.value);
                    _activity.txtRate.setText("Process : " + _activity.value + "%");
                    break;
            }
        }
    }
}

private final WeakHandler mHandler = new WeakHandler(this);

@Override
public void run() {
    for (int i = 1; i <= 100; i++) {
        value = i;

        mHandler.sendEmptyMessage(0);

        try {
            Thread.sleep(100);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            Toast.makeText(HandlerActivity.this, "Progress Done !.", Toast.LENGTH_SHORT).show();
        }
    });
}

}