Picasso 상세 설명, 완벽 호 환 OkHttp 3.3, 캐 시 최적화, https 지원

Tamic 모 바 일 개발 에 전념!관심http://www.jianshu.com/p/6241950f9daf csdn: http://blog.csdn.net/sk719887916/article/details/52852148
왜 Fresco, Glide 가 이렇게 강 한 배경 에서 나 는 그때 의 Picasso 가 생각 났 고 왜 이 글 을 썼 을 까?최근 프로젝트 는 square 회사 의 RxAndroid, Retrfit 과 OKhttp 를 사 용 했 기 때문에 이 회사 가 Picasso 를 불 러 올 사진 이 있 었 다 는 것 을 생각 할 수 밖 에 없 었 다. 그래서 square 회사 의 온 가족 통 으로 프로젝트 개발 을 진행 했다. 개발 원 가 를 줄 이 고 APK 의 증 가 를 방지 하기 위해 한 회사 의 구조 이전에 호환성 은 걱정 하지 않 아 도 된다.그러면 피 카 스 의 길 을 돌아 보 겠 습 니 다.
우선 주류 이미지 로드 라 이브 러 리 부터 보 여 주세요.
  • Picasso, Square 의 오픈 소스 프로젝트 는 Square 의 네트워크 라 이브 러 리 와 함께 가장 큰 역할 을 발휘 할 수 있다.메모리 사용량 이 적 고 캐 시 를 가지 고 있 지 않 습 니 다. OKhttps 에 의존 하여 캐 시 를 실행 해 야 합 니 다. gif 그림 은 지원 되 지 않 습 니 다
  • Fresco, FB 의 스타 프로젝트 이자 2015 년 에 가장 핫 한 프로젝트 중 하나 이다. 익명 공유 캐 시 등 체 제 는 저급 기기 의 표현 이 매우 좋 지만 소스 코드 는 C / C + + 를 바탕 으로 읽 기 어려움 이 높 아 졌 다.효율 이 높 고 sdk 라 이브 러 리 점용 패키지 의 부피 가 비교적 크다
  • Glide, Google 직원 의 개인 프로젝트 입 니 다. 그러나 Google 은 많은 프로젝트 를 사용 하고 있 습 니 다. 메모리 사용량 이 적 고 oom 을 낮 추 는 것 이 더 믿 을 수 있 습 니 다. Picasso 에 비해 Gif 에 유리 하고 캐 시 기능 을 가지 고 있 습 니 다!

  • 나 는 일반 listview 로 50 장의 그림 을 불 러 오고 빠 른 미끄럼 목록 을 만 들 었 다. 다음은 glide 와 picasso 소모 메모리 그림 이다.
    glide Picasso 详解,完美兼容 OkHttp3.3,缓存优化,支持https_第1张图片
    Picasso Picasso 详解,完美兼容 OkHttp3.3,缓存优化,支持https_第2张图片
  • 분석 한 결과 하나의 사용 메모리 가 cpu 자원 을 차지 하 는 것 이 크다 는 것 을 알 수 있 습 니 다. 이러한 차 이 는 picasso 가 큰 그림 만 캐 시 하고 매번 로드 할 때마다 imagview 의 크기 에 따라 자 르 기 때문에 소모 되 는 cpu 자원 이 높 습 니 다. glide 는 각각 다른 사이즈 의 작은 그림 을 저장 하고 매번 계산 하지 않 기 때문에 메모리 소모 가 비교적 많 고 로드 속도 가 Picasso 에 비해 빠 르 지만 데이터 소모 도 많 습 니 다.
  • OOM 을 피하 기 위해 저 는 메모리 소모 가 적은 picasso 를 선 택 했 습 니 다. Fresco 는 로드 속도 1 위 프레임 워 크 라 고 할 필요 가 없습니다. c 라 이브 러 리 를 사용 합 니 다. 저 는 통합 테스트 를 하지 않 았 습 니 다. 구체 적 으로 cpu 자원 을 얼마나 소모 하 는 지 데 이 터 를 제시 할 수 없습니다. 업계 1 위 라 고 합 니 다. 하지만 apk 크기 에 대한 요구 가 적당 하지 않 을 수 있 습 니 다. 여 기 는 Apk 패키지 의 부피 가 높 지 않 은 프로젝트 에 대한 우선 순위 입 니 다.

  • glide 를 좋아 하 는 친 구 는 이 글 을 볼 수 있 습 니 다.http://mrfu.me/2016/02/27/Glide_Getting_Started/
    실험 테스트 를 하고 간단 한 비 교 를 한 후에 왜 Picasso 를 계속 말 해 야 합 니까? 그 가 얼마나 유창 한 지 는 말 하지 않 습 니 다. 다만 square 회사 의 다른 오픈 소스 프로젝트 를 사용 하면 그들 은 모두 okhttp 에 의존 하 는 것 을 발견 할 수 있 습 니 다. okhttp 의 강 함 은 말 할 필요 도 없습니다. 오늘 은 piacsso 와 관련 된 것 만 소개 하고 picasso (공식:https://github.com/square/picasso) 자주 사용 하 는 기술!
    Picasso
    \ # 사용 방법:
    gradle 설정
    dependencies {
    c
    compile 'com.squareup.picasso:picasso:2.5.2'
    compile 'com.squareup.okhttp3:okhttp:3.3.1'
    compile 'com.squareup.okhttp3:logging-interceptor:3.3.1'
    }
    

    현재 2.5.3 은 2.52 에서 okhttp 3 를 호 환 할 수 없 는 문 제 를 복 구 했 지만 저 는 2.52 버 전 을 선 택 했 습 니 다.
    기본 로드 방법
    Picasso.with(getApplication())
    .load(url)
    .into(imageView);
    

    이상 의 용법 은 매우 간단 합 니 다. 그림 을 불 러 올 때 url 을 imageview 에 삽입 하면 됩 니 다. picasso 의 다른 강력 한 기능 이 아직 많이 이해 되 지 않 은 학생 들 은 Follow Me!
    그림 을 재단 하 다
     Picasso.with(getApplication()).resize(width, height);
    

    이 방법 은 bug, 오용!
    Transformation 으로 전의 실현:
           Picasso.with(getApplication())
            .load(url)
            .transform(new PaTransformation(width, height)).into(imageView);
    

    Transformation 은 picasoo 가 돌아 오 는 bitmap 를 차단 하고 bitmap 을 들 고 마음대로 할 수 있 습 니 다!
    public class TamicTransformation implements Transformation {
    
    private int width;
    private int height;
    private String key;
    
    public PaTransformation(int width, int height) {
        this(width, height,  width + "*" + height);
    }
    
    public PaTransformation(int width, int height, String key) {
        this.width = width;
        this.height = height;
        this.key = key;
    }
    
    @Override
    public Bitmap transform(Bitmap source) {
    
           source        
    
    
        if (result != source) {
            // Same bitmap is returned if sizes are the same
            source.recycle();
        }
        return result;
    }
    
    @Override
    public String key() {
    
        return key;
    }
    

    }
    원형 두상 처리
     public class CircleTransformation implements Transformation {   
     private static final int STROKE_WIDTH = 5;  
    
     @Override   
     public Bitmap transform(Bitmap source) {   
       int size = Math.min(source.getWidth(), source.getHeight());   
       int x = (source.getWidth() - size) / 2; 
       int y = (source.getHeight() - size) / 2;  
    
       Bitmap squaredBitmap = Bitmap.createBitmap(source, x, y, size, size);  
       if (squaredBitmap != source) { 
            source.recycle();   
       } 
       Bitmap bitmap = Bitmap.createBitmap(size, size,source.getConfig()); 
       Canvas canvas = new Canvas(bitmap); 
       Paint avatarPaint = new Paint();  
       BitmapShader shader = new BitmapShader(squaredBitmap, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP);avatarPaint.setShader(shader);  
    
       Paint outlinePaint = new Paint();
       outlinePaint.setColor(Color.WHITE);
       outlinePaint.setStyle(Paint.Style.STROKE);
       outlinePaint.setStrokeWidth(STROKE_WIDTH);
       outlinePaint.setAntiAlias(true);
    
       float r = size / 2f;  
       canvas.drawCircle(r, r, r, avatarPaint); 
       canvas.drawCircle(r, r, r - STROKE_WIDTH / 2, outlinePaint);
    
       squaredBitmap.recycle();
       return bitmap;  
      }
    
      @Override  
      public String key() { 
       return "circle)";
      }
    }
    

    이어서 렌 더 링 모드 설정
               Picasso.with(getApplication()) .fit().centerCrop()
    

    캐 시 비우 기
    새로운 버 전 2.52 는 이전의 cache 를 직접 가 져 올 수 없 기 때문에 Picasso. invalidate () 로 캐 시 를 선명 하 게 할 수 있 습 니 다!
    예전 에 우 리 는 이렇게 할 수 있 었 다.
     Clear.clearCache(Picasso.with(context));
    

    근 데 지금 은 안 돼 요.
    약간 봉 하여 이렇게 만 들 었 다.
    void clearCache(Uri uri, File file, String path) {
    
    if (!TextUtils.isEmpty(uri.toString())) {
    mPicasso.invalidate(uri);
    return;
    }
    if (!NullUtils.isNull(file)) {
    mPicasso.invalidate(file);
    return;
    }
    if (!TextUtils.isEmpty(path)) {
    mPicasso.invalidate(path);
    }
    }
    

    물론 그 럴 수도 있 지!
      Picasso.with(getContext()).load(Url).memoryPolicy(MemoryPolicy.NO_CACHE).into(image);
    

    그림 을 불 러 올 때 캐 시 를 하지 못 하 게 합 니 다!
    캐 시 추가
    물론 2.5.2 oKhttp 3.3 에 대한 호 환 을 하지 않 았 기 때문에 저 희 는 사용자 정의 cilent 를 추가 하여 okhttp 에 캐 시 맞 춤 형 을 만 들 었 습 니 다. 아래 자세 로 하 십시오.
    OkHttpClient 구축
        // creat the OkHttpClient.
        OkHttpClient client =new OkHttpClient
                .Builder()
                .cache(new Cache("      ", 1000*1024))
                .addInterceptor(new CaheInterceptor(context, null))
                .addNetworkInterceptor(new CaheInterceptor(context, null))
                .build();
    

    차단기 인 터 셉 터
    차단기 가 낯 설 지 않 습 니 다. 특히 okhttp 와 retofit 를 해 본 친구 들 은 http 의 차단 요청 과 응답 을 차단 한 것 이 분명 합 니 다.
    public class CaheInterceptor implements Interceptor {
    
    private Context context;
    public CaheInterceptor(@NonNull Context context) {
        this.context = context;
    }
    
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        if (NetworkUtil.isNetworkAvailable(context)) {
            Response response = chain.proceed(request);
            // read from cache for 60 s
            int maxAge = 300;
            String cacheControl = request.cacheControl().toString();
            Log.e("Tamic", maxAge+ "s load cahe:" + cacheControl);
            return response.newBuilder()
                    .removeHeader("Pragma")
                    .removeHeader("Cache-Control")
                    .header("Cache-Control", "public, max-age=" + maxAge)
                    .build();
        } else {
            Log.e("Tamic", " no network load cahe");
            request = request.newBuilder()
                    .cacheControl(CacheControl.FORCE_CACHE)
                    .build();
            Response response = chain.proceed(request);
            //set cahe times is 3 days
            int maxStale = 60 * 60 * 24 * 3;
            return response.newBuilder()
                    .removeHeader("Pragma")
                    .removeHeader("Cache-Control")
                    .header("Cache-Control", "public, only-if-cached, max-stale=" + maxStale)
                    .build();
        }
    }
    

    }
    Picasso 에 추가
        // Generate the global default Picasso instance.
      Picasso   mPicasso = getPicasso(context, null);
        mPicasso.setLoggingEnabled(true);
    
    }
    

    사용자 정의 Downloader
    okhttp 3.31 호 환 을 위해 다운로드 기 를 실현 합 니 다!
     public class ImageDownLoader implements Downloader {
    OkHttpClient client = null;
    
    public ImageDownLoader(OkHttpClient client) {
        this.client = client;
    }
    
    @Override
    public Response load(Uri uri, int networkPolicy) throws IOException {
    
        CacheControl cacheControl = null;
        if (networkPolicy != 0) {
            if (NetworkPolicy.isOfflineOnly(networkPolicy)) {
                cacheControl = CacheControl.FORCE_CACHE;
            } else {
                CacheControl.Builder builder = new CacheControl.Builder();
                if (!NetworkPolicy.shouldReadFromDiskCache(networkPolicy)) {
                    builder.noCache();
                }
                if (!NetworkPolicy.shouldWriteToDiskCache(networkPolicy)) {
                    builder.noStore();
                }
                cacheControl = builder.build();
            }
        }
    
        Request.Builder builder = new Request.Builder().url(uri.toString());
        if (cacheControl != null) {
            builder.cacheControl(cacheControl);
        }
    
        okhttp3.Response response = client.newCall(builder.build()).execute();
        int responseCode = response.code();
        if (responseCode >= 300) {
            response.body().close();
            throw new ResponseException(responseCode + " " + response.message(), networkPolicy,
                    responseCode);
        }
    
        boolean fromCache = response.cacheResponse() != null;
    
        ResponseBody responseBody = response.body();
        return new Response(responseBody.byteStream(), fromCache, responseBody.contentLength());
    
    }
    
    @Override
    public void shutdown() {
    
        Cache cache = client.cache();
        if (cache != null) {
            try {
                cache.close();
            } catch (IOException ignored) {
            }
        }
    }
    

    }
    이 어 ImageDownloader 를 Picasso / * * 에 추가 하여 Big Image only, Not singleton but shared cache * / public Picasso getPicasso (Context context) {OkHttpClient client = getProgressBarClient (); return new Picasso. Builder (context). downloader (new ImageDownloader (client). build ();}
    /** * Not singleton */ private OkHttpClient getProgressBarClient() { return client.newBuilder() .addInterceptor(new CaheInterceptor(context)) .addNetworkInterceptor(new CaheInterceptor(contextr)) .build(); }
    이렇게 하면 우리 가 그림 을 불 러 올 때:
      getPicasso(context) .load(Url).into(image)
    

    따라서 Picasso 를 사용 하면 우 리 는 캐 시 정책 을 retrofit 에 직접 사용 할 수 있 습 니 다. 사실은 일거양득 으로 개발 원 가 를 크게 간소화 할 수 있 습 니 다!
    Https 지원 방법
               final OkHttpClient client = new OkHttpClient.Builder()
             .protocols(Collections.singletonList(Protocol.HTTP_1_1))
             .build();
    
             final Picasso picasso = new Picasso.Builder(this)
             .downloader(new Downloader(client))
             .build();
    
            Picasso.setSingletonInstance(picasso);
    

    최적화 관련
    캐 시 되 지 않 는 정책 최적화
            public RequestCreator skipMemoryCache(RequestCreator requestCreator) {
        return requestCreator.memoryPolicy(MemoryPolicy.NO_STORE, MemoryPolicy.NO_CACHE)
                .networkPolicy(NetworkPolicy.NO_STORE, NetworkPolicy.NO_CACHE);
    }
    

    메모리 소 모 를 줄 이 고 RGB 565 인 코딩 형식 을 설정 하여 메모리 소 모 를 줄 입 니 다.
    public RequestCreator cutDownMemory(RequestCreator requestCreator) {
        return requestCreator.config(Bitmap.Config.RGB_565);
    }
    

    불 러 오기 취소
    public class TamicImageView extends ImageView  {
    
    
    
    public TamicImageView(Context context) {
        this(context, null, 0);
    }
    
    public TamicImageView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }
    
    public TamicImageView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    
    }
    
    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
         //       Bitmap
        setImageDrawable(null);
       //     
       mPicasso.pauseTag(this);
    
     }
    }
    

    그리고 많은 api 가 있 습 니 다. 예 를 들 어:
  • requestCreator. tag (tag); 키 설정
  • requestCreator. error (); 불 러 오 는 데 실패 한 그림 설정
  • mPicasso. pauseTag (); 로 딩 일시 정지
  • mPicasso. resumeTag (); 로 딩 복원
  • mPicasso. cancelRequest (); 로 딩 취소
  • requestCreator. priority () 우선 순위
  • requestCreator.. rotate () 회전 같은 거
  • 자주 사용 하 는 api 몇 개 말씀 드 리 겠 습 니 다.
    확장 로드
    물론 알림 표시 줄 에 불 러 온 api 도 있 습 니 다.
    알림 표시 줄 지원
    into(RemoteViews remoteViews, int viewId, int notificationId,Notification notification)
    

    widget 지원
    into(RemoteViews remoteViews, int viewId, int[] appWidgetIds)
    

    첫 번 째 는 원 격 보기, 두 번 째 view Id 세 번 째 는 widget id 배열 입 니 다.
    미리 불 러 오기
    반환 값 이 있 음
     Picasso.with(context).load(url).get()
    

    이 api 는 disk 와 메모리 에 그림 을 미리 불 러 오고 반환 값 Bitmap 이 있 습 니 다. 이 api 는 동기 화 되 어야 합 니 다. UI 메 인 스 레 드 로 호출 할 수 없습니다. 보통 view pager 에서 뒤의 index 그림 을 미리 불 러 오 거나 대상 bitmap 를 미리 가 져 와 서 업무 수행 을 하거나 일부 효과 처 리 를 할 수 있 습 니 다.
    반환 값 없 음
    Picasso.with(context).load(url).fetch()
    

    그림 을 미리 불 러 오 는 기능 도 있 습 니 다. 이 api 는 메 인 스 레 드 에서 호출 할 수 있 습 니 다. 주로 callback 이 실현 되 고 실패 와 성공 함 수 를 상부 에서 호출 할 수 있 습 니 다. 그러나 가 져 올 수 없 는 그림 자원 을 불 러 옵 니 다.
    public static class EmptyCallback implements Callback {
    
    @Override public void onSuccess() {
    }
    
    @Override public void onError() {
    }
      }
    }
    

    불 러 오기 취소
  • cancelRequest(ImageView imageView)
  • cancelTag(Object obj)
  • cancelRequest(Target)

  • 주로 위의 세 가지 방식 으로 첫 번 째 는 알 수 없 는 생각 입 니 다. 바로 특정한 view 의 로 딩 요청 을 취소 하 는 것 입 니 다. 보통 우 리 는 activity 가 사망 할 때 호출 합 니 다. 세 번 째 방법 은 우리 가 지정 한 로 딩 action 을 취소 하 는 것 입 니 다. 예 를 들 어 한 번 로 딩 에 picasso 의 Picasso. with (context). tag () 를 설정 할 때 cancelTag ("tag") 를 사용 할 수 있 습 니 다.지정 한 요청 을 취소 하려 면 마지막 으로 무엇 입 니까? 그 는 태그 의 포장 류 Target 에 가입 하여 리 셋 요청 처 리 를 해 야 합 니 다. 개발 자 상부 에서 취소 절차 에 대한 통 제 를 편리 하 게 해 야 합 니 다.
     mPicasso.cancelRequest(new Target() {
    @Override
    public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom afrom) {
    
    }
    
    @Override
    public void onBitmapFailed(Drawable errorDrawable) {
    
    }
    
    @Override
    public void onPrepareLoad(Drawable placeHolderDrawable) {
    
    }
    });
    

    알림 표시 줄 그림 에 대한 취소 인터페이스 도 있 습 니 다.
         cancelRequest(RemoteViews remoteViews, int viewId)
    

    알림 표시 줄 의 VIEW 는 모두 가 잘 알 고 있 습 니 다. 모두 RemoteViews 로 전환 하여 보 여 줍 니 다. 그러면 cancel 에 게 알 릴 때 이 취소 방법 을 직접 호출 할 수 있 습 니 다.
    후기
    한 마디 로 하면 picasso 가 가장 빠 른 그림 로드 프레임 워 크 는 아니 지만 그 는 기본 적 인 로 컬 과 인터넷 그림 을 로드 하 는 토대 에서 우리 로 하여 금 자신의 확장 능력 을 잘 제공 할 수 있 습 니 다. 그 확장 성과 적응성 이 더욱 강하 고 ohttp + rxJava + Picasso 를 결합 한 후에 그 가 확실히 당신 에 게 적합 하 다 는 것 을 알 게 될 것 입 니 다. 만약 에 glide 를 좋아한다 면 이 완벽 한 글 을 보 세 요: glide 시리즈튜 토리 얼

    좋은 웹페이지 즐겨찾기