android UI线程安全

首先对于android而言,UI线程就是我们的主线程,在Android应用启动时,会自动创建一个线程,主线程负责UI的展示、UI事件消息的派发处理等等,因此主线程也叫做UI线程。

线程安全是多线程编程时的计算机程序代码中的一个概念。在拥有共享数据的多条线程并行执行的程序中,线程安全的代码会通过同步机制保证各个线程都可以正常且正确的执行,不会出现数据污染等意外情况。

如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的,或者说:一个类或者程序所提供的接口对于线程来说是原子操作或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是说我们不用考虑同步的问题 。

  • 为什么说Android UI不是线程安全的?

UI线程才能与Android UI工具包中的组件进行交互,在开发Android应用时必须遵守单线程模型的原则:

android UI 中提供invalidate()来更新界面,而invalidate()方法是线程不安全

Android提供了Invalidate方法实现界面刷新,但是Invalidate不能直接在非UI主线程中调用,因为他是违背了单线程模型:Android UI操作并不是线程安全的,并且这些操作必须在UI线程中调用。例如:在非UI线程中调用invalidate会导致线程不安全,也就是说可能在非UI线程中刷新界面的时候,UI线程(或者其他非UI线程)也在刷新界面,这样就导致多个界面刷新的操作不能同步,导致线程不安全

Handler类

Handler主要用于异步消息的处理:当发出一个消息之后,首先进入一个消息队列,发送消息的函数即刻返回,而另外一个部分在消息队列中逐一将消息取出,然后对消息进行处理,也就是发送消息和接收消息不是同步的处理。 这种机制通常用来处理相对耗时比较长的操作。

传递Message。用于接受子线程发送的数据, 并用此数据配合主线程更新UI。

在Android中,对于UI的操作通常需要放在主线程中进行操作。如果在子线程中有关于UI的操作,那么就需要把数据消息作为一个Message对象发送到消息队列中,然后,由Handler中的handlerMessage方法处理传过来的数据信息,并操作UI。当然,Handler对象是在主线程中初始化的,因为它需要绑定在主线程的消息队列中。

类sendMessage(Message msg)方法实现发送消息的操作。 在初始化Handler对象时重写的handleMessage方法来接收Message并进行相关操作。

  • Message

Message是Handler接收与处理的消息对象

其中msg.what主要用于区分handler接受到的message实例。根据此区分,Handler可以对消息进行不同的处理操作。

msg.setData(),可以将数据存入msg。

利用handler.sendMessage(msg);将消息发送给Handler

通过Handler类将子线程中更新UI的消息发送至UI线程更新UI

  • 子线程中
Message msg=Message.obtain();
msg.what=1;
Bundle bundle =new Bundle();
bundle.putString("linkman", userAddressInfo.getLinkman());
bundle.putString("telephone", userAddressInfo.getTelephone());
msg.setData(bundle);
handler.sendMessage(msg);

因为在Android段进行异步网络请求获取数据的时候,成功获取得到数据是在子线程中的,因为UI更新是需要在UI线程(主线程)中进行的。所以需要发送一个Message给Handler,在主线程中接收消息并处理。

  • 主线程中
private Handler handler= new Handler(){
    public void handleMessage(Message msg){
        Bundle bundle=msg.getData();
        if(msg.what==1){
            linkman_issue_order_tv.setText(bundle.getString("linkman"));
            telephone_issue_order_tv.setText(bundle.getString("telephone"));
            
        }else if (msg.what==2){
            issue_order_touxiang_iv.setImageURL(bundle.getString("userImg"));
            issue_order_user_nick_name_tv.setText(bundle.getString("userNickname"));
        }
    }
};

主线程接收并处理子线程中发送的Message

参考资料

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐