android 下的多线程
来源:互联网 发布:js 获取div display 编辑:程序博客网 时间:2024/05/20 14:24
方法有许多,下面我们一一来讲:
第一种:用两个Handler。
为什么要两个?一个发起线程,一个处理消息,发起线程必须要有Looper,为何?没有Looper如何把消息加入到MessageQueue中去呢。为何处理线程又不需要Looper呢?因为他有默认的,也就是主线程的Looper。
OK,如何获取到发起线程的Looper,通过HandlerThread,看代码:
Handler handler;HandlerThread handlerT= new HandlerThread("test");handlerT.start();handler = new Handler(handlerT.getLooper());
然后,我们在handler的post中做我们的耗时处理(这里以请求一张图片为例),看代码:
void byHandler(final String url){ handler.post(new Runnable() { @Override public void run() { Log.i("byHandler", Thread.currentThread().getName()); Drawable drawable = null; try { drawable = Drawable.createFromStream(new URL(url).openStream(), "image.png"); } catch (Exception e) { e.printStackTrace(); } } }); }
到此,我们就把我们的耗时操作完成了,接下来就该更新UI了,但是不能在非UI线程外更新UI呀,OK,我们再用一个Handler来处理这个问题,这个Handler必须要用UI线程的Looper,能把我们的消息(处理结果)放入到主线程的MessageQueue中去。这个简单吧,构造一个无参的Handler就OK了。看代码:
Handler mainHandler = new Handler(){ public void handleMessage(Message msg) { super.handleMessage(msg); };};
OK啦,最后就是把handler中的处理结果,作为一个消息发送到mainHandler中进行处理就行了,完整的代码如下:
public class MultiThreadActivity extends Activity { Handler handler; ImageView image; Handler mainHandler = new Handler() { public void handleMessage(Message msg) { super.handleMessage(msg); if (msg.what == 2016) { image.setImageDrawable((Drawable) msg.obj); } }; }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.multi_thread_layout); image = (ImageView) findViewById(R.id.image_1); HandlerThread handlerT = new HandlerThread("test"); handlerT.start(); handler = new Handler(handlerT.getLooper()); } void byHandler(final String url) { handler.post(new Runnable() { @Override public void run() { Log.i("byHandler", Thread.currentThread().getName()); Drawable drawable = null; try { drawable = Drawable.createFromStream(new URL(url).openStream(), "image.png"); } catch (Exception e) { e.printStackTrace(); } Message msg = mainHandler.obtainMessage(); msg.what = 2016; msg.obj = drawable; msg.sendToTarget(); } }); }}
其实这种方法相对麻烦,用两个Handler,绕来绕去,容易绕晕,下面就来看第二种只需要一个Handler的方法。
第二种:直接创建一个线程并启动
这种方法就很好理解了,开启一个线程,做耗时操作,操作完成后,通过Message发送一个消息给主线程,直接看代码:
public class MultiThreadActivity extends Activity { ImageView image; Handler mainHandler = new Handler() { public void handleMessage(Message msg) { super.handleMessage(msg); if (msg.what == 2016) { image.setImageDrawable((Drawable) msg.obj); } }; }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.multi_thread_layout); image = (ImageView) findViewById(R.id.image_1); } void byThread(final String url){ new Thread(new Runnable(){ @Override public void run() { Log.i("byThread", Thread.currentThread().getName()); Drawable drawable = null; try { drawable = Drawable.createFromStream(new URL(url).openStream(), "image.png"); } catch (Exception e) { e.printStackTrace(); } Message msg = mainHandler.obtainMessage(); msg.what = 2016; msg.obj = drawable; msg.sendToTarget(); } }).start(); }}
相信这个大部分人都会的,下面看第三种
第三种:AsyncTask
这种方法比较简单,直接继承AsyncTask类,实现一些方法就OK,看代码,我在注释中解释相关内容:
先写一个内部类
/*** 第一个参数,是需要传入到doInBackground中的值* 第二个参数,是数据更新值* 第三个参数,是返回的结果值* */class DownloadTask extends AsyncTask<String,Integer,Drawable>{/*** 该方法就是用来做耗时操作的*/@Overrideprotected Drawable doInBackground(String... params) { Log.i("当前线程:", ""+Thread.currentThread().getName()); Drawable drawable = null; try { drawable = Drawable.createFromStream(new URL(params[0]).openStream(), "image.png"); } catch (Exception e) { e.printStackTrace(); } return drawable;}/*** 可以在此方法中对我们的UI进行更新 */@Overrideprotected void onPostExecute(Drawable result) { super.onPostExecute(result); image.setImageDrawable(result);}@Overrideprotected void onProgressUpdate(Integer... values) { super.onProgressUpdate(values);}@Overrideprotected void onPreExecute() { super.onPreExecute();} }
相信这个大家也是比较容易明白的,估计也是大家经常用到的。
第四种:ExecutorService线程池
ExecutorService有两种用来实现多线程的方法:
1:固定数量的线程,Executors.newFixedThreadPool(nThreads);
2:动态数量的线程,Executors.newCachedThreadPool();
创建ExecutorService对象,然后调用sumbit(r)的方法提交,下面看代码:
public class MultiThreadActivity extends Activity { ImageView image; ExecutorService service = Executors.newFixedThreadPool(5); Handler mainHandler = new Handler(){ public void handleMessage(Message msg) { super.handleMessage(msg); }; }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.multi_thread_layout); image = (ImageView) findViewById(R.id.image_1); } void byExecutor(final String url){ service .submit(new Runnable(){ @Override public void run() { try { final Drawable drawable = Drawable.createFromStream(new URL(url).openStream(), "image.png"); mainHandler.post(new Runnable(){ @Override public void run() { image.setImageDrawable(drawable); } }); } catch (Exception e) { e.printStackTrace(); } } }); }}
关于线程池
为何要引入线程池?
首先来说一下线程池的原理,当线程池的对象被创建出来以后,我们通常会设定一个最大线程数,里面的所有线程,都是处于睡眠状态,只有在用到的时候才会呗唤醒,工作完成之后,线程继续睡眠。而单起线程,创建-工作-销毁,并发量少,这个OK,但是并发量稍微一大,这个过程就需要消耗大量的内存资源和时间。所以就引入了线程池这个东西,说白了,就是重复利用资源。
关于线程间的通信
其实在上面已经讲了,从代码中我们也能看出来,线程间的通信,就是通过Handler 和 Looper来进行的。方法一和方法二,都可以看成是很好的线程间通信的例子。
最后,我们来讲一下关于线程的知识
什么是线程?它本质上就是一些命令或者说代码片段,我们需要做的事情就是把它发送给操作系统去执行。
一般来说,我们的CPU在任何时候一个核只能处理一个线程。多核处理自然可以同时处理多线程。
但在实际过程中,单核也是可以处理多线程的,因为可以通过模拟的方式来执行多线程。
- Android下的多线程
- Android下的多线程
- Android下的多线程
- Android下的多线程
- Android下的多线程
- Android下的多线程
- Android下的多线程
- Android下的多线程
- Android下的多线程
- Android下的多线程
- Android下的多线程
- Android下的多线程
- Android下的多线程
- android 下的多线程
- (转)Android下的多线程
- android 下的多线程(转)
- Android下的多线程通信机制
- java多线程和android平台下的多线程
- LeetCode 47 - Permutations II
- find:paths must precede expression问题及解决
- 深入理解Java的接口和抽象类
- 病毒基础-混沌内存沙盘演
- Android Training学习笔记——RecyclerView和CardView
- android 下的多线程
- Android 播放提示音
- PAT (Advanced Level) Practise 1016 Phone Bills (25)
- 【VS开发】文件共享内存2
- NSOperationQueue与GCD的使用原则和场景
- 深入理解C++中的mutable关键字
- CME-M5系列(一)——简介
- java中的 二分查找
- SPOJ QTREE Query on a tree [树链剖分+线段树]