【Android图片加载框架】制作自己的图片加载框架(一)

图片框架是在Android开发上占据了很重要的位置,我们常用的有Gilde,picasso,Fresco等,在功能上,这些框架已经基本满足我们的开发需求,在此不多讲它们的操作原理,现在我们开始学习自制一个网络图片加载框架

在做之前,我们先了解一下线程池的操作流程


  线程池的特点:
  1)提升性能。创建和消耗对象费时费CPU资源
  2)防止内存过度消耗。控制活动线程的数量,防止并发线程过多。
  使用条件:
     假设在一台服务器完成一项任务的时间为T
     T1 创建线程的时间    
     T2 在线程中执行任务的时间,包括线程间同步所需时间    
     T3 线程销毁的时间     
     显然T = T1+T2+T3。注意这是一个极度简化的假设。
     可以看出T1,T3是多线程本身的带来的开销,我们渴望减少T1,T3所用的时间,从而减少T的时间。但一些线程的使用者并没有注意到这一点,所以在程序中频繁的创建或销毁线程,这导致T1和T3在T中占有相当比例。显然这是突出了线程的弱点(T1,T3),而不是优点(并发性)。
     线程池技术正是关注如何缩短或调整T1,T3时间的技术,从而提高服务器程序性能的。它把T1,T3分别安排在服务器程序的启动和结束的时间段或者一些空闲的时间段,这样在服务器程序处理客户请求时,不会有T1,T3的开销了。
     线程池不仅调整T1,T3产生的时间段,而且它还显著减少了创建线程的数目。

     在Android中当同时并发多个网络线程时,引入线程池技术会极大地提高APP的性能。


下面以一实例做介绍:

1.ImageTask

注:此处的sleep 只是为了测试效果,下同,没有别的用意

try{
            Thread.sleep(1000);
        }catch (Exception e){
            e.printStackTrace();
        }

package com.example.officer.yycimageloader.tools;

import android.app.Application;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.AsyncTask;
import android.provider.MediaStore;
import android.support.v4.util.LruCache;
import android.util.Log;

import com.example.officer.yycimageloader.MainActivity;

import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * Created by officer on 2015/12/15.
 */
public class ImageTask implements Runnable{
    /**
     * 图片任务
     */
    //缓存存放图片
    private LruCache<String, Bitmap> mLruCache;

    public static final String TAG=ImageTask.class.getSimpleName();
    String name;
    Context mContext;
    public ImageTask(String name,Context context){
        this.name=name;
        int maxMemory = (int) Runtime.getRuntime().maxMemory();
        int cacheSize = maxMemory / 8;
        mLruCache = new LruCache<String, Bitmap>(cacheSize);
        mContext=context;
    }
    @Override
    public void run() {
//        // 读取uri所在的图片
//        try {
//            Uri uri=Uri.parse(name);
//            Bitmap bitmap = MediaStore.Images.Media.
//                    getBitmap(mContext.getContentResolver(), uri);
//            mLruCache.put("bit",bitmap);
//        }catch (Exception e){
//            e.printStackTrace();
//        }
        try{
            Thread.sleep(1000);
        }catch (Exception e){
            e.printStackTrace();
        }

        Log.v(TAG,name+"  完成加载");
    }



    public String getName(){
        return this.name;
    }


}
2.ImageTaskManager
package com.example.officer.yycimageloader.tools;

import android.util.Log;

import java.util.HashSet;
import java.util.LinkedList;
import java.util.Set;

/**
 * Created by officer on 2015/12/15.
 */
public class ImageTaskManager {
    /**
     * 图片任务管理
     */
    public static final String TAG=ImageTaskManager.class.getSimpleName();
    //请求线程队列
    private LinkedList<ImageTask> imageTasks;
    //任务不能重复
    private Set<String> taskIdSet;

    private static ImageTaskManager imageTaskManager;

    public static synchronized ImageTaskManager getInstance(){
        if (null == imageTaskManager) {
            imageTaskManager = new ImageTaskManager();
        }
        return imageTaskManager;
    }

    private ImageTaskManager() {
        imageTasks = new LinkedList<ImageTask>();
        taskIdSet = new HashSet<String>();
    }

    public void addImageTask(ImageTask downloadTask){
        synchronized (imageTasks) {
            if (!isTaskRepeat(downloadTask.getName())) {
                imageTasks.addLast(downloadTask);
            }
        }
    }

    public boolean isTaskRepeat(String fileId) {
        synchronized (taskIdSet) {
            if (taskIdSet.contains(fileId)) {
                return true;
            } else {
               Log.v(TAG,"任务管理  添加任务" + fileId);
                taskIdSet.add(fileId);
                return false;
            }
        }
    }

    public ImageTask getImageTask() {
        synchronized (imageTasks) {//强制同步
            if (imageTasks.size() > 0) {
                Log.v(TAG,"任务管理   " + "取出任务");
                ImageTask imageTask = imageTasks.removeFirst();//先进先出,取出顶部的任务
                return imageTask;
            }
        }
        return null;
    }
}
3.ImageTaskManagerThread

package com.example.officer.yycimageloader.tools;

import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * Created by officer on 2015/12/15.
 */
public class ImageTaskManagerThread implements Runnable{
    /**
     * 线程池
     */

    private ImageTaskManager imageTaskManager;
    private ExecutorService pool;//可重用固定线程数的线程池
    private final int SIZE=10;//线程数
    private final int SLEEP=1000;//轮询时间
    private boolean isStop=false;

    public ImageTaskManagerThread(){
        this.imageTaskManager=ImageTaskManager.getInstance();//获得实例
        pool= Executors.newFixedThreadPool(SIZE);
    }
    @Override
    public void run() {
        while(!isStop){
            ImageTask imageTask=imageTaskManager.getImageTask();
            if(imageTask!=null){
                pool.execute(imageTask);
            }else{
                try{
                    Thread.sleep(SLEEP);
                }catch (Exception e){
                    e.printStackTrace();
                }
            }
        }
        if(isStop){//关闭线程池
            pool.shutdown();
        }
    }

    public void setStop(boolean isStop){
        this.isStop=isStop;
    }
}

运行的MainActivity

package com.example.officer.yycimageloader;

import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;

import com.example.officer.yycimageloader.tools.ImageTask;
import com.example.officer.yycimageloader.tools.ImageTaskManager;
import com.example.officer.yycimageloader.tools.ImageTaskManagerThread;
import com.example.officer.yycimageloader.tools.ImageUtil;
import com.example.officer.yycimageloader.tools.SearchImage;

import java.io.File;
import java.util.List;


public class MainActivity extends ActionBarActivity {

    Button btn;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btn=(Button)findViewById(R.id.btn);
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
              //  test_pool();
                synchronized (this) {
                   // test_find();
                    test_pool();
                }
            }
        });
    }

    private void test_find(){
        SearchImage s=new SearchImage(this);
    }


    /**
     * 线程池
     */
    private void  test_pool(){
        ImageTaskManager imageTaskManager=ImageTaskManager.getInstance();
        ImageTaskManagerThread imageTaskManagerThread=new ImageTaskManagerThread();
        new Thread(imageTaskManagerThread).start();

//        File f= ImageUtil.getDirName();
//        List<String> list=ImageUtil.getPicName();

        String []items={"图1"
                ,"图2",
                "图3",
                "图4",
                "图5",
                "图6"};

        for(int i=0;i<items.length;i++){
            imageTaskManager.addImageTask(new ImageTask(items[i],this));//添加任务进线程池
                try{
                Thread.sleep(1000);
            }catch (Exception e){
                e.printStackTrace();
            }
        }
    }



    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

如上:

我们将  图1至图6放入任务队列中,下面是打印出的结果:

【Android图片加载框架】制作自己的图片加载框架(一)_第1张图片

那么回到我们的主线,继续写图片加载框架。

我们常常遇到的问题是:

用户的快速操作,必须保证浏览图片的流畅。

设想一个应用场景:

用户浏览某网络资源相册,在GridView中呈现图片,用户快速滑动至底部,如果完全按照顺序来加载的话,会是怎么一个情景呢?例如1000张图片,是不是要苦等几分钟?这显然是不行的。

我们可以这么做:

用户每时每刻都只是浏览部分(即屏幕停留的地方),那么已滑过或者未滑到的位置就没必要加载。

这是一个比较直接有效的思路。





你可能感兴趣的:(android,线程池,安卓,图片加载框架)