在Android中使用ProgressBar进行回调设置进度时候会提示‘This Handler class should be static or leaks might occur’的警告,那就说明是你的自定义Handler类有内存泄露的问题,一般来说就是持有外部类的引用。要解决这个ProgressBar的使用问题需要明确如下几个知识点:
1.Android的UI(比如ProgressBar)也是线程不安全的,如果想要更新应用程序里的UI元素,则必须在主线程中进行,否则会出现异常。
2.不能在UI主线程中使用Thread.sleep();会导致视图变化看不到(后面做ProgressBar演示需要用到)。
3.静态内部类是不持有外部类的引用,因此自定义Handler类可以用静态内部类来完成,至于为什么不持有外部类的引用可参考:非静态内部类、非静态匿名内部类会持有外部对象的引用
4.如果你想在静态内部类/匿名类中使用外部类的属性或方法时,可以显示的持有一个弱引用(WeakReference )。
下面给大家展示用静态内部类实现Handler类来完成ProgressBar的进度条显示的源码。
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private ProgressBar progressBar;
private MyHandler handler = new MyHandler(this);
/**
* 静态内部类实现Handler
*/
private static class MyHandler extends Handler{
private WeakReference mActivity;
private MyHandler(MainActivity mActivity) {
super();
this.mActivity = new WeakReference(mActivity);
}
@Override
public void handleMessage(Message msg) {
if(mActivity.get() == null){
return;
}
//在静态内部类/匿名类中使用外部类的属性或方法时,可以显示的持有一个弱引用
final MainActivity activity = mActivity.get(); //弱引用
activity.progress.setText(msg.arg1+"%");
}
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
progressBar = findViewById(R.id.progress_bar); //实例化ProgressBar
Button button = findViewById(R.id.button);
button.setOnClickListener(this); //启动进度条的按钮添加点击事件
}
@Override
public void onClick(View view) {
if (view.getId() == R.id.button){
new Thread(new Runnable() {
@Override
public void run() {
int progress = progressBar.getProgress();
while (progress < 100) {
try {
Message message = new Message();
progress = progress + 1;
progressBar.setProgress(progress);
message.arg1 = progress;
handler.sendMessage(message);
Thread.sleep(100); //不能在主线程中使用
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
}
当然只是针对ProgressBar的显示而又不想发生‘This Handler class should be static or leaks might occur’我们还可以使用Android提供的runOnUiThread来完成。源码如下:
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private ProgressBar progressBar;
private int pro; //进度条的值
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
progressBar = findViewById(R.id.progress_bar); //实例化ProgressBar
Button button = findViewById(R.id.button);
button.setOnClickListener(this); //启动进度条的按钮添加点击事件
}
@Override
public void onClick(View view) {
if (view.getId() == R.id.button){
pro = progressBar.getProgress();
new Thread(new Runnable() {
@Override
public void run() {
while (pro <= 100) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {//切换回主线程更改ProgressBar的值
@Override
public void run() {
progress.setText(String.format("%d%%", pro));
}
pro = pro + 1;
}
});
}
}
}).start();
}
}
}
小弟也是最近再跟着郭霖大牛的《第一行代码》在学习android,纯纯的菜鸟一枚,对很多东西的认识不深,知其然不知其所以然,这也是我的第一篇博文,写的不好,有错误的地方希望各位大神包含和指正,小弟感激不尽!