记录Android异步加载的学习(线程池、信号量、图片压缩、Looper)

来源:互联网 发布:旅行物品 品牌 知乎 编辑:程序博客网 时间:2024/05/06 05:33

本文说是原创的,其实是看了各路大神的博客后记录下自己的理解,以便于以后开发的时候可以用得到。
首先感谢鸿洋_大神的文章Android 框架练成 教你打造高效的图片加载框架 ,要了解异步加载框架的可以去看这篇文章。

在这篇文章中学到了很多,也把以前比较模糊的地方重新整理了一下,这次主要是梳理一下知识点。

1.关于线程池(Executors)

记得刚做项目的时候,异步加载基本全是用AsyncTask,有多少就任务就有多少AsyncTask,以前不知道,现在才知道这样做的坏处,后来接触到线程池,管理线程,方便很多,资源得到很好地利用。
关于线程池的详细用法网上有很多文章写得很好,这里我推荐雨松MOMO的Android研究院之应用开发线程池的经典使用 ,感谢大神们的无私奉献。

创建线程池:

 Executors.newSingleThreadExecutor();// 每次只执行一个线程任务的线程池 Executors.newFixedThreadPool(count);// 限制线程池大小为count的线程池 Executors.newCachedThreadPool(); // 一个没有限制最大线程数的线程池,对线程进行缓存复用 Executors.newScheduledThreadPool(3);// 一个可以按指定时间可周期性的执行的线程池 Executors.newFixedThreadPool(3, new MyThreadFactory());// 按指定工厂模式来执行的线程池 threadpool.execute(Runnable r);//加入一条线程 Future<String> f=threadpool.submit(Runnable r);//这种方式加入可以得到返回值

2.关于信号量(Semaphore)

信号量是在多线程环境下使用, 它负责协调各个线程, 以保证它们能够正确、合理的使用公共资源。我理解的和锁很类似。
参考文章,老紫竹JAVA提高教程-信号量(Semaphore)在生产者和消费者模式的使用

在java中,还可以设置该信号量是否采用公平模式,如果以公平方式执行,则线程将会按到达的顺序(FIFO)执行,如果是非公平,则可以后请求的有可能排在队列的头部。
JDK中定义如下:

Semaphore(int permits, boolean fair)

 创建具有给定的许可数和给定的公平设置的Semaphore。

3.图片压缩

压缩图片最重要的就是设置options.inJustDecodeBounds = true;在得到inSampleSize 后在设置生false(一定要记住,否则渠道的bitmap会空),

 // 获得图片的宽和高,并不把图片加载到内存中BitmapFactory.Options options = new BitmapFactory.Options();options.inJustDecodeBounds = true;BitmapFactory.decodeFile(path, options);options.inSampleSize =size;   //一个合适的大小 // 使用获得到的InSampleSize再次解析图片options.inJustDecodeBounds = false;Bitmap bitmap = BitmapFactory.decodeFile(path, options);

4.Looper

looper这玩意儿我看了好久问了很多大神也没彻底搞明白。

创建的线程默认是没有消息循环和消息队列的,如果想让该线程具有消息队列和消息循环,需要在线程中首先调用Looper.prepare()来创建消息队列,然后调用Looper.loop()进入消息循环。

Message:消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,终由Handler处理。
Handler:处理者,负责Message的发送及处理。使用Handler时,需要实现handleMessage(Message msg)方法来对特定的Message进行处理,例如更新UI等。

MessageQueue:消息队列,用来存放Handler发送过来的消息,并按照FIFO规则执行。当然,存放Message并非实际意义的保存,而是将Message以链表的方式串联起来的,等待Looper的抽取。

Looper:消息泵,不断地从MessageQueue中抽取Message执行。因此,一个MessageQueue需要一个Looper。

Thread:线程,负责调度整个消息循环,即消息循环的执行场所。

class LooperThread extends Thread {      public Handler mHandler;      public void run() {          Looper.prepare();          mHandler = new Handler() {              public void handleMessage(Message msg) {                  // process incoming messages here              }          };          Looper.loop();      }  }

上面的代码里加了Looper,那么这个线程就可以循环处理消息了。

@Override    public void onClick(View v) {        switch (v.getId()) {        case R.id.start_looper:            sendMessage();            break;        default:            break;        }    }    private void sendMessage() {        if (UIhandler == null) {            try {                notEmpty.acquire();            } catch (InterruptedException e) {                e.printStackTrace();            }        }        UIhandler.sendEmptyMessage(0);    }    private void backThread() {        Thread thread = new Thread() {            @Override            public void run() {                Looper.prepare();                UIhandler = new Handler() {                    @Override                    public void handleMessage(Message msg) {                        super.handleMessage(msg);                        Log.i(TAG, "i:" + i++);                    }                };                notEmpty.release();                Looper.loop(); //不加这句只有在第一次点击按钮的时候UIhandler会处理消息,即没有循环处理消息            }        };        thread.start();    }

上面的代码是我写的一个例子,便于自己理解,效果就是点击一次按钮Log就会打印一次,如果没有执行Looper.loop()方法,那么就不会一直从消息队列取消息。

android的Activity也是一个消息轮询线程,有消息队列和消息循环。

0 0
原创粉丝点击