当前位置: 首页 > news >正文

网站正在建设中备案燕郊 网站开发

网站正在建设中备案,燕郊 网站开发,房建设计网站,wordpress5.2 icp备案号一、handler的引入#xff1a; 我们都知道#xff0c;Android UI是线程不安全的#xff0c;如果在子线程中尝试进行UI操作#xff0c;程序就有可能会崩溃。相信大家在日常的工作当中都会经常遇到这个问题#xff0c;解决的方案应该也是早已烂熟于心#xff0c;即创建一个… 一、handler的引入 我们都知道Android UI是线程不安全的如果在子线程中尝试进行UI操作程序就有可能会崩溃。相信大家在日常的工作当中都会经常遇到这个问题解决的方案应该也是早已烂熟于心即创建一个Message对象然后借助Handler发送出去之后在Handler的handleMessage()方法中获得刚才发送的Message对象然后在这里进行UI操作就不会再出现崩溃了。具体实现代码如下 package com.example.androidthreadtest;import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView;public class MainActivity extends Activity implements OnClickListener {public static final int UPDATE_TEXT 1;private TextView text;private Button changeText;private Handler handler new Handler() {public void handleMessage(Message msg) {switch (msg.what) {case UPDATE_TEXT:text.setText(Nice to meet you);break;default:break;}}};Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);text (TextView) findViewById(R.id.text);changeText (Button) findViewById(R.id.change_text);changeText.setOnClickListener(this);}Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.change_text:new Thread(new Runnable() {Overridepublic void run() {Message message new Message();//或者 Message messagehandler.obtainMessage();message.what UPDATE_TEXT;handler.sendMessage(message);}}).start();break;default:break;}} }上面的代码中我们并没有在子线程中直接进行UI操作而是创建了一个Message对象并将它的what字段的值指定为了一个整形常量UPDATE_TEXT用于表示更新TextView这个动作。然后调用Handler的sendMessage()方法将这条Message发送出去。很快Handler就会收到这条Message并在handleMessage()方法在这里对具体的Message进行处理需要注意的是此时handleMessage()方法中的代码是在主线程中运行的。如果发现Message的what字段的值等于UPDATE_TEXT就将TextView显示的内容更新。运行程序后点击按钮TextView就会显示出更新的内容。 注如果从源码的角度理解粗略的描述是这样的 先是调用了handler的obtainMessage()方法得到Message对象。在obtainMessage()方法里做的事情是调用了Message.obtain(this)方法把handler作为对象传进来。在Message.obtain(this)方法里做的事情是生成message对象把handler作为参数赋值给message的target属性。总的来说一个Handler对应一个Looper对象一个Looper对应一个MessageQueue对象使用Handler生成Message所生成的Message对象的Target属性就是该对象。而一个Handler可以生成多个Message所以说Handler和Message是一对多的关系。 二、异步消息处理机制 Handler是Android类库提供的用于接受、传递和处理消息或Runnable对象的处理类它结合Message、MessageQueue和Looper类以及当前线程实现了一个消息循环机制用于实现任务的异步加载和处理。整个异步消息处理流程的示意图如下图所示 根据上面的图片我们现在来解析一下异步消息处理机制 Message消息体用于装载需要发送的对象。handler它直接继承自Object。作用是在子线程中发送Message或者Runnable对象到MessageQueue中在UI线程中接收、处理从MessageQueue分发出来的Message或者Runnable对象。发送消息一般使用Handler的sendMessage()方法而发出去的消息经过处理后最终会传递到Handler的handlerMessage()方法中。MessageQueue用于存放Message或Runnable对象的消息队列。它由对应的Looper对象创建并由Looper对象管理。每个线程中都只会有一个MessageQueue对象。Looper是每个线程中的MessageQueue的管家循环不断地管理MessageQueue接收和分发Message或Runnable的工作。调用Looper的loop()方法后就会进入到一个无限循环中然后每当发现MessageQueue中存在一条消息就会将它取出并调用Handler的handlerMessage()方法。每个线程中也只会有一个Looper对象。 了解这些之后我们在来看一下他们之间的联系 首先要明白的是Handler和Looper对象是属于线程内部的数据不过也提供与外部线程的访问接口Handler就是公开给外部线程的接口用于线程间的通信。Looper是由系统支持的用于创建和管理MessageQueue的依附于一个线程的循环处理对象而Handler是用于操作线程内部的消息队列的所以Handler也必须依附一个线程而且只能是一个线程。 我们再来对异步消息处理的整个流程梳理一遍 当应用程序开启时系统会自动为UI线程创建一个MessageQueue(消息队列)和Looper循环处理对象。首先需要在主线程中创建一个Handler对象并重写handlerMessage()方法。然后当子线程中需要进行UI操作时就创建一个Message对象并通过Handler将这条消息发送出去。之后这条消息就会被添加到MessageQueue的队列中等待被处理而Looper则会一直尝试从MessageQueue中取出待处理消息并找到与消息对象对应的Handler对象然后调用Handler的handleMessage()方法。由于Handler是在主线程中创建的所以此时handleMessage()方法中的代码也会在主线程中运行于是我们在这里就可以安心地进行UI操作了。 通俗地来讲一般我们在实际的开发过程中用的比较多一种情况的就是主线程的Handler将子线程中处理过的耗时操作的结果封装成Message(消息),并将该Message(利用主线程里的MessageQueue和Looper)传递到主线程中最后主线程再根据传递过来的结果进行相关的UI元素的更新从而实现任务的异步加载和处理并达到线程间的通信。 通过上一小节对Handler的一个初步认识后我们可以很容易总结出Handler的主要用途下面是Android官网总结的关于Handler类的两个主要用途 (1)执行定时任务 指定任务时间在某个具体时间或某个时间段后执行特定的任务操作例如使用Handler提供的postDelayed(Runnable r,long delayMillis)方法指定在多久后执行某项操作比如当当、淘宝、京东和微信等手机客户端的开启界面功能都是通过Handler定时任务来完成的。 我们接下来讲一下post。  (2)线程间的通信 在执行较为耗时的操作时Handler负责将子线程中执行的操作的结果传递到UI线程然后UI线程再根据传递过来的结果进行相关UI元素的更新。(上面已有说明) 三、post 对于Handler的Post方式来说它会传递一个Runnable对象到消息队列中这句话稍后会进行详细解释在这个Runnable对象中重写run()方法。一般在这个run()方法中写入需要在UI线程上的操作。 Post允许把一个Runnable对象入队到消息队列中。它的方法有post(Runnable)、postAtTime(Runnable,long)、postDelayed(Runnable,long)。详细解释如下 boolean post(Runnable r)把一个Runnable入队到消息队列中UI线程从消息队列中取出这个对象后立即执行。boolean postAtTime(Runnable r,long uptimeMillis)把一个Runnable入队到消息队列中UI线程从消息队列中取出这个对象后在特定的时间执行。boolean postDelayed(Runnable r,long delayMillis)把一个Runnable入队到消息队列中UI线程从消息队列中取出这个对象后延迟delayMills秒执行void removeCallbacks(Runnable r)从消息队列中移除一个Runnable对象。 下面通过一个Demo讲解如何通过Handler的post方式在新启动的线程中修改UI组件的属性 package com.example.m03_threadtest01;import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.view.View; import android.widget.Button; import android.widget.TextView;public class MainActivity extends Activity {private Button btnMes1,btnMes2;private TextView tvMessage;// 声明一个Handler对象private static Handler handlernew Handler();Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main); btnMes1(Button)findViewById(R.id.button1);btnMes2(Button)findViewById(R.id.button2);tvMessage(TextView)findViewById(R.id.TextView1);btnMes1.setOnClickListener(new View.OnClickListener() {Overridepublic void onClick(View v) {// 新启动一个子线程new Thread(new Runnable() { Overridepublic void run() {// tvMessage.setText(...);// 以上操作会报错无法再子线程中访问UI组件UI组件的属性必须在UI线程中访问// 使用post方式修改UI组件tvMessage的Text属性handler.post(new Runnable() { Overridepublic void run() {tvMessage.setText(使用Handler.post在工作线程中发送一段执行到消息队列中在主线程中执行。); }}); }}).start();}});btnMes2.setOnClickListener(new View.OnClickListener() {Overridepublic void onClick(View v) {new Thread(new Runnable() { Overridepublic void run() {// 使用postDelayed方式修改UI组件tvMessage的Text属性值// 并且延迟3S执行handler.postDelayed(new Runnable() {Overridepublic void run() {tvMessage.setText(使用Handler.postDelayed在工作线程中发送一段执行到消息队列中在主线程中延迟3S执行。); }}, 3000); }}).start();}});}}点击按钮运行结果如下有一点值得注意的是对于Post方式而言它其中Runnable对象的run()方法的代码37行至39行或者58至61行均运行在主线程上虽然看上去是写在子线程当中的如果我们在这段代码里打印日志输出线程的名字会发现输出的是Main Thread的名字。所以对于这段代码而言不能执行在UI线程上的操作一样无法使用post方式执行比如说访问网络。  我们现在来解释一下上面蓝色字体的那句话 这个Runnable对象被放到了消息队列当中去了然后主线程中的Looper因为Handler是在主线程中生成的所以Looper也在主线程中将这个Runnable对象从消息队列中取出来取出来之后做了些什么呢为什么在执行Pos的Runnable对象的run()方法时不是重新开启一个线程呢要了解这个过程只能求助Android的源代码 打开源码的目录sdk\sources\android-19\android\os并找到Handler.java这个文件。找到post方法 public final boolean post(Runnable r){return sendMessageDelayed(getPostMessage(r), 0);} 上方的代码中 可以看到post方法其实就一行代码326行里面调用了sendMessageDelayed()这个方法里面有两个参数。先看一下第一个参数getPostMessage(r)719行private static Message getPostMessage(Runnable r) {Message m Message.obtain();m.callback r;return m;} 上方的代码中将Runnable对象赋值给Message的callback属性。注通过查看Message.java文件的源代码发现callback属性是一个Runnable对象91行/*package*/ Runnable callback; 我们再来分析一下上方getPostMessage()这个方法该方法完成了两个操作 一是生成了一个Message对象二是将r对象复制给Message对象的callback属性。返回的是一个Message对象。 再回到326行 public final boolean post(Runnable r){return sendMessageDelayed(getPostMessage(r), 0);}  这行代码相当于public final boolean post(Runnable r) {Message msg getPostMessage(r);return sendMessage(msg);// //如果需要延时的话这一行可以改为return sendMessageDelayed(msg,0);其中第二个参数改为具体的延时时间 } 现在应该好理解了 第一个问题如何把一个Runnable对象放到消息队列中实际上是生成了一个Message对象并将r赋值给Message对象的callback属性然后再将Message对象放置到消息队列当中。 我们再看看一下Looper做了什么。打开Looper.java的dispatchMessage的方法136行 //一个Handler对应一个Looper对象一个Looper对应一个MessageQueue对象//使用Handler生成Message所生成的Message对象的Target属性就是该对象 //Message msg handler.obtainMessage();//发送一个message对象//handler.sendMessage(msg);msg.target.dispatchMessage(msg);  这里面调用了dispatchMessage()方法打开Handler.java的dispatchMessage()方法93至104行1 /**2 * Handle system messages here.3 */4 public void dispatchMessage(Message msg) {5 if (msg.callback ! null) {6 handleCallback(msg);7 } else {8 if (mCallback ! null) {9 if (mCallback.handleMessage(msg)) { 10 return; 11 } 12 } 13 handleMessage(msg); 14 } 15 }  上方第5行代码因为这次已经给Message的callback属性赋值了所以就不为空直接执行这行代码。即执行handleCallBack()这个方法。打开handleCallBack()方法的源码732至734行 private static void handleCallback(Message message) {message.callback.run();}  看到这个方法就真相大白了message的callback属性直接调用了run()方法而不是开启一个新的子线程。 现在可以明白了  第二个问题 Looper取出了携带有r对象的Message对象以后做的事情是取出Message对象之后调用了dispatchMessage()方法然后判断Message的callback属性是否为空此时的callback属性是有值的所以执行了handleCallback(Message message)在该方法中执行了 message.callback.run()。根据Java的线程知识我们可以知道如果直接调用Thread对象或者Runnable对象的run()方法是不会开辟新线程的而是在原有的线程中执行。  因为Looper是在主线程当中的所以dispatchMessage()方法和handleMessage()方法也都是在主线程当中运行。所以post()里面的run方法也自然是在主线程当中运行的。 使用Post()方法的好处在于避免了在主线程和子线程中将数据传来传去的麻烦。 四、Message Handler如果使用sendMessage的方式把消息入队到消息队列中需要传递一个Message对象而在Handler中需要重写handleMessage()方法用于获取工作线程传递过来的消息此方法运行在UI线程上。 对于Message对象一般并不推荐直接使用它的构造方法得到而是建议通过使用Message.obtain()这个静态的方法或者Handler.obtainMessage()获取。Message.obtain()会从消息池中获取一个Message对象如果消息池中是空的才会使用构造方法实例化一个新Message这样有利于消息资源的利用。并不需要担心消息池中的消息过多它是有上限的上限为10个。Handler.obtainMessage()具有多个重载方法如果查看源码会发现其实Handler.obtainMessage()在内部也是调用的Message.obtain()。 Handler中与Message发送消息相关的方法有 Message obtainMessage()获取一个Message对象。boolean sendMessage()发送一个Message对象到消息队列中并在UI线程取到消息后立即执行。boolean sendMessageDelayed()发送一个Message对象到消息队列中在UI线程取到消息后延迟执行。boolean sendEmptyMessage(int what)发送一个空的Message对象到队列中并在UI线程取到消息后立即执行。boolean sendEmptyMessageDelayed(int what,long delayMillis)发送一个空Message对象到消息队列中在UI线程取到消息后延迟执行。void removeMessage()从消息队列中移除一个未响应的消息。 五、通过Handler实现线程间通信 1、在Worker Thread发送消息在MainThread中接收消息 【实例】点击反扭将下方的TextView的内容修改为“从网络中获取的数据” 【实例】点击反扭将下方的TextView的内容修改为“从网络中获取的数据” 【实际意义】点击按钮时程序访问服务器服务器接到请求之后会返回字符串结果然后更新到程序。完整版代码如下XML布局文件代码如下RelativeLayout xmlns:androidhttp://schemas.android.com/apk/res/androidxmlns:toolshttp://schemas.android.com/toolsandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentandroid:paddingBottomdimen/activity_vertical_marginandroid:paddingLeftdimen/activity_horizontal_marginandroid:paddingRightdimen/activity_horizontal_marginandroid:paddingTopdimen/activity_vertical_margintools:context.MainActivity TextViewandroid:idid/TextViewIdandroid:layout_widthmatch_parentandroid:layout_heightwrap_contentandroid:text数据 / Buttonandroid:idid/ButtonIdandroid:layout_widthmatch_parentandroid:layout_heightwrap_contentandroid:text发送消息 android:layout_belowid/TextViewId//RelativeLayout/prepre namecode classhtmlimport android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView;public class MainActivity extends Activity {private TextView textView ; private Button button ;private Handler handler ;Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);textView (TextView)findViewById(R.id.TextViewId) ;button (Button)findViewById(R.id.ButtonId) ; handler new MyHandler() ;button.setOnClickListener(new ButtonListener()) ;}//在MainAthread线程中接收数据从而修改TextView的值class MyHandler extends Handler {Overridepublic void handleMessage(Message msg) {System.out.println(handleMessage---Thread.currentThread().getName()) ;//得到当前线程的名字String s (String)msg.obj ;textView.setText(s) ;}}//生成线程对象让NetworkThread线程启动class ButtonListener implements OnClickListener {Override public void onClick(View arg0) {Thread t new NetworkThread() ;t.start();}}//在Worker Thread线程中发送数据class NetworkThread extends Thread {Override public void run(){System.out.println(network---Thread.currentThread().getName()) ;//得到当前线程的名字//模拟访问网络当线程运行时首先休眠2秒钟try {Thread.sleep(2*1000) ;} catch (InterruptedException e) {e.printStackTrace();}//变量s的值模拟从网络当中获取的数据String s 从网络中获取的数据 ;//textView.setText(s) ; //这种做法是错误的只有在Mainthread中才能操作UI //开始发送消息Message msg handler.obtainMessage() ; msg.obj s ;handler.sendMessage(msg) ;//sendMessage()方法在主线程或者Worker Thread线程中发送都是可以的都可以被取到}} Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);return true;}} 这段代码的结构和最上面的第一章节是一样的。 上方代码中我们在子线程中休眠2秒来模拟访问网络的操作。 65行用字符串s表示从网络中获取的数据70行然后我们把这个字符串放在Message的obj属性当中发送出去并在主线程中接收36行。 运行后结果如下 可以看到子线程的名字是Thread-1118主线程的名字是main。   2、在MainThread中发送消息在Worker Thread中接收消息 【实例】点击按钮在在MainThread中发送消息在Worker Thread中接收消息并在后台打印输出。 【代码】完整版代码如下 XML布局文件代码如下 /prepre namecode classhtmlRelativeLayout  xmlns:androidhttp://schemas.android.com/apk/res/androidxmlns:toolshttp://schemas.android.com/toolsandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentandroid:paddingBottomdimen/activity_vertical_marginandroid:paddingLeftdimen/activity_horizontal_marginandroid:paddingRightdimen/activity_horizontal_marginandroid:paddingTopdimen/activity_vertical_margintools:context.MainActivity Buttonandroid:idid/ButtonIdandroid:layout_widthmatch_parentandroid:layout_heightwrap_contentandroid:text在主线程中发送消息 //RelativeLayout /prepre namecode classhtmlimport android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.util.Log; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class MainActivity extends Activity {private Button button ;private Handler handler ;Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);button (Button)findViewById(R.id.ButtonId) ;//当用户点击按钮时发送Message的对象msgbutton.setOnClickListener(new OnClickListener() {  //使用匿名内部类为button绑定监听器Overridepublic void onClick(View v) {Log.i(onClick:, Thread.currentThread().getName());Message msg handler.obtainMessage() ;handler.sendMessage(msg) ;}            }) ;WorkerThread wt new WorkerThread() ;wt.start() ;}//在WorkerThread生成handlerclass WorkerThread extends  Thread {Overridepublic void run() {//准备Looper对象Looper.prepare() ;//在WorkerThread当中生成一个Handler对象handler new Handler() {Overridepublic void handleMessage(Message msg) {Log.i(handleMessage:, Thread.currentThread().getName());Log.i(后台输出, 收到了消息对象);}};//调用Looper的loop()方法之后Looper对象将不断地从消息队列当中取出对象然后调用handler的handleMessage()方法处理该消息对象//如果消息队列中没有对象则该线程阻塞Looper.loop() ;   //通过Looper对象将消息取出来}}Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);return true;}}这段代码的结构和最上面的第一章节是一样的。 上方代码中我们在子线程中休眠2秒来模拟访问网络的操作。 65行用字符串s表示从网络中获取的数据70行然后我们把这个字符串放在Message的obj属性当中发送出去并在主线程中接收36行。 运行后结果如下 可以看到子线程的名字是Thread-1118主线程的名字是main。   2、在MainThread中发送消息在Worker Thread中接收消息 【实例】点击按钮在在MainThread中发送消息在Worker Thread中接收消息并在后台打印输出。 【代码】完整版代码如下 XML布局文件代码如下 RelativeLayout xmlns:androidhttp://schemas.android.com/apk/res/androidxmlns:toolshttp://schemas.android.com/toolsandroid:layout_widthmatch_parentandroid:layout_heightmatch_parentandroid:paddingBottomdimen/activity_vertical_marginandroid:paddingLeftdimen/activity_horizontal_marginandroid:paddingRightdimen/activity_horizontal_marginandroid:paddingTopdimen/activity_vertical_margintools:context.MainActivity Buttonandroid:idid/ButtonIdandroid:layout_widthmatch_parentandroid:layout_heightwrap_contentandroid:text在主线程中发送消息 //RelativeLayoutMainActivity.java代码如下 package com.example.m03_handle01;import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.util.Log; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class MainActivity extends Activity {private Button button ;private Handler handler ;Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);button (Button)findViewById(R.id.ButtonId) ;//当用户点击按钮时发送Message的对象msgbutton.setOnClickListener(new OnClickListener() { //使用匿名内部类为button绑定监听器Overridepublic void onClick(View v) {Log.i(onClick:, Thread.currentThread().getName());Message msg handler.obtainMessage() ;handler.sendMessage(msg) ;} }) ;WorkerThread wt new WorkerThread() ;wt.start() ;}//在WorkerThread生成handlerclass WorkerThread extends Thread {Overridepublic void run() {//准备Looper对象Looper.prepare() ;//在WorkerThread当中生成一个Handler对象handler new Handler() {Overridepublic void handleMessage(Message msg) {Log.i(handleMessage:, Thread.currentThread().getName());Log.i(后台输出, 收到了消息对象);}};//调用Looper的loop()方法之后Looper对象将不断地从消息队列当中取出对象然后调用handler的handleMessage()方法处理该消息对象//如果消息队列中没有对象则该线程阻塞Looper.loop() ; //通过Looper对象将消息取出来}}Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);return true;}} 上方的第42行至54行代码这是MainThread中发送消息在Worker Thread中接收消息的固定写法。上面的三个步骤再重复一下 准备Looper对象在WorkerThread当中生成一个Handler对象调用Looper的loop()方法之后Looper对象将不断地从消息队列当中取出对象然后调用handler的handleMessage()方法处理该消息对象如果消息队列中没有对象则该线程阻塞 注意此时handleMessage()方法是在Worker Thread中运行的。 运行程序后当我们点击按钮就会在后台输出“收到了消息对象”这句话 小小地总结一下 首先执行Looper的prepare()方法这个方法有两个作用一是生成Looper对象而是把Looper对象和当前线程对象形成键值对线程为键存放在ThreadLocal当中然后生成handler对象调用Looper的myLooper()方法得到与Handler所对应的Looper对象这样的话handler、looper 、消息队列就形成了一一对应的关系然后执行上面的第三个步骤即Looper在消息队列当中循环的取数据。 六、为什么在有些时候子线程中是可以直接更新UI的 这道面试题应该是本文中最难的一个面试题了需要好好理解。为了回答这个问题我们需要先通过看源码去了解下面这三个问题 1Android是如何检测非UI线程去更新UI的 2ViewRootImp是什么 3ViewRootImp是在哪里创建的 源码我就不贴出来了这里我只是总结一下。 答案   非UI线程真的不能更新UI吗? 是可以的。 解释   在线程中更新UI时会调用ViewParent.invalidateChild()方法检查当前的thread是否是Mainthread。 具体源码如下 final ViewParent p mParent;if (p ! null ai ! null l r t b) {final Rect damage ai.mTmpInvalRect;damage.set(l, t, r, b);p.invalidateChild(this, damage);}而ViewParent是一个接口类其实现类是ViewRootImpl通过查看invalidateChild()方法里面的代码就可以看到会他调用checkThread()方法。checkThread()方法如下void checkThread() {if (mThread ! Thread.currentThread()) { //检查更新UI的线程是否是MainThreadthrow new CalledFromWrongThreadException(Only the original thread that created a view hierarchy can touch its views.);}} 上面的第02行就是检查在线程中更新UI时当前线程是否是MainThread。但是ViewRootImpl这个类是在activity的onResume()方法中创建的。就算在子线程中更新UI只要在ViewRootImpl创建之前更新UI比如程序在执行onCreate方法时我就去执行setText方法区更新UI就可以逃避掉checkThread()的检查。 关于本题给出以下链接大家去细读一下源码吧 Android更新Ui进阶精解一 http://www.jianshu.com/p/6de0a42a44d6 为什么我们可以在非UI线程中更新UI http://blog.csdn.net/aigestudio/article/details/43449123
http://wiki.neutronadmin.com/news/328083/

相关文章:

  • 网站建设 微信小程序虫虫wap建站源码
  • 本溪网站建设兼职网页浏览器的缩写
  • 北京做网站比较好的mega Wordpress
  • 汽车网站网页设计import wordpress
  • 做百度网站每年的费用多少钱南昌网站建设模板合作
  • 一般vs做的网站的总体框架英文营销网站建设
  • 镇江网站制作价格电脑网站建设
  • 成都网站建设创意python 做网站很快吗
  • 免费宣传网站上海自贸区注册公司优惠政策
  • 网站建设的五个基本要素新闻门户网站建设
  • h5页面设计是什么意思佛山百度快速排名优化
  • 网站建设万户曲靖网站制作一条龙
  • 企业官网网站建设上海电脑网页版微信
  • 建设集团有限公司网站首页ui培训设计怎么样
  • 温州网站建设前十公司企业策划书内容
  • 南通市网站大学计算机网页设计作业
  • 化妆品网站建设策划书调用wordpress文章
  • 做淘宝客网站需要做后台吗郑州 小程序开发
  • 网站开发与管理实验五自适应网站什么意思
  • 市北区大型网站建设商业网站的相关内容
  • 学生成绩管理系统网站建设大门户wordpress主题破解版
  • 网站空间到期时间查询公益广告设计图片
  • 如何进行网站宣传推广wordpress增强编辑器
  • 上海商城网站北京代理网站备案
  • 邢台专业做wap网站网站开发项目的部署
  • 做IP授权的一般看什么网站设计公司网站的主页怎么做
  • 摄影师如何做网站万网 成品网站
  • 个人免费域名空间建站国家信用企业信息系统
  • 网站怎么做施工企业环保应急预案
  • 三合一网站建设哪个好人像摄影网站