handler是android给我们提供用来更新UI的一套机制,也是一套消息处理的机制,我们可以发送消息,也可以通过它处理消息。

        它最根本的目的就是解决多线程并发问题,假设如果在一个Activity当中,有多个线程去更新UI,并且都没有加锁机制,就会产生更新界面错乱。如果对更新UI的操作都进行枷锁处理又会使应用性能下降,所以Android给我们提供了一套更新UI的机制,我们只需要遵循这样的机制就可以了,根本不用去关心多线程问题,多有的更新UI操作,都是在主线程的消息队列当中去轮询处理的。

handler的使用:

1、使用handler更新UI

详细参考:Android Handler使用详解之UI更新

定义handler

private Handler handler = new Handler();

定义Runnable

Runnable runnable = new Runnable() {
	public void run() {
		tetxView.setText("cx");
	}
};

启动Runnable

handler.post(runnable);

2、使用handler延时更新UI

前面相同,只有启动时有差别

handler.postDelayed(runnable, 2000);//延时2s更新UI

延时发送通知

handler.sendEmptyMessageDelayed(what, 2000);

3、使用handler消息传递

创建消息,可以创建不同类型的消息(这里arg1、arg2和obj)

Message message = new Message(); //或Message message = handler.obtainMessage();这是也可以用message.sendToTarget();发送消息
message.arg1=66;
message.arg2=33;
message.obj="cx";
handler.sendMessage(message);

接收并处理消息

private Handler handler = new Handler(){
	public void handleMessage(Message msg) {
		tetxView.setText((String) msg.obj + msg.arg1 + msg.arg2);
	};
};

4、消息延时传递sendMessageDelayed,与上面相同。

5、handler移除功能

例如:在2中的延时更新UI过程中,在延时过程中移除,则UI不再更新。

handler.removeCallbacks(runnable);

6、handler消息拦截

消息接收

private Handler handler = new Handler(new Callback() {
		
	@Override
	public boolean handleMessage(Message msg) {
		// TODO Auto-generated method stub
		Toast.makeText(getApplicationContext(), "1", 1).show();
		return true;//返回false,执行完上面的代码在执行下面的;返回true,则不再执行下面的代码
	}
}){
	@Override
	public void handleMessage(Message msg) {
		// TODO Auto-generated method stub
		Toast.makeText(getApplicationContext(), "2", 1).show();
	}
};

发送一个空消息

handler.sendEmptyMessage(1);

7、handler原理总结:

Handler负责发送消息,Looper负责接收Handler发送的消息,并直接把消息回传给handler自己,MessageQueue就是一个存储消息的容器。

8、创建与子线程相关的Handler

主线程的Handler中不要执行耗时操作,否则界面会出现卡死现象。

创建主线程Handler

private Handler handler = new Handler(){
	public void handleMessage(android.os.Message msg) {
		System.out.println("UI-----------"+Thread.currentThread());
	};
};

创建子线程和子线程Handler

class MyThread extends Thread{
	public Handler handler;
	@Override
	public void run() {
		// TODO Auto-generated method stub
		Looper.prepare();//要创建handler必须先创建接收handler消息的Looper
		handler=new Handler(){
			public void handleMessage(android.os.Message msg) {
				System.out.println("-----------"+Thread.currentThread());
			};
		};
		Looper.loop();//开始循环Looper
	}
};

发送消息

MyThread thread=new MyThread();//定义子线程
thread.start();//启动子线程
thread.handler.sendEmptyMessage(1);//向子线程Handler发送消息
handler.sendEmptyMessage(1);<span style="font-family: Arial, Helvetica, sans-serif;">//向主线程Handler发送消息</span>

9、HandlerThread

在主线程的Handler中传入子线程中定义的Looper时,会出现空指针问题。

定义子线程及子线程中的Handler和Looper

class MyThread extends Thread{
	public Handler handler;
	public Looper looper;
	@Override
	public void run() {
		// TODO Auto-generated method stub
		Looper.prepare();
		looper=Looper.myLooper();
		handler=new Handler(){
			public void handleMessage(android.os.Message msg) {
				System.out.println("-----------"+Thread.currentThread());
			};
		};
		Looper.loop();
	}
};

启动子线程,创建一个Handler并传入子线程中的Looper

MyThread thread=new MyThread();
thread.start();
Handler handler=new Handler(thread.looper){
	public void handleMessage(android.os.Message msg) {
		System.out.println(msg);
	};
};

        运行程序会出现错误,thread.looper为空,因为在主线程中创建Handler时,子线程中的Looper还没有创建,这就是多线程并发的问题。修改上面代码:

HandlerThread thread=new HandlerThread("chenxu");//主要功能就是创建Looper,参数为线程名。
thread.start();
Handler handler=new Handler(thread.getLooper()){
	public void handleMessage(android.os.Message msg) {
		//可执行耗时操作
		System.out.println(">>>>>>>>>>>>" + Thread.currentThread());//与上面线程名一致
	};
};
handler.sendEmptyMessage(1);

        这时的handler就相当于是子线程中的handler,即使执行耗时操作也不会出现界面卡顿的现象。

10、主线程与子线程信息交互

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Message;

public class MainActivity extends Activity {
	private Handler threadHandler;
	
	//主线程handler
	Handler handler = new Handler(){
		public void handleMessage(android.os.Message msg) {
			Message message = new Message();
			//向子线程发送消息
			threadHandler.sendMessageDelayed(message, 1000);
			System.out.println("main handler");
		};
	};
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		
		HandlerThread thread = new HandlerThread("threadHandler");//主要功能就是创建Looper,参数为线程名。
		thread.start();
		//子线程handler
		threadHandler = new Handler(thread.getLooper()){
			public void handleMessage(android.os.Message msg) {
				Message message = new Message();
				//向主线程发送消息
				handler.sendMessageDelayed(message, 1000);
				System.out.println("threadHandler handler");
			};
		};
		handler.sendEmptyMessage(1);
	}
}

11、其他消息传递方法

发送消息

handler.obtainMessage(1,true).sendToTarget();
handler.obtainMessage(2,"str").sendToTarget();

接收消息

Handler handler = new Handler() {

	@Override
	public void handleMessage(Message msg) {
		super.handleMessage(msg);
			switch (msg.what) {
				case 1:
					boolean b = (Boolean)msg.obj;
				break;
				
				case 2:
					String  s = (String)msg.obj;
			break;
		}
	}
};

12、Handler黄色警告

        出现黄色警告是因为 Handler 在 Android 中用于消息的发送与异步处理,常常在 Activity 中作为一个匿名内部类来定义,此时 Handler 会隐式地持有一个外部类对象(通常是一个 Activity)的引用。当 Activity 已经被用户关闭时,由于 Handler 持有 Activity 的引用造成 Activity 无法被 GC 回收,这样容易造成内存泄露。

        解决办法:将其定义成一个静态内部类(此时不会持有外部类对象的引用),在构造方法中传入 Activity 并对 Activity 对象增加一个弱引用,这样 Activity 被用户关闭之后,即便异步消息还未处理完毕,Activity 也能够被 GC 回收,从而避免了内存泄露。

private MyHandler mHandler = new MyHandler((Activity) context);

// 发送消息
Message message = new Message();
message.what = 1;
mHandler.sendMessage(message);

// 静态内部类
static class MyHandler extends Handler {
    // 弱引用
    WeakReference weakReference;
    public MyHandler(Activity activity) {
        weakReference = new WeakReference(activity);
    }

    @Override
    public void handleMessage(Message msg) {
        switch (msg.what) {
            case 1:
                Toast.makeText((Context) weakReference.get(), "收到消息", Toast.LENGTH_SHORT).show();
                break;
            default:
                // do something...
                break;
        }
    }
}

13、消息队列使用

private ExecutorService singleThreadExecutor = null;
private LinkedBlockingQueue linkedBlockingQueue = new LinkedBlockingQueue<Runnable>(200);

/**
 * 创建队列
 */
private ExecutorService getThreadExecutor() {
    if (singleThreadExecutor == null) {
        singleThreadExecutor = new ThreadPoolExecutor(1, 1,
                1000L, TimeUnit.MILLISECONDS,
                linkedBlockingQueue);
    }
    return singleThreadExecutor;
}

/**
 * 加入队列
 */
getThreadExecutor().execute(new Runnable() {
        @Override
        public void run() {
            //要执行的代码
        }
    });
}
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐