图片缓存和显示能力 -- Picasso

一、基本使用

//添加依赖(build.gradle)
implementation 'com.squareup.picasso:picasso:2.5.2'

//添加网络权限(AndroidManifest.xml)


//加载网络图片(MainActivity)
public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        String url = "http://img1.imgtn.bdimg.com/it/u=1447234934,94659509&fm=26&gp=0.jpg";
        ImageView imageView = findViewById(R.id.imageview);
        Picasso.with(this)
                .load(url)
                .into(imageView);
    }
}

//加载Uri路径的图片(MainActivity)
public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        ImageView imageView = findViewById(R.id.imageview);
        Uri uri = Uri.parse("android.resource://" + getPackageName() + "/" + R.mipmap.ic_launcher);
        Picasso.with(this)
                .load(uri)
                .into(imageView);
    }
}

//加载本地资源图片(MainActivity)
public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        ImageView imageView = findViewById(R.id.imageview);
        Picasso.with(this)
                .load(R.mipmap.ic_launcher)
                .into(imageView);
    }
}

//加载File中的图片(MainActivity)
public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        String path = getExternalCacheDir().getAbsoluteFile() + File.separator + "ic_launcher.png";
        Log.d(TAG, "zwm, path: " + path);
        File file = new File(path);
        ImageView imageView = findViewById(R.id.imageview);
        Picasso.with(this)
                .load(file)
                .into(imageView);
    }
}

二、placeholder & error & noPlaceholder & noFade

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        String url = "http://img1.imgtn.bdimg.com/it/u=1447234934,94659509&fm=26&gp=0.jpg";
        ImageView imageView = findViewById(R.id.imageview);
        Picasso.with(this)
                .load(url)
                .placeholder(R.mipmap.ic_launcher) //占位图
                //.noPlaceholder() //不显示占位图
                .error(R.mipmap.ic_launcher_round) //加载出错时显示的图片
                .noFade() //不显示渐入效果
                .into(imageView);
    }
}

三、Resize(设置图片尺寸) & Scale(缩放) & Crop(裁剪)

resize(int targetWidth, int targetHeight),以px为单位

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        String url = "http://img1.imgtn.bdimg.com/it/u=1447234934,94659509&fm=26&gp=0.jpg";
        ImageView imageView = findViewById(R.id.imageview);
        Picasso.with(this)
                .load(url)
                .placeholder(R.mipmap.ic_launcher) //占位图
                .resize(200,200)
                .into(imageView);
    }
}

resizeDimen(int targetWidthResId, int targetHeightResId),以dp为单位

//dimens.xml

    200dp
    200dp


//MainActivity
public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        String url = "http://img1.imgtn.bdimg.com/it/u=1447234934,94659509&fm=26&gp=0.jpg";
        ImageView imageView = findViewById(R.id.imageview);
        Picasso.with(this)
                .load(url)
                .placeholder(R.mipmap.ic_launcher) //占位图
                .resizeDimen(R.dimen.image_width, R.dimen.image_height)
                .into(imageView);
    }
}

onlyScaleDown()

当调用resize方法重新设置图片尺寸,并调用了onlyScaleDown方法,只有当原始图片的尺寸大于我们指定的尺寸时,resize才起作用。

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        String url = "http://img1.imgtn.bdimg.com/it/u=1447234934,94659509&fm=26&gp=0.jpg";
        ImageView imageView = findViewById(R.id.imageview);
        Picasso.with(this)
                .load(url)
                .placeholder(R.mipmap.ic_launcher) //占位图
                .resize(200,200)
                .onlyScaleDown()
                .into(imageView);
    }
}

centerCrop()

充满View边界,居中裁剪。

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        String url = "http://img1.imgtn.bdimg.com/it/u=1447234934,94659509&fm=26&gp=0.jpg";
        ImageView imageView = findViewById(R.id.imageview);
        Picasso.with(this)
                .load(url)
                .placeholder(R.mipmap.ic_launcher) //占位图
                .resize(200,200)
                .centerCrop()
                .into(imageView);
    }
}

centerInside()

centerCrop是可能看不到全部图片的,如果想让View将图片完全展示,可以用centerInside。但是如果图片尺寸小于View尺寸的话,是不能充满View边界的。

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        String url = "http://img1.imgtn.bdimg.com/it/u=1447234934,94659509&fm=26&gp=0.jpg";
        ImageView imageView = findViewById(R.id.imageview);
        Picasso.with(this)
                .load(url)
                .placeholder(R.mipmap.ic_launcher) //占位图
                .resize(200,200)
                .centerInside()
                .into(imageView);
    }
}

fit()

充满View边界,有可能会出现拉伸扭曲的情况。

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        String url = "http://img1.imgtn.bdimg.com/it/u=1447234934,94659509&fm=26&gp=0.jpg";
        ImageView imageView = findViewById(R.id.imageview);
        Picasso.with(this)
                .load(url)
                .placeholder(R.mipmap.ic_launcher) //占位图
                .fit()
                .into(imageView);
    }
}

四、Rotate(旋转)

rotate(float degrees)

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        String url = "http://img1.imgtn.bdimg.com/it/u=1447234934,94659509&fm=26&gp=0.jpg";
        ImageView imageView = findViewById(R.id.imageview);
        Picasso.with(this)
                .load(url)
                .placeholder(R.mipmap.ic_launcher) //占位图
                .rotate(180)
                .into(imageView);
    }
}

rotate(float degrees, float pivotX, float pivotY)

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        String url = "http://img1.imgtn.bdimg.com/it/u=1447234934,94659509&fm=26&gp=0.jpg";
        ImageView imageView = findViewById(R.id.imageview);
        Picasso.with(this)
                .load(url)
                .placeholder(R.mipmap.ic_launcher) //占位图
                .rotate(90, 200, 100)
                .into(imageView);
    }
}

五、Transformation(转换器)

Transformation是Picasso的一个非常强大的功能,它允许在加载图片的过程中对图片做一系列的变换,如高斯模糊、添加圆角、度灰处理、圆形图片等。

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        String url = "http://img1.imgtn.bdimg.com/it/u=1447234934,94659509&fm=26&gp=0.jpg";
        ImageView imageView = findViewById(R.id.imageview);
        Picasso.with(this)
                .load(url)
                .placeholder(R.mipmap.ic_launcher) //占位图
                .transform(new BlurTransformation(this))
                .transform(new GrayTransformation())
                .into(imageView);
    }

    //高斯模糊
    private static class BlurTransformation implements Transformation {
        RenderScript rs;

        public BlurTransformation(Context context) {
            super();
            rs = RenderScript.create(context);
        }

        @Override
        public Bitmap transform(Bitmap bitmap) {
            // Create another bitmap that will hold the results of the filter.
            Bitmap blurredBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);

            // Allocate memory for Renderscript to work with
            Allocation input = Allocation.createFromBitmap(rs, blurredBitmap, Allocation.MipmapControl.MIPMAP_FULL, Allocation.USAGE_SHARED);
            Allocation output = Allocation.createTyped(rs, input.getType());

            // Load up an instance of the specific script that we want to use.
            ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
            script.setInput(input);

            // Set the blur radius
            script.setRadius(25);

            // Start the ScriptIntrinisicBlur
            script.forEach(output);

            // Copy the output to the blurred bitmap
            output.copyTo(blurredBitmap);

            bitmap.recycle();

            return blurredBitmap;
        }

        @Override
        public String key() {
            return "blur";
        }
    }

    //度灰
    private static class GrayTransformation implements Transformation{

        @Override
        public Bitmap transform(Bitmap source) {
            int width, height;
            height = source.getHeight();
            width = source.getWidth();

            Bitmap bmpGrayscale = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
            Canvas c = new Canvas(bmpGrayscale);
            Paint paint = new Paint();
            ColorMatrix cm = new ColorMatrix();
            cm.setSaturation(0);
            ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
            paint.setColorFilter(f);
            c.drawBitmap(source, 0, 0, paint);

            if(source!=null && source!=bmpGrayscale){
                source.recycle();
            }
            return bmpGrayscale;
        }

        @Override
        public String key() {
            return "gray";
        }
    }
}

或者:

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        String url = "http://img1.imgtn.bdimg.com/it/u=1447234934,94659509&fm=26&gp=0.jpg";
        ImageView imageView = findViewById(R.id.imageview);
        List transformations = new ArrayList<>();
        transformations.add(new GrayTransformation());
        transformations.add(new BlurTransformation(this));
        Picasso.with(this)
                .load(url)
                .placeholder(R.mipmap.ic_launcher) //占位图
                .transform(transformations)
                .into(imageView);
    }

    //高斯模糊
    private static class BlurTransformation implements Transformation {
        RenderScript rs;

        public BlurTransformation(Context context) {
            super();
            rs = RenderScript.create(context);
        }

        @Override
        public Bitmap transform(Bitmap bitmap) {
            // Create another bitmap that will hold the results of the filter.
            Bitmap blurredBitmap = bitmap.copy(Bitmap.Config.ARGB_8888, true);

            // Allocate memory for Renderscript to work with
            Allocation input = Allocation.createFromBitmap(rs, blurredBitmap, Allocation.MipmapControl.MIPMAP_FULL, Allocation.USAGE_SHARED);
            Allocation output = Allocation.createTyped(rs, input.getType());

            // Load up an instance of the specific script that we want to use.
            ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs));
            script.setInput(input);

            // Set the blur radius
            script.setRadius(25);

            // Start the ScriptIntrinisicBlur
            script.forEach(output);

            // Copy the output to the blurred bitmap
            output.copyTo(blurredBitmap);

            bitmap.recycle();

            return blurredBitmap;
        }

        @Override
        public String key() {
            return "blur";
        }
    }

    //度灰
    private static class GrayTransformation implements Transformation{

        @Override
        public Bitmap transform(Bitmap source) {
            int width, height;
            height = source.getHeight();
            width = source.getWidth();

            Bitmap bmpGrayscale = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565);
            Canvas c = new Canvas(bmpGrayscale);
            Paint paint = new Paint();
            ColorMatrix cm = new ColorMatrix();
            cm.setSaturation(0);
            ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
            paint.setColorFilter(f);
            c.drawBitmap(source, 0, 0, paint);

            if(source!=null && source!=bmpGrayscale){
                source.recycle();
            }
            return bmpGrayscale;
        }

        @Override
        public String key() {
            return "gray";
        }
    }
}

六、请求优先级

Picasso为请求设置有优先级,有三种优先级:LOW、NORMAL、HIGH,默认情况下都是NORMAL,但是fetch方法除外,fetch方法的优先级是LOW。
可以通过priority方法设置请求的优先级,这会影响请求的执行顺序,但是这是不能保证的,它只会往高的优先级靠拢。

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        String url = "http://img1.imgtn.bdimg.com/it/u=1447234934,94659509&fm=26&gp=0.jpg";
        ImageView imageView = findViewById(R.id.imageview);
        Picasso.with(this)
                .load(url)
                .placeholder(R.mipmap.ic_launcher)
                .priority(Picasso.Priority.HIGH)
                .into(imageView);
    }
}

七、Tag管理请求

Picasso#

  • cancelTag(Object tag):取消设置了给定tag的所有请求。
  • pauseTag(Object tag):暂停设置了给定tag的所有请求。
  • resumeTag(Object tag):resume被暂停的给定tag的所有请求。

RequestCreator#

  • tag(Object tag):为请求设置tag。
public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        String url = "http://img1.imgtn.bdimg.com/it/u=1447234934,94659509&fm=26&gp=0.jpg";
        ImageView imageView = findViewById(R.id.imageview);
        Picasso.with(this)
                .load(url)
                .placeholder(R.mipmap.ic_launcher)
                .tag("PhotoTag")
                .into(imageView);
    }
}

使用场景1:快速滑动列表时暂停请求

//Adapter
Picasso.with(this).load(mData.get(position))
        .placeholder(R.drawable.default_bg)
        .error(R.drawable.error_iamge)
        .tag("PhotoTag")
        .into(holder.mImageView);

//Activity
mRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
    @Override
    public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
        final Picasso picasso = Picasso.with(MainActivity.this);

        if (newState == SCROLL_STATE_IDLE) {
            picasso.resumeTag("PhotoTag");
        } else {
            picasso.pauseTag("PhotoTag");
        }
    }
});

使用场景2:退出界面取消请求

@Override
protected void onDestroy() {
    super.onDestroy();
    Picasso.with(this).cancelTag("PhotoTag");
}

八、同步/异步加载图片

同步:

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        final String url = "http://img1.imgtn.bdimg.com/it/u=1447234934,94659509&fm=26&gp=0.jpg";

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Bitmap bitmap = Picasso.with(MainActivity.this).load(url).get();
                    Log.d(TAG, "zwm, bitmap: " + bitmap);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }
}

异步:

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        String url = "http://img1.imgtn.bdimg.com/it/u=1447234934,94659509&fm=26&gp=0.jpg";
        //Picasso.with(MainActivity.this).load(url).fetch();
        Picasso.with(MainActivity.this).load(url).fetch(new Callback() {
            @Override
            public void onSuccess() {
                Log.d(TAG, "zwm, onSuccess");
            }

            @Override
            public void onError() {
                Log.d(TAG, "zwm, onError");
            }
        });
    }
}

九、缓存

内存缓存是使用LRU策略的缓存实现,它的大小是内存大小的15%。磁盘缓存的大小是磁盘容量的2%,并且不超过50M、不少于5M。
处理一个请求时,按照顺序检查:memory -> disk -> network。
默认情况下,Picasso内存缓存和磁盘缓存都是开启了的,但是有些时候,我们并不需要缓存,比如加载一张大图片的时候,如果在内存中保存一份,很容易造成OOM,这时候我们只希望有磁盘缓存,而不希望缓存到内存,因此就需要我们设置缓存策略了。

设置内存缓存策略:

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        ImageView imageView = findViewById(R.id.imageview);
        String url = "http://img1.imgtn.bdimg.com/it/u=1447234934,94659509&fm=26&gp=0.jpg";
        Picasso.with(MainActivity.this)
                .load(url)
                .memoryPolicy(MemoryPolicy.NO_CACHE, MemoryPolicy.NO_STORE)
                .into(imageView);
    }
}

设置磁盘缓存策略:

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "zwm, onCreate");
        ImageView imageView = findViewById(R.id.imageview);
        String url = "http://img1.imgtn.bdimg.com/it/u=1447234934,94659509&fm=26&gp=0.jpg";
        Picasso.with(MainActivity.this)
                .load(url)
                .networkPolicy(NetworkPolicy.NO_CACHE, NetworkPolicy.NO_STORE) //注意:NetworkPolicy.NO_STORE只对OkHttp有效
                //.networkPolicy(NetworkPolicy.OFFLINE) //只从缓存获取结果,不发起网络请求
                .into(imageView);
    }
}

十、Debug和日志

缓存指示器:
在图片的左上角出现一个带色块的三角形标示,有3种颜色,绿色表示从内存加载、蓝色表示从磁盘加载、红色表示从网络加载。

Picasso.with(this).setIndicatorsEnabled(true);

日志:
Picasso可以打印一些日志,比如一些关键方法的执行时间等。

Picasso.with(this).setLoggingEnabled(true);

十一、Picasso扩展

  • 用Builder自己构造一个Picasso实例。
  • 配置自定义下载器DownLoader。
  • 配置缓存。
  • 配置线程池。
  • 配置全局的Picasso实例。
//Application
@Override
public void onCreate() {
    super.onCreate();
    
    //配置全局的Picasso实例
    Picasso.Builder builder = new Picasso.Builder(this);
    //配置下载器
    builder.downloader(new CustomDownloader());
    //配置缓存
    LruCache cache = new LruCache(5*1024*1024); //设置缓存大小
    builder.memoryCache(cache);
    //配置线程池
    ExecutorService executorService = Executors.newFixedThreadPool(8);
    builder.executor(executorService);

    //构造一个Picasso
    Picasso picasso = builder.build();
    //设置全局的Picasso实例
    Picasso.setSingletonInstance(picasso);
}

//Activity
Picasso.with(MainActivity.this)
        .load(url)
        .into(imageView);

十二、源码解析

Picasso源码解析

你可能感兴趣的:(图片缓存和显示能力 -- Picasso)