前言
这个是一个入门的话题但是也要通透的简单的说一下对于学过java或者Android的都知道,在代码中主线程不能进行耗时操作,子线程不能更新UI,比如在自定义view时,想要让View重绘,需要先判断当前线程到底是不是主线程,然后根据判断结果来决定到底是调用 invalidate() 还是 postInvalidate() 方法. 如果当前是主线程,就调用 invalidate()方法;而如果当前是子线程,就调用 postInvalidate() 方法,注意:子线程中不能调用 invalidate() 方法,否则就会报异常,提示我们不能在子线程中更新UI。
那么该这么判断呢?可以用这个来进行判断
boolean b = Thread.currentThread() == Looper.getMainLooper().getThread();
方式1:
打个比方如果我们不知道onCreate是不是主线程怎么办(当然onCreate肯定是主线程)用这个先判断一下,然后再决定是否做耗时操作
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
boolean b = Thread.currentThread() == Looper.getMainLooper().getThread();
Toast.makeText(MainActivity.this, b+"", Toast.LENGTH_SHORT).show();
}
}
结果是返回true确定了是主线程(我们可以在这里更新UI比如setText,Toast等)但是这个时候我们就不能做耗时操作了,会有人问什么是耗时操作呢?
例如
1.下载文件
2.文件操作
3.比较大的数据初始化操作
4.音频格式转换
5.网络链接操作
等
那么有这个些操作的时候就应该在主线程创建个子线程了,在Thread里面操作
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Thread(new Runnable() {
@Override
public void run() {
boolean b = Thread.currentThread() == Looper.getMainLooper().getThread();//这个不是耗时操作
}
}).start();
}
}
这个时候Thread.currentThread() == Looper.getMainLooper().getThread()这个结果肯定是false了但是这个我为啥没有在Thread里面添加Toast呢?答案是Toast是UI操作,但是我们不能在子线程做UI操作这个时候我们应该切换到主线程Toast
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Thread(new Runnable() {
@Override
public void run() {
boolean b = Thread.currentThread() == Looper.getMainLooper().getThread();
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, b+"", Toast.LENGTH_SHORT).show();
}
});
}
}).start();
}
}
这样返回的就是false了因为我们是在子线程里面获取的Thread.currentThread(),如果在runOnUiThread里面获取Thread.currentThread()再Toast那就是true了。
但是要考虑一种情况就是Runnable是一个匿名内部类,所以它会持有当前Activity的隐式引用。如果Activity销毁,但是线程任务还未执行完毕,就会导致Activity无法被GC回收,造成内存泄漏。
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
new Thread(new mRunnable()).start();
}
private static class mRunnable implements Runnable{
@Override
public void run() {
boolean b = Thread.currentThread() == Looper.getMainLooper().getThread();
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this, b+"", Toast.LENGTH_SHORT).show();
}
});
}
}
}
方式2
第二种方式是用Handler话不多说上代码,这种方式的通信打个比方就是软件开屏页面倒计时会用到
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
HandlerThread handlerThread = new HandlerThread("HandlerThread");
handlerThread.start();
Handler handler=new Handler(handlerThread.getLooper()){
@Override
public void handleMessage(@NonNull Message msg) {
super.handleMessage(msg);
if (msg.what==1){
Log.e("handlerThread=====","子线程执行");
}
}
};
Log.e("handlerThread=====","主线程执行");
handler.sendEmptyMessage(1);
}
}
//附上handler销毁的方式需要的话可以手动销毁
handler.removeCallbacksAndMessages(null);
结尾
编码过程中答案不唯一按照自己的思路进行,查漏补缺都会是一个很好的锻炼👋
启发文档
https://www.jianshu.com/p/bd15810967e4
https://blog.csdn.net/yjh_dream/article/details/84030162