android的handle
‘壹’ android 线程可以有几个handle
android.os.Handler Handler在android里负责发送和处理消息。它的主要用途有: 1)按计划发送消息或执行某个Runnanble(使用POST方法); 2)从其他线程中发送来的消息放入消息队列中,避免线程冲突(常见于更新UI线程) 默认情况下,Handler接受的是当前线程下的消息循环实例(使用Handler(Looper looper)、Handler(Looper looper, Handler.Callback callback)可以指定线程),同时一个消息队列可以被当前线程中的多个对象进行分发、处理(在UI线程中,系统已经有一个Activity来处理了,你可以再起若干个Handler来处理)。在实例化Handler的时候,Looper可以是任意线程的,只要有Handler的指针,任何线程也都可以sendMessage。Handler对于Message的处理不是并发的。一个Looper 只有处理完一条Message才会读取下一条,所以消息的处理是阻塞形式的(handleMessage()方法里不应该有耗时操作,可以将耗时操作放在其他线程执行,操作完后发送Message(通过sendMessges方法),然后由handleMessage()更新UI)。 android中Handle类的用法 当我们在处理下载或是其他需要长时间执行的任务时,如果直接把处理函数放Activity的OnCreate或是OnStart中,会导致执行过程中整个Activity无响应,如果时间过长,程序还会挂掉。Handler就是把这些功能放到一个单独的线程里执行,与Activity互不影响。 当用户点击一个按钮时如果执行的是一个常耗时操作的话,处理不好会导致系统假死,用户体验很差,而Android则更进一步,如果任意一个Acitivity没有响应5秒钟以上就会被强制关闭,因此我们需要另外起动一个线程来处理长耗时操作,而主线程则不受其影响,在耗时操作完结发送消息给主线程,主线程再做相应处理。那么线程之间的消息传递和异步处理用的就是Handler。 加群讨论研究 QQ群:56839077
‘贰’ android 创建了handle 在别的地方怎么获取到handle对象
这个问题应该算是java的基础吧,在别的地方这是个可见性的问题。同一个类中:
classTest{
Handleh;
publicTest(){
h=newHandler();
}
}
全局变量,在Test中都是可用的。
不同的类中,Android中自带一个Application全局变量:
{
publicHandlerh;
}
//然后在你创建的地方将这个handler赋值给application中的
((MyApplication)getApplication()).h=this.h;
//于是你可以再其他地方拿到这个handler了
((MyApplication)getApplication()).h.sendxxxx
当然了,你可能在《app研发录》中看到过不要把奇奇怪怪的东西放到Application中这个说法,我也同意,不过你可以将handler传过去,咋传根据你的需求来,大概的思路就跟Application里差不多,拿到一个对象调用public方法设置Handler。
‘叁’ android怎么区分handler
重写handler 的一个方法 handleMessage(android.os.Message msg)
通过handler.sendMessage(msg)发送一个消息过来他就会接收到
通过msg的what值区分消息
例如:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Message msg = new Message();
msg.what = 1;
handler.sendMessage(msg);
}
private Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
if(msg.what == 1) {
Toast.makeText(MainActivity.this, "收到消息一", 1).show();
}else if (msg.what == 2) {
Toast.makeText(MainActivity.this, "收到消息二", 1).show();
}
}
};
‘肆’ android中handle在内部类中为什么不执行
当Android应用启动的时候,会先创建一个应用主线程的Looper对象,Looper实现了一个简单的消息队列,一个一个的处理里面的Message对象。主线程Looper对象在整个应用生命周期中存在。
当在主线程中初始化Handler时,该Handler和Looper的消息队列关联。发送到消息队列的Message会引用发送该消息的Handler对象,这样系统可以调用 Handler#handleMessage(Message) 来分发处理该消息。
在Java中,非静态(匿名)内部类会引用外部类对象。而静态内部类不会引用外部类对象。
如果外部类是Activity,则会引起Activity泄露 。
当Activity finish后,延时消息会继续存在主线程消息队列中1分钟,然后处理消息。而该消息引用了Activity的Handler对象,然后这个Handler又引用了这个Activity。这些引用对象会保持到该消息被处理完,这样就导致该Activity对象无法被回收,从而导致了上面说的 Activity泄露。
要修改该问题,只需要按照Lint提示的那样,把Handler类定义为静态即可,然后通过WeakReference 来保持外部的Activity对象。
‘伍’ Android中Handler的主要作用是什么通俗点,初学。
Handler的使用主要是android中无法在主线程(即UI线程)中访问网络、无法在子线程中访问UI线程元素。
一般是在子线程中访问网络,然后使用Handler发送message通知主线程处理UI更新操作
‘陆’ 如何生动形象的理解Android Handler消息处理机制
在一个Android 程序开始运行的时候,会单独启动一个Process。默认的情况下,所有这个程序中的Activity,Service,Content Provider,Broadcast Receiver(Android 4大组件)都会跑在这个Process。一个Android 程序默认情况下也只有一个Process,但一个Process下却可以有许多个Thread。在这么多Thread当中,有一个Thread,称之为UI Thread。UI Thread在Android程序运行的时候就被创建,是一个Process当中的主线程Main Thread,主要是负责控制UI界面的显示、更新和控件交互。在Android程序创建之初,一个Process呈现的是单线程模型,所有的任务都在一个线程中运行。因此,UI Thread所执行的每一个函数,所花费的时间都应该是越短越好。而其他比较费时的工作(访问网络,下载数据,查询数据库等),都应该交由子线程去执行,以免阻塞主线程,导致ANR。那么问题来了,UI 主线程和子线程是怎么通信的呢。这就要提到这里要讲的Handler机制。
简单来说,handler机制被引入的目的就是为了实现线程间通信的。handler一共干了两件事:在子线程中发出message,在主线程中获取、处理message。听起来好像so easy,如果面试中让阐述下Handler机制,这么回答显然不是面试官想要的答案。忽略了一个最重要的问题:子线程何时发送message,主线程何时获取处理message。
为了能让主线程“适时”得处理子线程所发送的message,显然只能通过回调的方式来实现——开发者只要重写Handler类中处理消息的方法,当子线程发送消时,Handler类中处理消息的方法就会被自动回调。
Handler类包含如下方法用于发送处理消息
void handleMessage(Message msg):处理消息的方法,该方法通常用于被重写。
final boolean hasMessage(int what):检查消息队列中是否包含what属性为指定值的消息。
final boolean hasMessage(int what,Object object):检查消息队列中是否包含what属性为指定值且object属性为指定对象的消息。
sendEmptyMessage(int what)发送空消息。
sendEmptyMessageDelayed(int what,longdelayMillis);指定多少毫秒之后发送空消息。
sendMessage(Message msg)立即发送消息。
sendMessageDelayed(int what,longdelayMillis);指定多少毫秒之后发送消息。
借助以上方法,就可以自由穿梭于主线程和子线程之中了。
到这里就结束了么?当然没有。要讲的东西才刚刚开始,要知道消息处理这件事,不是handler一个人在战斗,android的消息处理有三个核心类:Handler,Looper,和Message。其实还有一个MessageQueue(消息队列),但是Message Queue被封装到Looper里面了,不会直接与Message Queue打交道。
Looper的字面意思是“循环装置”,它被设计用来使一个普通线程变成Looper线程。所谓Looper线程就是循环工作的线程。在程序开发中,经常会需要一个线程不断循环,一旦有新任务则执行,执行完继续等待下一个任务,这就是Looper线程。Looper是用于给一个线程添加一个消息队列(MessageQueue),并且循环等待,当有消息时会唤起线程来处理消息的一个工具,直到线程结束为止。通常情况下不会用到Looper,因为对于Activity,Service等系统组件,Frameworks已经为初始化好了线程(俗称的UI线程或主线程),在其内含有一个Looper,和由Looper创建的消息队列,所以主线程会一直运行,处理用户事件,直到某些事件(BACK)退出。
如果,需要新建一个线程,并且这个线程要能够循环处理其他线程发来的消息事件,或者需要长期与其他线程进行复杂的交互,这时就需要用到Looper来给线程建立消息队列。
使用Looper也非常的简单,它的方法比较少,最主要的有四个:
public static prepare();为线程初始化消息队列。
public static myLooper();获取此Looper对象的引用
public static loop();让线程的消息队列开始运行,可以接收消息了。
public void quit();退出具体哪个Looper
在整个消息处理机制中,message又叫task,封装了任务携带的信息和处理该任务的handler,这个很好理解,就不做介绍了。
说了这么多,一定没听太明白。没关系,再对Handler运行机制做个总结:
子线程(无looper)借用主线程(有looper)里的Hander发送一条message到主线程,这个message会被主线程放入message queue,主线程里面有一个looper,在轮询message queue的时候发现有一条message。调用handler消息处理者,执行handlemessage方法,去处理这个message,就可以在handlemessage的方法里面更新ui。好像画面感不是太强,举个例子吧。试想有一个生产方便面的车间,这个车间有两条生产线,一条是生产面饼的,一条是生产调料包的,面饼的生产线比较先进一点,配备了一个工人叫handler,还配备了一个调料包分类循环器。这个车间能生产很多种方便面,有老坛酸菜,有泡椒凤爪,有香菇炖鸡,有红烧牛肉等等。其中方便面的面饼都是一样的,只有调料包和包装袋不一样,包装袋是根据调料包来定的。那么生产线运作起来了:工人Handler把子生产线(子线程)上的调料包(message)放到了主生产线(主线程)上的调料包分类循环器(Looper)上,通过轮询分类筛选后工人Handler确定这是一包合格的老坛酸菜味调料包,于是工人把老坛酸菜调料包和面饼放在一块(sendmessage),告诉主生产线,这是一包老坛酸菜方便面,请给这包方便面包一个老坛酸菜的包装袋(更新UI).
‘柒’ Android的handler机制的原理
Android的handler机制的原理分为异步通信准备,消息发送,消息循环,消息处理。
1、异步通信准备
在主线程中创建处理器对象(Looper)、消息队列对象(Message Queue)和Handler对象。
2、消息入队
工作线程通过Handler发送消息(Message) 到消息队列(Message Queue)中。
3、消息循环
消息出队: Looper循环取出消息队列(Message Queue) 中的的消息(Message)。
消息分发: Looper将取出的消息 (Message) 发送给创建该消息的处理者(Handler)。
4、消息处理
处理者(Handler) 接收处理器(Looper) 发送过来的消息(Message),根据消息(Message) 进行U操作。
handler的作用
handler是android线程之间的消息机制,主要的作用是将一个任务切换到指定的线程中去执行,(准确的说是切换到构成handler的looper所在的线程中去出处理)android系统中的一个例子就是主线程中的所有操作都是通过主线程中的handler去处理的。
Handler的运行需要底层的 messagequeue和 looper做支撑。
‘捌’ android中handle和线程的关系是什么
作者:李板溪
链接:http://www.hu.com/question/24766848/answer/53037579
来源:知乎
着作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
问题背景,假设你要下载一张美女图显示出来。 使用这个问题就可以说明主要的问题了。
好了 上代码,下载美女图片,然后显示在 ImageView 中。 代码如下:
public class MainActivity extends AppCompatActivity {
public static final String beautyUrl = "http://ww3.sinaimg.cn/large/.jpg";
ImageView mBeautyImageView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mBeautyImageView = (ImageView)findViewById(R.id.beauty);
mBeautyImageView.setImageBitmap(downloadImage(beautyUrl));
}
@Nullable
public Bitmap downloadImage(String urlString){
try {
final URL url = new URL(urlString);
try(InputStream is = url.openStream()){
return BitmapFactory.decodeStream(is);
}
} catch (IOException e) {
e.printStackTrace();
return null;
}
}
}
然后这样的一段看似没有问题的代码,在 Android 3 以上是会直接报错的。 主要错误原因在
Caused by: android.os.NetworkOnMainThreadException at android.os.StrictMode$AndroidBlockGuardPolicy.onNetwork(StrictMode.java:1147)
为了保证用户体验, Android 在 3.0 之后,就不允许在 主线程(MainThread)即 UI线程 中执行网络请求了。 那怎么办呢?
好吧,我们暂不考试 Android 提供的一系统组件及工具类, 用纯 Java 的方式来解决这个问题。
在新的线程中下载显示图片
在新创建的线程中下载显示图片如下:
new Thread(new Runnable() {
@Override
public void run() {
mBeautyImageView.setImageBitmap(downloadImage(beautyUrl));
}
}).start();
看起来来错的样子,跑起来看看。 啊,又报错了。
android.view.ViewRootImpl$: Only the original thread that created a view hierarchy can touch its views.
说只能在创建View 层级结构的线程中修改它。 创建它的线程就是主线程。 在别的线程不能修改。 那怎么办?
那现在我们遇到的问题是: 下载不能在主线程下载。 更新ImageView 一定要在 主线程中进行。 在这样的限制下,我们自然而然想去一个解决办法: 就是在新创建的线程中下载。 下载完成在主线程中更新 ImageView。
但是,怎么在下载完成之后,将图片传递给主线程呢?这就是我们问题的关键了。
线程间通信
我们的通信要求,当下载线程中下载完成时,通知主线程下载已经完成,请在主线程中设置图片。 纯 Java 的实现上面的线程间通信的办法我暂没有找到,于是我想到使用 FutureTask 来实现在主线程中等待图片下载完成,然后再设置。
FutureTask<Bitmap> bitmapFutureTask = new FutureTask<>(new Callable<Bitmap>() {
@Override
public Bitmap call() throws Exception {
return downloadImage(beautyUrl);
}
});
new Thread(bitmapFutureTask).start();
try {
Bitmap bitmap = bitmapFutureTask.get();
mBeautyImageView.setImageBitmap(bitmap);
} catch (InterruptedException |ExecutionException e) {
e.printStackTrace();
}
不过这虽然骗过了 Android 系统,但是虽然系统阻塞的现象没有解决。 例如我在 get() 方法前后设置了输出语句:
Log.i(TAG,"Waiting Bitmap");
Bitmap bitmap = bitmapFutureTask.get();
Log.i(TAG,"Finished download Bitmap");
设置了下载时间至少 5 秒钟之后,输出如下:
06-27 23:30:18.058 21298-21298/com.banxi1988.androiditc I/MainActivity﹕ Waiting Bitmap 06-27 23:30:23.393 21298-21298/com.banxi1988.androiditc I/MainActivity﹕ Finished download Bitmap
让主线程什么事做不做,就在那傻等了半天。然后由于 onCreate没有返回。用户也就还没有看到界面。 导致说应用半天启动不了。。卡死了。。
查阅了一些资料,没有不用 Android 的框架层的东西而实现在其他进程执行指定代码的。
而 Android 中线程间通信就得用到 android.os.Handler 类了。 每一个 Handler 都与一个线程相关联。 而 Handler 的主要功能之一便是: 在另一个线程上安插一个需要执行的任务。
这样我的问题就通过一个 Handler 来解决了。
于是 onCreate 中的相关代码变成如下了:
final Handler mainThreadHandler = new Handler();
new Thread(new Runnable() {
@Override
public void run() {
final Bitmap bitmap = downloadImage(beautyUrl);
mainThreadHandler.post(new Runnable() {
@Override
public void run() {
mBeautyImageView.setImageBitmap(bitmap);
}
});
}
}).start();
看起来很酷的样子嘛,一层套一层的 Runnable. mainThreadHandler 因为是在 主线程中创建的, 而 Handler创建时,绑定到当前线程。 所以 mainThreadHandler 绑定到主线程中了。
当然 Android 为了方便你在向主线程中安排进操作,在 Activity类中提供了 runOnUiThread 方法。 于是上面的代码简化为:
new Thread(new Runnable() {
@Override
public void run() {
final Bitmap bitmap = downloadImage(beautyUrl);
runOnUiThread(new Runnable() {
@Override
public void run() {
mBeautyImageView.setImageBitmap(bitmap);
}
});
}
}).start();
你不用自己创建一个 Handler了。
而 runOnUiThread 的具体实现,也跟我们做得差不多。UI线程即主线程。
public final void runOnUiThread(Runnable action) {
if (Thread.currentThread() != mUiThread) {
mHandler.post(action);
} else {
action.run();
}
}
Handler 与 Loop 简介
上面说到 每一个 Handler 都与一个线程相绑定。 实际上是,通过 Handler 与 Loop 绑定,而每一个 Loop 都与一个线程想绑定的。 比如 Handler 中两个主要构造函数大概如下:
public Handler(...){
mLooper = Looper.myLooper();
// ...
}
public Handler(Looper looper,...){
mLooper = looper;
// ...
}
public static Looper myLooper() {
return sThreadLocal.get();
}
然后 Looper 的构造函数如下:
private Looper(boolean quitAllowed) {
mQueue = new MessageQueue(quitAllowed);
mThread = Thread.currentThread();
}
绑定了当前的线程和生成了一个消息队列。
值得提起的一点是, Looper 类保持了对 应用的主线程的 Looper 对象的静态应用。
private static Looper sMainLooper; // guarded by Looper.class
public static Looper getMainLooper() {
synchronized (Looper.class) {
return sMainLooper;
}
}
这样就可以方便你在其他线程中,使用一个绑定到主线程的 Handler,从而方便向主线程安插任务。 例如一般的图片处理库即是如此。这样你只要指定一个 图片的 url,及要更新的ImageView 即可。 如 Picasso 库可以用如下代码的读取并更新图片。 Picasso.with(context).load(url).into(imageView);
然后 Handler 可以做的事情还有很多。 因为它后面有 Looper 有 MessageQueue。可以深入了解下。
谈一下线程池与 AsyncTask 类
Android 早期便有这个便利的类来让我们方便的处理 工作线程及主线程的交互及通信。 但是现在先思考一下,我们上面的代码可能遇到的问题。 比如,我们现在要显示一个图片列表。 一百多张图片。 如果每下载一张就开一个线程的话,那一百多个线程,那系统资源估计支持不住。特别是低端的手机。
正确的做法是使用一个线程池。
final ExecutorService executor = Executors.newCachedThreadPool();
executor.execute(new Runnable() {
@Override
public void run() {
final Bitmap bitmap = downloadImage(beautyUrl);
runOnUiThread(new Runnable() {
@Override
public void run() {
mBeautyImageView.setImageBitmap(bitmap);
}
});
executor.shutdown();
}
});
由于我们是在在一个局部方法中使用了一个线程池。所以处理完了之后应该将线程停止掉。 而我们上面只有一个线程,所以直接在下载完成之后,调用 executor停掉线程池。 那如果执行了多个图片的下载请求。需要怎么做呢? 那就要等他们都完成时,再停止掉线程池。 不过这样用一次就停一次还是挺浪费资源的。不过我们可以自己保持一个应用级的线程池。 不过这就麻烦不少。
然后 Android 早已经帮我们想法了这一点了。 我们直接使用 AsyncTask 类即可。
于是我们下载图片并显示图片的代码如下:
new AsyncTask<String,Void,Bitmap>(){
@Override
protected Bitmap doInBackground(String... params) {
return downloadImage(params[0]);
}
@Override
protected void onPostExecute(Bitmap bitmap) {
mBeautyImageView.setImageBitmap(bitmap);
}
}.execute(beautyUrl);
相比之前的代码简洁不少。
看一下 AsyncTask 的源代码,正是集合我们之前考虑的这些东西。
一个全局的线程池
public static final Executor THREAD_POOL_EXECUTOR
= new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE,
TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
一个绑定主线程的 Handler ,在线程中处理传递的消息
private static class InternalHandler extends Handler {
public InternalHandler() {
super(Looper.getMainLooper());
}
@SuppressWarnings({"unchecked", "RawUseOfParameterizedType"})
@Override
public void handleMessage(Message msg) {
AsyncTaskResult<?> result = (AsyncTaskResult<?>) msg.obj;
switch (msg.what) {
case MESSAGE_POST_RESULT:
// There is only one result
result.mTask.finish(result.mData[0]);
break;
case MESSAGE_POST_PROGRESS:
result.mTask.onProgressUpdate(result.mData);
break;
}
}
}
小结
Android 提供的 Looper 和 Handler 可以让我们非常方便的在各线程中安排可执行的任务