Android开发过程中为什么要多线程?
答:我们创建的Service、Activity以及Broadcast均是一个主线程处理,这里我们可以理解为UI线程。但是在操作一些耗时操作时,比如I/O读写的大文件读写,数据库操作以及网络下载需要很长时间,为了不阻塞用户界面,出现ANR的响应提示窗口,这个时候我们可以考虑使用Thread线程来解决。
Android中使用Thread线程会遇到哪些问题?
答:对于Android平台来说UI控件都没有设计成为线程安全类型,所以需要引入一些同步的机制来使其刷新,这点Google在设计Android时倒是参考了下Win32的消息处理机制。
Handler原理:Handler主要接受子线程发送的数据,并用此数据配合主线程更新UI.
当应用程序启动时,Android首先会开启一个主线程 (也就是UI线程) , 主线程为管理界面中的UI控件,进行事件分发,比如说,你要是点击一个 Button ,Android会分发事件到Button上,来响应你的操作。 如果此时需要一个耗时的操作,例如:联网读取数据, 或者读取本地较大的一个文件的时候,你不能把这些操作放在主线程中,,如果你放在主线程中的话,界面会出现假死现象,如果5秒钟还没有完成的话,,会收到Android系统的一个错误提示 "强制关闭". 这个时候我们需要把这些耗时的操作,放在一个子线程中,因为子线程涉及到UI更新,,Android主线程是线程不安全的,也就是说,更新UI只能在主线程中更新,子线程中操作是危险的.这个时候,Handler就出现了,来解决这个复杂的问题, 由于Handler运行在主线程中(UI线程中), 它与子线程可以通过Message对象来传递数据,这个时候,Handler就承担着接受子线程传过来的(子线程用sedMessage()方法传弟)Message对象,(里面包含数据) ,把这些消息放入主线程队列中,配合主线程进行更新UI。
Handler一些特点:handler可以分发Message对象和Runnable对象到主线程中,每个Handler实例,都会绑定到创建他的线程中(一般是位于主线程),它有两个作用: (1)安排消息或Runnable在某个主线程中某个地方执行 (2)安排一个动作在不同的线程中执行
Handler中分发消息的一些方法 post(Runnable) postAtTime(Runnable,long) postDelayed(Runnable long) sendEmptyMessage(int) sendMessage(Message) sendMessageAtTime(Message,long) sendMessageDelayed(Message,long) 以上post类方法允许你排列一个Runnable对象到主线程队列中,sendMessage类方法,允许你安排一个带数据的Message对象到队列中,等待更新.
Handler的用法:
Handler的基本概念 包含线程队列和消息队列,实现异步的消息处理机制,跟web开发的ajax有异曲同工之妙。 创建一个Handler对象 Handler handler = new Handler();
将要执行的操作写在线程对象的run方法当中 Runnable updateThread = new Runnable(){ public void run(){ handler.postDelayed(updateThread,3000); } }
一个点击监听事件,在handler中添加要执行的线程 Class StartButtonListener implements OnClickListener{ public voidonClick(View v){ //调用Handler的post方法,将要执行的线程对象添加到队列中 handler.post(updateThread); } }
一个点击监听事件,在handler中把线程移除 Class EndButtonListerger implements OnClickListener(){ public void onClick(View v){ handler.removeCallBacks(updateThread); } }
使用Handler更新ProgressBar的方法
分别使用:
updateBarHandler.post(updateThread);
updateBarHandler.sendMessage(msg);
传递线程和消息。
通过Handler的handleMessage()方法处理消息。
首先使用匿名内部类来复写Handler当中的handlerMessage方法,该方法用于接收消息 Handler updateBarHandler = new Handler(){ public void handleMessage(Message msg){ bar.setProgress(msg.arg1); updateBarHandler.post(updateThread); } };
创建一个线程类,用于控制进度条的进度,该类使用匿名内部类的方式进行声明 Runnable updateThread = new Runnable(){ int i = 0; public void run(){ i = i + 10; Message msg = updateBarHandle.obtainMessage(); msg.arg1 = i; try{ Thread.sleep(1000); } catch(InterruptedException e) { e.printStackTrack(); } //将msg对象加入到消息队列 updateBarHandler.sendMessage(msg); if( i == 100){ updateBarHandler.removeCallbacks(updateThread); } } }
点击按钮事件,加入队列,启动线程 class ButtonListener implements OnClickListener{ public void onClick(View v){ bar.setVisibility(View.VISIBLE); //线程队列 updateBarHandler.post(updateThread); } }
Handler中使用单独的线程
需要使用public Handler (Looper looper) 构造函数创建Handler对象。从而实现使用Looper来处理消息队列的功能。借助Bundle使用Message传递数据。 当使用 handler.post(new Runnable); 时Handler和Activity处于同一个线程当中,在同一个线程中调用run方法。 而使用 Thread t = new Thread(new Runnable()); t.start(); 创建的线程和Activity处于不同的线程中
Bundle的用法 可以把Bundle看成是特殊的map,所有的key都是String类型的 在新线程当中处理消息的方法 protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //打印当前线程的ID System.out.println(Thread.currentThread().getId()); //生成一个HandlerThread对象,实现了Looper来处理消息队列的功能,这个类由android应用框架提供 HandlerThread handlerThread = new HandlerThread("hanlderThread"); //必须先调用该类的start的方法,否则该获取的Looper对象为NULL handlerThread.start(); MyHanlder myHandler = new MyHandler(handlerThread.getLooper()); Message msg = myHandler.obtainMessage(); Bundle bundle = new Bundle(); bundle.putString("name","arthinking"); msg.setData(b); msg.sendToTarget(); } class MyHandler extends Handler{ public MyHandler(){} public MyHandler(Looper looper){ super(looper); } //每当有消息进入消息队列时就执行这个函数对消息进行操作 public void handleMessage(Message msg){ Bundle bundle = msg.getData(); String name = bundle.getString("name"); System.out.println(Thread.currentThread().getId()); System.out.println(name); } }