Android 主线程与子线程区分和实践

35 篇文章 0 订阅

前言
这个是一个入门的话题但是也要通透的简单的说一下对于学过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

  • 7
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

王富贵王富贵王富贵

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值