show code block

顯示具有 third-party 標籤的文章。 顯示所有文章
顯示具有 third-party 標籤的文章。 顯示所有文章

2017年3月9日 星期四

third-party元件 ─ 網路下載圖片比較和簡易使用Fresco、Picasso 、Glide、ImageLoader

前言:

這幾天遇到OOM問題。
情況大概就是RecyclerView裡面跑大量的ImageView,導致崩潰。
RecyclerView我是寫在Fragment上面的,一開始我以為是因為Fragment沒有做好回收導致重複創建。

後來找到的問題,原來是網路下載圖片(ImageLoader)的方式緩存沒有做到釋放。
我更換了一下我讀取網路上圖片的的第三方,使用了Picasso發現問題就迎刃而解了!!

問了一下大家才發現如果對處理執行緒(Thread)不熟的話,不太推使用ImageLoader,它有一堆Leak的問題。
迷之聲:TMD緩存方式寫得天花亂墜的還不是一堆Leak


Android是比較推薦使用Glide和Picasso。



Glide和Picasso
使用起來其實大同小異。
在這邊大致上介紹一下使用方式:


重點程式碼:
在build.gradle(Module:app)內

Picasso
免不了的import:
compile 'com.squareup.picasso:picasso:2.5.2'

使用方式:
Picasso.with(context)
.load("http://i.imgur.com/DvpvklR.png")
.into(imageView);


Glide
免不了的import:
compile 'com.github.bumptech.glide:glide:3.7.0'

使用方式:
Glide.with(context)
        .load(url)
        .into(imageView);


兩個第三方很像吧,是不是都簡單的不要不要的!


Fresco
而Fresco是facebook自己釋出的圖片下載第三方,你自己一定體驗過facebook它們寫的app雖然用到大量的圖片,但卻不會有卡頓、Crash掉的問題,你就知道Fresco有多麼的強大了!

推薦使用:
Glide > Picasso > Fresco > ImageLoader
當然這是比較主觀的推薦,也須依你當下的需求來使用。
如果圖片量不大,個人覺得Picasso是首選,因為他比較瘦。
當你的App內有大量的圖片需要處理,首選就會是Fresco


我擷取它人一段文章讓你參考:

Picasso所能實現的功能Glide都能做到,只是所需設置不同。兩者的區別是Picasso比Glide體積小很多且圖像質量比Glide高,但Glide的速度比Picasso更快,Glide的長處是處理大型的圖片流,如gif、video,如果要製作視頻類應用,Glide當為首選。
Fresco
可以說是綜合了之前圖片加載庫的優點,其在5.0以下的內存優化非常好,但它的不足是體積太大,按體積進行比較:Fresco>Glide>Picasso,所以Fresco在圖片較多的應用中更能凸顯其價值,如果應用沒有太多圖片需求,不推薦使用Fresco。


文獻:



2017年2月16日 星期四

third-party元件:ImageLoader(網路下載圖片 imageLoader, 封裝)

網路下載圖片 imageLoader

官方檔案:




前言:
In short, 網路上很多資訊,稍微講解一下我覺得重要的部分。
我從網路上抓圖片都使用這一套,防止APP oom的好幫手。
為什麼我要自己拉出來做一個Tools呢?這樣不是脫褲子放屁嗎?
因為在一個專案裡面,你一定會大量的用到某些元件,這時候就可以把你重複用到的原件自己封裝成一包寫進Tools內。
ImageLoader也是常用到的一員,就拉出來自己寫在tools內了。



實作:
在 build.gradle (Module: app) 加上

compile 'com.nostra13.universalimageloader:universal-image-loader:1.9.5'

以下是整個Tools.java

public class Tools {
   private static final String handle = Tools.class.getSimpleName();

   public void imageLoading(Context context, String url, ImageView imageView) {
       ImageLoaderConfiguration config = new ImageLoaderConfiguration
               .Builder(context)
               .memoryCacheExtraOptions(480, 800) //保存每個緩存圖片的最大寬高
               .threadPriority(Thread.NORM_PRIORITY - 2) //線池中的緩存數
               .denyCacheImageMultipleSizesInMemory() //禁止緩存多張圖片
               .memoryCache(new FIFOLimitedMemoryCache(2 * 1024 * 1024))//缓存策略
//                .memoryCacheSize(50 * 1024 * 1024) //設置內存緩存的大小
               .diskCacheFileNameGenerator(new Md5FileNameGenerator()) //缓存文件名的保存方式
//                .diskCacheSize(200 * 1024 * 1024) //緩存大小
               .tasksProcessingOrder(QueueProcessingType.LIFO) //工作序列
               .diskCacheFileCount(200) //緩存的文件數量
               .build();
       if (!ImageLoader.getInstance().isInited()) {//偵測如果imagloader已經init,就不再init
           Log.d(handle, "CheckPoint init");
           ImageLoader.getInstance().init(config);
       }
       ImageLoader.getInstance().displayImage(url, imageView, ImageUsing);

   }
//    UsingFreqLimitedMemoryCache(如果緩存的圖片總量超過限定值,先刪除使用頻率最小的bitmap)
//    LRULimitedMemoryCache(這個也是使用的lru算法,和LruMemoryCache不同的是,他緩存的是bitmap的弱引用)
//    FIFOLimitedMemoryCache(先進先出的緩存策略,當超過設定值,先刪除最先加入緩存的bitmap)
//    LargestLimitedMemoryCache(當超過緩存限定值,先刪除最大的bitmap對象)
//    LimitedAgeMemoryCache(當bitmap加入緩存中的時間超過我們設定的值,將其刪除)

//    Universal-Image-Loader的硬盤緩存策略
//    詳細的硬盤緩存策略可以移步:http://blog.csdn.net/xiaanming/article/details/27525741,下方是總結的結果:

//    FileCountLimitedDiscCache(可以設定緩存圖片的個數,當超過設定值,刪除掉最先加入到硬盤的文件)
//    LimitedAgeDiscCache(設定文件存活的最長時間,當超過這個值,就刪除該文件)
//    TotalSizeLimitedDiscCache(設定緩存bitmap的最大值,當超過這個值,刪除最先加入到硬盤的文件)
//    UnlimitedDiscCache(這個緩存類沒有任何的限制)
  
   DisplayImageOptions ImageUsing = new DisplayImageOptions.Builder()
           .showImageOnLoading(R.drawable.loading)//圖片還沒下載好時跑的臨時圖片
           .showImageForEmptyUri(R.drawable.loading)
           .showImageOnFail(R.drawable.loading).cacheInMemory(true)//緩存
           .cacheOnDisc(true).bitmapConfig(Bitmap.Config.RGB_565)
           .imageScaleType(ImageScaleType.IN_SAMPLE_INT)
           .build();
}
//.showImageOnLoading(R.drawable.loading)//圖片還沒下載好時跑的臨時圖片
//.showImageOnFail(R.drawable.loading)//圖片讀取失敗時跑的臨時圖片


所以請在drawable內放入您自己想放入的圖片。



使用方式:
        /**
         * imageLoading(Context context, String url, ImageView imageView)
         * context就是context;
         * url:你需要讀取圖片的網址
         * imageview:你指定findViewById的物件
         */

        tools.imageLoading(context, url,  imageView);

當然你也可以使用
ImageLoader.getInstance().displayImage(url, imageView, ImageUsing);




完整程式碼:

activity_main.xml



activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/activity_main"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.chat.a015865.imageloderdemo.MainActivity">

    <ImageView
        android:layout_centerInParent="true"
        android:id="@+id/show"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" />
</RelativeLayout>


MainActivity.java

public class MainActivity extends AppCompatActivity {

    private ImageView imageView;
    private Tools tools=new Tools();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
        initSet();
    }
    private void initView() {
        imageView = (ImageView)findViewById(R.id.show);
    }
    private void initSet() {
        String url = "https://www.cloudnloud.com/wp-content/uploads/2016/07/podcast-ac-new_2.jpg";
        tools.imageLoading(this, url, imageView);
    }
}


Tools.java

public class Tools {
    private static final String handle = Tools.class.getSimpleName();

    public void imageLoading(Context context, String url, ImageView imageView) {
        ImageLoaderConfiguration config = new ImageLoaderConfiguration
                .Builder(context)
                .memoryCacheExtraOptions(480, 800) //保存每個緩存圖片的最大寬高
                .threadPriority(Thread.NORM_PRIORITY - 2) //線池中的緩存數
                .denyCacheImageMultipleSizesInMemory() //禁止緩存多張圖片
                .memoryCache(new FIFOLimitedMemoryCache(2 * 1024 * 1024))//缓存策略
//                .memoryCacheSize(50 * 1024 * 1024) //設置內存緩存的大小
                .diskCacheFileNameGenerator(new Md5FileNameGenerator()) //缓存文件名的保存方式
//                .diskCacheSize(200 * 1024 * 1024) //緩存大小
                .tasksProcessingOrder(QueueProcessingType.LIFO) //工作序列
                .diskCacheFileCount(200) //緩存的文件數量
                .build();
        if (!ImageLoader.getInstance().isInited()) {//偵測如果imagloader已經init,就不再init
            Log.d(handle, "CheckPoint init");
            ImageLoader.getInstance().init(config);
        }
        ImageLoader.getInstance().displayImage(url, imageView, ImageUsing);

    }
    DisplayImageOptions ImageUsing = new DisplayImageOptions.Builder()
            .showImageOnLoading(R.drawable.loading)
            .showImageForEmptyUri(R.drawable.loading)
            .showImageOnFail(R.drawable.loading).cacheInMemory(true)//緩存
            .cacheOnDisc(true).bitmapConfig(Bitmap.Config.RGB_565)
            .imageScaleType(ImageScaleType.IN_SAMPLE_INT)
            .build();
}


最後別忘了,加權限。 TMD寫Demo被這雷了十分鐘。QQ

<uses-permission android:name="android.permission.INTERNET"/>




Demo下載:
https://drive.google.com/open?id=0Byk75IYx-dKXWFNjMFRoQ3N2Rkk

協程(coroutine) - 協程為什麼要學它?

 Coroutine 協程 再強調一次 協程就是由kotlin官方所提供的線程api //Thread Thread { }.start() //Executor val execu...