1).Android 价值千万 java线程专题:Wait¬ify&join&Yield
http://blog.csdn.net/whb20081815/article/details/65627387
2).Android 价值千万 java多线程同步 <二>Callable和Future&FutureTask
http://blog.csdn.net/whb20081815/article/details/65630694
3).Android 价值千万 java多线程<三>生产者消费者模型四种实现方法
http://blog.csdn.net/whb20081815/article/details/65635647
4).Android 价值千万 java多线程同步 <四> synchronized&Lock&Atomic6种方式
http://blog.csdn.net/whb20081815/article/details/66971983
http://blog.csdn.net/whb20081815/article/details/68498371
6).Android AsyncTask 那些你不知道的事
https://blog.csdn.net/WHB20081815/article/details/70332209
7).Android 厉害了ThreadLocal的工作原理和实例分析
https://blog.csdn.net/WHB20081815/article/details/66974651
8).Android Handle消息机制:秒懂Looper、Handler、Message三者关系
https://blog.csdn.net/WHB20081815/article/details/67639060
9).Android 性能优化<八> 多线程优化和线程管理
https://blog.csdn.net/WHB20081815/article/details/77775444
1. 不要阻塞UI线程;
2. 不要在UI线程之外访问UI组件,即不能在子线程访问UI组件,只能在UI线程访问。
对于Looper主要是prepare()和loop()两个方法。
首先看prepare()方法
private static void prepare(boolean quitAllowed) {
if (sThreadLocal.get() != null) {
throw new RuntimeException("Only one Looper may be created per thread");
}
sThreadLocal.set(new Looper(quitAllowed));
}
ThreadLocal保证了一个线程中只有一个Looper实例
在构造方法中,创建了一个MessageQueue(消息队列)。
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
Loop方法:里面一个For循环,阻塞队列,不断的取消息
public static void loop() {
final Looper me = myLooper();
if (me == null) {
throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
}
final MessageQueue queue = me.mQueue;
// Make sure the identity of this thread is that of the local process,
// and keep track of what that identity token actually is.
Binder.clearCallingIdentity();
final long ident = Binder.clearCallingIdentity();
for (;;) {
Message msg = queue.next(); // might block
if (msg == null) {
// No message indicates that the message queue is quitting.
return;
}
Looper主要作用:
1、 与当前线程绑定,保证一个线程只会有一个Looper实例,同时一个Looper实例也只有一个MessageQueue。
2、 loop()方法,不断从MessageQueue中去取消息,交给消息的target属性的dispatchMessage去处理。
好了,我们的异步消息处理线程已经有了消息队列(MessageQueue),也有了在无限循环体中取出消息的哥们,现在缺的就是发送消息的对象了,于是:Handler登场了。
public Handler(Callback callback, boolean async) {
if (FIND_POTENTIAL_LEAKS) {
final Class extends Handler> klass = getClass();
if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
(klass.getModifiers() & Modifier.STATIC) == 0) {
Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
klass.getCanonicalName());
}
}
mLooper = Looper.myLooper();
if (mLooper == null) {
throw new RuntimeException(
"Can't create handler inside thread that has not called Looper.prepare()");
}
mQueue = mLooper.mQueue;
mCallback = callback;
mAsynchronous = async;
}
发送消息:把消息添加到了MessageQueue队列里面
移除消息:通过MessageQueue
public final void removeMessages(int what) {
mQueue.removeMessages(this, what, null);
}
总结流程:
1、首先Looper.prepare()在本线程中保存一个Looper实例,然后该实例中保存一个MessageQueue对象;因为Looper.prepare()在一个线程中只能调用一次,所以MessageQueue在一个线程中只会存在一个。
2、Looper.loop()会让当前线程进入一个无限循环,不端从MessageQueue的实例中读取消息,然后回调msg.target.dispatchMessage(msg)方法。
3、Handler的构造方法,会首先得到当前线程中保存的Looper实例,进而与Looper实例中的MessageQueue想关联。
4、Handler的sendMessage方法,会给msg的target赋值为handler自身,然后加入MessageQueue中。
5.报错Can't create handler inside thread that has not called Looper.prepare(),没有调用Looper.loop().UI线程默认调用了Looper.prepare()和Looper.loop()方法。Looper.prepare()和Looper.loop()方法。
列子:
public void testHandler2(final TextView textView){
mHandler=new Handler();
new Thread(new Runnable() {
@Override
public void run() {
while (true){
i++;
mHandler.post(new Runnable() {
@Override
public void run() {
textView.setText(""+i);
Log.d("mHandler",""+i);
}
});
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
错误代码如下:
/**
* Error,while死循环,主线程做了耗时的操作
* @param textView
*/
public void testHandler(final TextView textView){
mHandler=new Handler(getMainLooper());
mHandler.post(new Runnable() {
@Override
public void run() {
// textView.setText(""+i);
while (true){
Log.d("mHandler",""+i+"ThreadName"+Thread.currentThread().getName());
i++;
if(i%1000==0){
textView.setText(""+i);
}
}
}
});
}
AS代码地址:不知道为什么上传不了