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在任何时候一个核只能处理一个线程。多核处理自然可以同时处理多线程。
  但在实际过程中,单核也是可以处理多线程的,因为可以通过模拟的方式来执行多线程。

0 0
原创粉丝点击