Android——HandlerThread浅析

Android——HandlerThread浅析,第1张

概述1.简介在Android系统中,我们执行完耗时 *** 作都要另外开启子线程来执行,执行完线程以后线程会自动销毁。想象一下如果我们在项目中经常要执行耗时 *** 作,如果经常要开启线程,接着又销毁线程,这无疑是很消耗性能的。HandlerThread是Google帮我们封装好的,可以用来执行多个耗时 *** 作,而 1. 简介

在AndroID系统中,我们执行完耗时 *** 作都要另外开启子线程来执行,执行完线程以后线程会自动销毁。想象一下如果我们在项目中经常要执行耗时 *** 作,如果经常要开启线程,接着又销毁线程,这无疑是很消耗性能的。

HandlerThread是Google帮我们封装好的,可以用来执行多个耗时 *** 作,而不需要多次开启线程,里面是采用Handler和Looper实现的。

怎么使用?

//创建实例对象,该参数表示线程的名字HandlerThread handlerThread = new HandlerThread("myHandlerThread");//启动我们创建的HandlerThread线程handlerThread.start();//怎样将Handler与线程对象绑定在一起mThreadHandler = new Handler(mHandlerThread.getLooper()) {	@OverrIDe	public voID handleMessage(Message msg) {		checkForUpdate();		if(isUpdate){			mThreadHandler.sendEmptyMessage(MSG_UPDATE_INFO);		}	}};
2. 看个实例
public class MainActivity extends AppCompatActivity {	private static final int MSG_UPDATE_INFO = 0x100;	Handler mMainHandler = new Handler();	private TextVIEw mTv;	private Handler mThreadHandler;	private HandlerThread mHandlerThread;	private boolean isUpdate = true;	@OverrIDe	protected voID onCreate(Bundle savedInstanceState) {		super.onCreate(savedInstanceState);		setContentVIEw(R.layout.activity_main);		mTv = (TextVIEw) findVIEwByID(R.ID.tv);		initHandlerThread();	}	private voID initHandlerThread() {		mHandlerThread = new HandlerThread("xujun");		mHandlerThread.start();		mThreadHandler = new Handler(mHandlerThread.getLooper()){			@OverrIDe			public voID handleMessage(Message msg) {				checkForUpdate();				if (isUpdate) {					mThreadHandler.sendEmptyMessage(MSG_UPDATE_INFO);				}			}		};	}	/*** 模拟从服务器解析数据*/	private voID checkForUpdate() {		try {			//模拟耗时			Thread.sleep(1200);			mMainHandler.post(new Runnable() {				@OverrIDe				public voID run() {					String result = "实时更新中,当前股票行情:<Fontcolor='red'>%d</Font>";					result = String.format(result, (int) (Math.random() * 5000 + 1000));					mTv.setText(HTML.fromHTML(result));				}				});		} catch (InterruptedException e) {			e.printstacktrace();		}	}		@OverrIDe	protected voID onResume() {		isUpdate = true;		super.onResume();		mThreadHandler.sendEmptyMessage(MSG_UPDATE_INFO);	}	@OverrIDe	protected voID onPause() {		super.onPause();		isUpdate = false;		mThreadHandler.removeMessages(MSG_UPDATE_INFO);	}@OverrIDe	protected voID onDestroy() {		super.onDestroy();		mHandlerThread.quit();		mMainHandler.removeCallbacksAndMessages(null);	}}

运行以上测试代码,将可以看到如下效果图(例子不太恰当,主要使用场景是在handleMessage中执行耗时 *** 作)

3. 看看源码

基于sdk23的,可以看到,只有一百多行代码:

public class HandlerThread extends Thread {	int mPriority;	int mTID = -1;	Looper mLooper;	public HandlerThread(String name) {		super(name);		mPriority = Process.THREAD_PRIORITY_DEFAulT;	}	public HandlerThread(String name, int priority) {		super(name);		mPriority = priority;	}/*** Call back method that can be explicitly overrIDden if needed to execute some* setup before Looper loops.*/	protected voID onLooperPrepared() {	}		@OverrIDe	public voID run() {		mTID = Process.myTID();		Looper.prepare();		//持有锁机制来获得当前线程的Looper对象		synchronized (this) {			mLooper = Looper.myLooper();			//发出通知,当前线程已经创建mLooper对象成功,这里主要是通知getLooper方法中的wait			notifyAll();		}		//设置线程的优先级别		Process.setThreadPriority(mPriority);		//这里默认是空方法的实现,我们可以重写这个方法来做一些线程开始之前的准备,方便扩展		onLooperPrepared();		Looper.loop();		mTID = -1;	}		public Looper getLooper() {		if (!isAlive()) {		return null;		}		// 直到线程创建完Looper之后才能获得Looper对象,Looper未创建成功,阻塞		synchronized (this) {			while (isAlive() && mLooper == null) {				try {					wait();				} catch (InterruptedException e) {				}			}		}		return mLooper;	}		public boolean quit() {		Looper looper = getLooper();		if (looper != null) {			looper.quit();			return true;		}		return false;	}		public boolean quitSafely() {		Looper looper = getLooper();		if (looper != null) {			looper.quitSafely();			return true;		}		return false;	}/*** Returns the IDentifIEr of this thread. See Process.myTID().*/	public int getThreadID() {		return mTID;	}}

(1)首先看看构造函数

	public HandlerThread(String name) {		super(name);		mPriority = Process.THREAD_PRIORITY_DEFAulT;	}	public HandlerThread(String name, int priority) {		super(name);		mPriority = priority;	}

一个参数的和两个参数的,name代表当前线程的名称,priority为线程的优先级别

(2)看一下run()方法
在run方法里面我们可以看到我们会初始化一个Looper,并设置线程的优先级别

	public voID run() {		mTID = Process.myTID();		Looper.prepare();		//持有锁机制来获得当前线程的Looper对象		synchronized (this) {			mLooper = Looper.myLooper();			//发出通知,当前线程已经创建mLooper对象成功,这里主要是通知getLooper方法中的wait			notifyAll();		}		//设置线程的优先级别		Process.setThreadPriority(mPriority);		//这里默认是空方法的实现,我们可以重写这个方法来做一些线程开始之前的准备,方便扩展		onLooperPrepared();		Looper.loop();		mTID = -1;	}

前面我们说到使用HandlerThread的时候必须调用 start() 方法,接着才可以将我们的HandlerThread和我们的handler绑定在一起

原因就是我们是在 run() 方法才开始初始化我们的looper,而我们调用HandlerThread的 start() 方法的时候,线程会交给虚拟机调度,由虚拟机自动调用run方法

为什么要使用锁机制和 notifyAll() :

原因我们可以从 getLooper() 方法中知道
	public Looper getLooper() {		if (!isAlive()) {			return null;		}	// 直到线程创建完Looper之后才能获得Looper对象,Looper未创建成功,阻塞	synchronized (this) {		while (isAlive() && mLooper == null) {			try {				wait();			} catch (InterruptedException e) {			}		}	}	return mLooper;}

总结:在获得mLooper对象的时候存在一个同步的问题,只有当线程创建成功并且Looper对象也创建成功之后才能获得mLooper的值。这里等待方法wait和run方法中的notifyAll方法共同完成同步问题。

(3)接着我们来看一下quit方法和quitSafe方法

	public boolean quit() {		Looper looper = getLooper();		if (looper != null) {			looper.quit();			return true;		}		return false;	}		public boolean quitSafely() {		Looper looper = getLooper();		if (looper != null) {			looper.quitSafely();			return true;		}		return false;	}

跟踪这两个方法容易知道只两个方法最终都会调用MessageQueue的 quit(boolean safe) 方法

voID quit(boolean safe) {	if (!mQuitAllowed) {		throw new IllegalStateException("Main thread not allowedto quit.");	}	synchronized (this) {		if (mQuitting) {			return;		}		mQuitting = true;		//安全退出调用这个方法		if (safe) {			removeAllFutureMessagesLocked();		} else {//不安全退出调用这个方法			removeAllMessagesLocked();		}		// We can assume mPtr != 0 because mQuitting was prevIoUsly false.		nativeWake(mPtr);	}}

不安全的会调用 removeAllMessagesLocked(); ,我们来看这个方法是怎样处理的,其实就是遍历Message链表,移除所有信息的回调,并重置为null。

private voID removeAllMessagesLocked() {	Message p = mMessages;	while (p != null) {		Message n = p.next;		p.recycleUnchecked();		p = n;	}	mMessages = null;}

安全地会调用 removeAllFutureMessagesLocked(); 这个方法,它会根据Message.when这个属性,判断我们当前消息队列是否正在处理消息,没有正在处理消息的话,直接移除所有回调,正在处理的话,等待该消息处理处理完毕再退出该循环。因此说 quitSafe() 是安全的,而 quit() 方法是不安全的,因为quit方法不管是否正在处理消息,直接移除所有回调

private voID removeAllFutureMessagesLocked() {	final long Now = SystemClock.uptimeMillis();	Message p = mMessages;	if (p != null) {		//判断当前队列中的消息是否正在处理这个消息,没有的话,直接移除所有回调		if (p.when > Now) {			removeAllMessagesLocked();		} else {			//正在处理的话,等待该消息处理处理完毕再退出该循环			Message n;			for (;;) {				n = p.next;				if (n == null) {					return;				}				if (n.when > Now) {					break;				}				p = n;			}			p.next = null;			do {				p = n;				n = p.next;				p.recycleUnchecked();			} while (n != null);		}	}}
总结

以上是内存溢出为你收集整理的Android——HandlerThread浅析全部内容,希望文章能够帮你解决Android——HandlerThread浅析所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/999500.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-21
下一篇2022-05-21

发表评论

登录后才能评论

评论列表(0条)

    保存