<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                問題1: 加載太多的圖片很容易造成OOM異常。 ## 一、圖片緩存 **方法1:使用二級緩存 ->自己維護一個緩存區** 只要有足夠的內存,就一直保持對象,直到發現內存吃緊且沒有Strong Ref時才回收對象。 所以可以這么做:map里面的鍵是用來放圖片地址的,既可以是網絡上的圖片地址,也可以SDcard上的圖片地址, map里面的值里面放的是持有軟引用的Bitmap. ~~~ private Map<String, SoftReference<Bitmap>> imageMap = new HashMap<String, SoftReference<Bitmap>>(); ~~~ 每次為ImageView設置圖片時,先去map中尋找,存在就直接用,不存在則從網絡加載,下載好后存到map中。 **方法2:使用一級緩存,LruCache** 2.1 LRU算法簡介: LRU是Least Recently Used 近期最少使用算法。 內存管理的一種頁面置換算法,對于在內存中但又不用的數據塊(內存塊)叫做LRU,操作系統會根據哪些數據屬于LRU而將其移出內存而騰出空間來加載另外的數據。 什么是LRU算法? LRU是Least Recently Used的縮寫,即最少使用頁面置換算法,是為虛擬頁式存儲管理服務的。 2.2 在Android中,有一個叫做LruCache類專門用來做圖片緩存處理的。 它有一個特點,當緩存的圖片達到了預先設定的值的時候,那么近期使用次數最少的圖片就會被回收掉。 步驟: 1)要先設置緩存圖片的內存大小,這里設置為手機內存的1/10 手機內存的獲取方式:int MAXMEMONRY = (int) (Runtime.getRuntime() .maxMemory() / 10); 2)LruCache里面的鍵值對分別是URL和對應的圖片 3)使用時和上面類似,每次給item中的ImageView設置圖片時先從緩存中查找,存在直接用,不存在則從網絡加載,加載完成存到緩存中。 ~~~ private LruCache<String, BitmapDrawable> mMemoryCache; public MyCache() { // 獲取應用程序最大可用內存 int maxMemory = (int) Runtime.getRuntime().maxMemory(); int cacheSize = maxMemory / 10;//大小為當前程序運行時內存的1/10 mMemoryCache = new LruCache<String, BitmapDrawable>(cacheSize) { @Override protected int sizeOf(String key, BitmapDrawable drawable) { return drawable.getBitmap().getByteCount(); } }; } ~~~ **方法3.使用三級緩存:利用外部存儲(即文件系統來緩存下載的圖片)** 只是把緩存放到了外部存儲中,其他用法不變。 注意: **3.1根據實際情況決定在程序結束后要不要把緩存文件刪除,如果程序中加載的圖片更新速度很快(如新聞,更新速度很快),就需要在程序結束后清空緩存文件。反之,可以不用刪除。** **方法4.一級三級緩存配合使用** 設置圖片時先從一級緩存中取,存在則直接使用,不存在再去三級緩存中查找,存在直接使用,不存在再從網絡加載, 注意: 4.1加載完成后,分別存到一級緩存和二級緩存。使用這種方案時,可以把一級緩存設置小一點。 4.2根據實際情況決定在程序結束后要不要把緩存文件刪除,如果程序中加載的圖片更新速度很快(如新聞,更新速度很快),就需要在程序結束后清空緩存文件。反之,可以不用刪除。 ## 二、四種方案的比較 1.:方案1、2使用的內存是運行時內存,速度相對較快,方案3使用的是二級緩存,速度相對較慢,方案4是一級緩存和二級緩存的配合使用,速度適中。 2.:方案1是自己維護一個緩存,緩存中的圖片何時被回收完全由GC決定,所以可能會占用很大內存;方案2是用Android提供的緩存,內部存儲原理和方案1類似,但使用了LRU算法,優點能較智能的決定那些圖片該回收,哪些不能回收,所以會把內存控制在一個較合理的狀態。方案3使用二級緩存,速度雖然慢了點,但是外部存儲基本不用擔心內存不夠用。方案4是一級緩存和二級緩存的結合使用,一級緩存加快使用速度,二級緩存增加使用內存。但操作較麻煩,保存需要兩次,也浪費了一些內存。 **總結:**根據實際情況使用不同方案,方案1不推薦使用,方案2 3 4 各有優點. ## 三、listView異步加載圖片錯位的問題 **1.問題**:使用ListView異步加載圖片時,如果不做處理,會出現圖片圖片錯位的情況,特別是在網速不給力的情況下。 效果圖: ![這里寫圖片描述](https://box.kancloud.cn/2016-04-23_571af4d5716cb.jpg "") **2.原因**:由ListVIew內部回收機制所致。 RecycleBin機制: ![這里寫圖片描述](https://box.kancloud.cn/2016-04-23_571af4d60025a.jpg "") ![這里寫圖片描述](https://box.kancloud.cn/2015-12-01_565da63ce5c6f.jpg "") 分析:當重用 convertView 時,最初一屏顯示 7 條記錄, getView 被調用 7 次,創建了 7 個 convertView. 當 Item1 劃出屏幕, Item8 進入屏幕時,這時沒有為 Item8 創建新的 view 實例, Item8 復用的是 Item1 的 view 如果沒有異步不會有任何問題,雖然 Item8 和 Item1 指向的是同一個 view,但滑到 Item8 時刷上了 Item8 的數據,這時 Item1 的數據和 Item8 是一樣的,因為它們指向的是同一塊內存, 但 Item1 已滾出了屏幕你看不見。當 Item1 再次可見時這塊 view 又涮上了 Item1 的數據。 但當有異步下載時就有問題了,假設 Item1 的圖片下載的比較慢,Item8 的圖片下載的比較快,你滾上去 使 Item8 可見,這時 Item8 先顯示它自己下載的圖片沒錯,但等到 Item1 的圖片也下載完時你發現 Item8 的圖片也變成了 Item1 的圖片,因為它們復用的是同一個 view。 如果 Item1 的圖片下載的比 Item8 的圖片快, Item1 先刷上自己下載的圖片,這時你滑下去,Item8 的圖片還沒下載完, Item8 會先顯示 Item1 的圖片,因為它們是同一快內存,當 Item8 自己的圖片下載完后 Item8 的圖片又刷成 了自己的,你再滑上去使 Item1 可見, Item1 的圖片也會和 Item8 的圖片是一樣的, 因為它們指向的是同一塊內存。 ## 四、解決方案 **1.給ImageView添加tag** 1)在getView()方法中得到一個Imageview時,添加一個tag,tag一般是一個url 2)在異步任務加載圖片成功時,通過listView的findViewWithTag(tag)方法得到一個imageview,然后設置圖片 ~~~ @Override public View getView( int position, View convertView, ViewGroup parent) { if (listView == null) listView = (ListView) parent; View view = null; ImageView imageView = null; if (convertView != null) view = convertView; else { view = LayoutInflater.from(context).inflate(R.layout. image_item, parent, false); } imageView = (ImageView) view.findViewById(R.id.image ); imageView.setImageResource(R.drawable. ic_launcher); String url = data[position]; imageView.setTag(url); BitmapDrawable bitmapDrawable = cache.getBitmapFromMemoryCache(url); if (bitmapDrawable != null && imageView != null) { imageView.setImageDrawable(bitmapDrawable); } else { new ImageLoadAsyncTask(listView , context , cache).execute(url); } return view; } @Override protected void onPostExecute(BitmapDrawable drawable) { ImageView mImageView = (ImageView) listView.findViewWithTag(imageUrl ); if (mImageView != null && drawable != null) { mImageView.setImageDrawable(drawable); } } ~~~ **2、使用Volley的NetworkImageView** 1)在item布局文件中,用NetworkImageView替換ImageView 2)使用ImageLoader圖片加載器 ~~~ <?xml version= "1.0" encoding ="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width= "match_parent" android:layout_height= "match_parent" android:orientation= "vertical" > <com.android.volley.toolbox.NetworkImageView android:id="@+id/image" android:layout_width="match_parent" android:layout_height="120dp" android:scaleType="fitXY" android:src="@drawable/ic_launcher" /> </LinearLayout> ~~~ ~~~ @Override public View getView( int position, View convertView, ViewGroup parent) { String url = getItem(position); View view; if (convertView == null) { view = LayoutInflater.from(getContext()).inflate( R.layout. image_item, n ull) ; } else { view = convertView; } NetworkImageView image = (NetworkImageView) view .findViewById(R.id. image); image.setDefaultImageResId(R.drawable. ic_launcher); image.setErrorImageResId(R.drawable. ic_launcher); image.setImageUrl(url, mImageLoader); return view; } ~~~ **3、使用弱引用把asynctask和imageview相關聯** 1)本質是要讓ImageView和BitmapWorkerTask之間建立一個雙向關聯,互相持有對方的引用,再通過適當的邏輯判斷來解決圖片亂序問題,然后為了防止出現內存泄漏的情 況,雙向關聯要使用弱引用的方式建立。 1.自定義的一個 Drawable,讓這個Drawable持有BitmapWorkerTask的弱引用。 ~~~ /** * 自定義的一個 Drawable,讓這個 Drawable持有BitmapWorkerTask的弱引用。 */ public class AsyncDrawable extends BitmapDrawable { private WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference; public AsyncDrawable(Resources res, Bitmap bitmap, BitmapWorkerTask bitmapWorkerTask) { super(res, bitmap); bitmapWorkerTaskReference = new WeakReference<BitmapWorkerTask>( bitmapWorkerTask); } public BitmapWorkerTask getBitmapWorkerTask() { return bitmapWorkerTaskReference .get(); } } ~~~ 2.定義自己的異步加載任務,讓這個任務擁有ImageView的弱引用 ~~~ /** * 異步下載圖片的任務。 * * @author guolin */ class BitmapWorkerTask extends AsyncTask<String, Void, BitmapDrawable> { String imageUrl; private BitmapCache bitmapCache; private Context context; private WeakReference<ImageView> imageViewReference; public BitmapWorkerTask(ImageView imageView, Context context, BitmapCache bitmapCache) { imageViewReference = new WeakReference<ImageView>(imageView); this.context = context; this.bitmapCache = bitmapCache; } @Override protected BitmapDrawable doInBackground(String... params) { imageUrl = params[0]; // 在后臺開始下載圖片 Bitmap bitmap = downloadBitmap(imageUrl); BitmapDrawable drawable = new BitmapDrawable(context.getResources(), bitmap); bitmapCache.addBitmapToMemoryCache(imageUrl, drawable); return drawable; } @Override protected void onPostExecute(BitmapDrawable drawable) { ImageView imageView = getAttachedImageView(); if (imageView != null && drawable != null) { imageView.setImageDrawable(drawable); } } /** * 獲取當前BitmapWorkerTask所關聯的ImageView。 */ private ImageView getAttachedImageView() { ImageView imageView = imageViewReference.get(); BitmapWorkerTask bitmapWorkerTask = BitmapWorkManager.getBitmapWorkerTask(imageView); if (this == bitmapWorkerTask) { return imageView; } return null; } /** * 建立HTTP請求,并獲取Bitmap對象。 * * @param imageUrl * 圖片的URL地址 * @return 解析后的Bitmap對象 */ private Bitmap downloadBitmap(String imageUrl) { Bitmap bitmap = null; HttpURLConnection con = null; try { URL url = new URL(imageUrl); con = (HttpURLConnection) url.openConnection(); con.setConnectTimeout(5 * 1000); con.setReadTimeout(10 * 1000); bitmap = BitmapFactory.decodeStream(con.getInputStream()); } catch (Exception e) { e.printStackTrace(); } finally { if (con != null) { con.disconnect(); } } return bitmap; } } ~~~ 3.使用 ~~~ @Override public View getView(int position, View convertView, ViewGroup parent) { if (mListView == null) { mListView = (ListView) parent; } String url = getItem(position); View view; if (convertView == null) { view = LayoutInflater.from(getContext()).inflate( R.layout.image_item, null); } else { view = convertView; } ImageView image = (ImageView) view.findViewById(R.id.image); BitmapDrawable drawable = mMemoryCache.getBitmapFromMemoryCache(url);// 從緩存中取對應url圖片 if (drawable != null) { image.setImageDrawable(drawable); // cancelPotentialWork返回true代表當前ImageView正在加載另一張圖片, // 所以要cancel上個任務,來執行新的任務 } else if (BitmapWorkManager.cancelPotentialWork(url, image)) { BitmapWorkerTask task = new BitmapWorkerTask(image, getContext(), mMemoryCache); AsyncDrawable asyncDrawable = new AsyncDrawable(getContext() .getResources(), mLoadingBitmap, task); image.setImageDrawable(asyncDrawable); task.execute(url); } return view; } ~~~ [源碼](http://download.csdn.net/detail/u011102153/9172245) 注:Android中對于圖片的加載有很多開源的框架,這里列舉幾個: 1.xUtils(中國人做的哦) [https://github.com/wyouflf/xUtils](https://github.com/wyouflf/xUtils) 2.Volley(谷歌,非常好用) [https://github.com/adamrocker/volley](https://github.com/adamrocker/volley) 3.Picasso(感覺沒前兩個好) [https://github.com/square/picasso](https://github.com/square/picasso) 4.Glide [https://github.com/bumptech/glide](https://github.com/bumptech/glide) 5.Universal ImageLoader 6.Fresco (Facebook,非常強大) [https://github.com/facebook/fresco](https://github.com/facebook/fresco)
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看