android 下的多线程

本文详细介绍了Android应用开发中使用多线程技术的四种常见方法:使用两个Handler、直接创建线程、AsyncTask和ExecutorService线程池。通过实例代码解释了每种方法的工作原理和应用场景,特别强调了线程间通信的重要性以及线程池的作用。文章旨在帮助开发者理解和选择最适合项目需求的多线程解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

方法有许多,下面我们一一来讲:
第一种:用两个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>{

/**
* 该方法就是用来做耗时操作的
*/
@Override
protected 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进行更新
 */
@Override
protected void onPostExecute(Drawable result) {
    super.onPostExecute(result);
    image.setImageDrawable(result);
}

@Override
protected void onProgressUpdate(Integer... values) {
    super.onProgressUpdate(values);
}

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值