首頁 收藏 QQ群
 網(wǎng)站導(dǎo)航

ZNDS智能電視網(wǎng) 推薦當(dāng)貝市場

TV應(yīng)用下載 / 資源分享區(qū)

軟件下載 | 游戲 | 討論 | 電視計算器

綜合交流 / 評測 / 活動區(qū)

交流區(qū) | 測硬件 | 網(wǎng)站活動 | Z幣中心

新手入門 / 進(jìn)階 / 社區(qū)互助

新手 | 你問我答 | 免費(fèi)刷機(jī)救磚 | ROM固件

查看: 13221|回復(fù): 0
上一主題 下一主題
[教程]

androud異步加載,處理圖片溢出

[復(fù)制鏈接]
跳轉(zhuǎn)到指定樓層
樓主
發(fā)表于 2013-8-28 16:27 | 只看該作者 回帖獎勵 |倒序?yàn)g覽 |閱讀模式
88最近在Android開發(fā)中碰到比較棘手的問題,就是加載圖片內(nèi)存溢出。我開發(fā)的是一個新聞應(yīng)用,應(yīng)用中用到大量的圖片,一個界面中可能會有上百張圖片。開發(fā)android應(yīng)用的朋友可能或多或少碰到加載圖片內(nèi)存溢出問題,一般情況下,加載一張大圖就會導(dǎo)致內(nèi)存溢出,同樣,加載多張圖片內(nèi)存溢出的概率也很高。   
列一下網(wǎng)絡(luò)上查到的一般做法:   
1.使用BitmapFactory.Options對圖片進(jìn)行壓縮   
2.優(yōu)化加載圖片的adapter中的getView方法,使之盡可能少占用內(nèi)存   
3.使用異步加載圖片的方式,使圖片在頁面加載后慢慢載入進(jìn)來。   
   
1、2步驟是必須做足的工作,但是對于大量圖片的列表仍然無法解決內(nèi)存溢出的問題,采用異步加載圖片的方式才能有效解決圖片加載內(nèi)存溢出問題。   
測試的效果圖如下:   
     
   
   
在這里我把主要的代碼貼出來,給大家分享一下。   
1、首先是MainActivity和activity_main.xml布局文件的代碼。   
(1)、MainActivity的代碼如下:package net.loonggg.test;import java.util.List;import net.loonggg.adapter.MyAdapter;import net.loonggg.bean.Menu;import net.loonggg.util.HttpUtil;import net.loonggg.util.Utils;import android.app.Activity;import android.app.ProgressDialog;import android.os.AsyncTask;import android.os.Bundle;import android.view.Window;import android.widget.ListView;public class MainActivity extends Activity {        private ListView lv;        private MyAdapter adapter;        private ProgressDialog pd;        @Override        protected void onCreate(Bundle savedInstanceState) {                requestWindowFeature(Window.FEATURE_NO_TITLE);                super.onCreate(savedInstanceState);                setContentView(R.layout.activity_main);                lv = (ListView) findViewById(R.id.lv);                pd = new ProgressDialog(this);                pd.setTitle("加載菜單");                pd.setMessage("正在加載");                adapter = new MyAdapter(this);                new MyTask().execute("1");        }        public class MyTask extends AsyncTask<String, Void, List<Menu>> {                @Override                protected void onPreExecute() {                        super.onPreExecute();                        pd.show();                }                @Override                protected void onPostExecute(List<Menu> result) {                        super.onPostExecute(result);                        adapter.setData(result);                        lv.setAdapter(adapter);                        pd.dismiss();                }                @Override                protected List<Menu> doInBackground(String... params) {                        String menuListStr = getListDishesInfo(params[0]);                        return Utils.getInstance().parseMenusJSON(menuListStr);                }        }        private String getListDishesInfo(String sortId) {                // url                String url = HttpUtil.BASE_URL + "servlet/MenuInfoServlet?sortId="                                + sortId + "&flag=1";                // 查詢返回結(jié)果                return HttpUtil.queryStringForPost(url);        }}   
   
復(fù)制代碼   
package net.loonggg.test;import java.util.List;import net.loonggg.adapter.MyAdapter;import net.loonggg.bean.Menu;import net.loonggg.util.HttpUtil;import net.loonggg.util.Utils;import android.app.Activity;import android.app.ProgressDialog;import android.os.AsyncTask;import android.os.Bundle;import android.view.Window;import android.widget.ListView;public class MainActivity extends Activity {        private ListView lv;        private MyAdapter adapter;        private ProgressDialog pd;        @Override        protected void onCreate(Bundle savedInstanceState) {                requestWindowFeature(Window.FEATURE_NO_TITLE);                super.onCreate(savedInstanceState);                setContentView(R.layout.activity_main);                lv = (ListView) findViewById(R.id.lv);                pd = new ProgressDialog(this);                pd.setTitle("加載菜單");                pd.setMessage("正在加載");                adapter = new MyAdapter(this);                new MyTask().execute("1");        }        public class MyTask extends AsyncTask<String, Void, List<Menu>> {                @Override                protected void onPreExecute() {                        super.onPreExecute();                        pd.show();                }                @Override                protected void onPostExecute(List<Menu> result) {                        super.onPostExecute(result);                        adapter.setData(result);                        lv.setAdapter(adapter);                        pd.dismiss();                }                @Override                protected List<Menu> doInBackground(String... params) {                        String menuListStr = getListDishesInfo(params[0]);                        return Utils.getInstance().parseMenusJSON(menuListStr);                }        }        private String getListDishesInfo(String sortId) {                // url                String url = HttpUtil.BASE_URL + "servlet/MenuInfoServlet?sortId="                                + sortId + "&flag=1";                // 查詢返回結(jié)果                return HttpUtil.queryStringForPost(url);        }}   
   
復(fù)制代碼   
(2)、activity_main.xml的布局文件如下:<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas.android.com/tools"    android:layout_width="match_parent"    android:layout_height="match_parent"    android:background="#ffffff"    android:orientation="vertical" >    <ListView        android:id="@+id/lv"        android:layout_width="fill_parent"        android:layout_height="wrap_content" >    </ListView></LinearLayout>   
   
復(fù)制代碼   
2、這是自定義的ListView的adapter的代碼:package net.loonggg.adapter;import java.util.List;import net.loonggg.bean.Menu;import net.loonggg.test.R;import net.loonggg.util.ImageLoader;import android.app.Activity;import android.content.Context;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.ImageView;import android.widget.TextView;public class MyAdapter extends BaseAdapter {        private List<Menu> list;        private Context context;        private Activity activity;        private ImageLoader imageLoader;        private ViewHolder viewHolder;        public MyAdapter(Context context) {                this.context = context;                this.activity = (Activity) context;                imageLoader = new ImageLoader(context);        }        public void setData(List<Menu> list) {                this.list = list;        }        @Override        public int getCount() {                return list.size();        }        @Override        public Object getItem(int position) {                return list.get(position);        }        @Override        public long getItemId(int position) {                return position;        }        @Override        public View getView(int position, View convertView, ViewGroup parent) {                if (convertView == null) {                        convertView = LayoutInflater.from(context).inflate(                                        R.layout.listview_item, null);                        viewHolder = new ViewHolder();                        viewHolder.tv = (TextView) convertView.findViewById(R.id.item_tv);                        viewHolder.iv = (ImageView) convertView.findViewById(R.id.item_iv);                        convertView.setTag(viewHolder);                } else {                        viewHolder = (ViewHolder) convertView.getTag();                }                viewHolder.tv.setText(list.get(position).getDishes());                imageLoader.DisplayImage(list.get(position).getPicPath(), activity,                                viewHolder.iv);                return convertView;        }        private class ViewHolder {                private ImageView iv;                private TextView tv;        }}   
   
復(fù)制代碼   
3、這是最重要的一部分代碼,這就是異步加載圖片的一個類,這里我就不解釋了,代碼中附有注釋。代碼如下:package net.loonggg.util;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.InputStream;import java.io.OutputStream;import java.net.HttpURLConnection;import java.net.URL;import java.util.Collections;import java.util.Map;import java.util.Stack;import java.util.WeakHashMap;import net.loonggg.test.R;import android.app.Activity;import android.content.Context;import android.graphics.Bitmap;import android.graphics.BitmapFactory;import android.widget.ImageView;/*** 異步加載圖片類** @author loonggg**/public class ImageLoader {        // 手機(jī)中的緩存        private MemoryCache memoryCache = new MemoryCache();        // sd卡緩存        private FileCache fileCache;        private PicturesLoader pictureLoaderThread = new PicturesLoader();        private PicturesQueue picturesQueue = new PicturesQueue();        private Map<ImageView, String> imageViews = Collections                        .synchronizedMap(new WeakHashMap<ImageView, String>());        public ImageLoader(Context context) {                // 設(shè)置線程的優(yōu)先級                pictureLoaderThread.setPriority(Thread.NORM_PRIORITY - 1);                fileCache = new FileCache(context);        }        // 在找不到圖片時,默認(rèn)的圖片        final int stub_id = R.drawable.stub;        public void DisplayImage(String url, Activity activity, ImageView imageView) {                imageViews.put(imageView, url);                Bitmap bitmap = memoryCache.get(url);                if (bitmap != null)                        imageView.setImageBitmap(bitmap);                else {// 如果手機(jī)內(nèi)存緩存中沒有圖片,則調(diào)用任務(wù)隊(duì)列,并先設(shè)置默認(rèn)圖片                        queuePhoto(url, activity, imageView);                        imageView.setImageResource(stub_id);                }        }        private void queuePhoto(String url, Activity activity, ImageView imageView) {                // 這ImageView可能之前被用于其它圖像。所以可能會有一些舊的任務(wù)隊(duì)列。我們需要清理掉它們。                picturesQueue.Clean(imageView);                PictureToLoad p = new PictureToLoad(url, imageView);                synchronized (picturesQueue.picturesToLoad) {                        picturesQueue.picturesToLoad.push(p);                        picturesQueue.picturesToLoad.notifyAll();                }                // 如果這個線程還沒有啟動,則啟動線程                if (pictureLoaderThread.getState() == Thread.State.NEW)                        pictureLoaderThread.start();        }        /**         * 根據(jù)url獲取相應(yīng)的圖片的Bitmap         *         * @param url         * @return         */        private Bitmap getBitmap(String url) {                File f = fileCache.getFile(url);                // 從SD卡緩存中獲取                Bitmap b = decodeFile(f);                if (b != null)                        return b;                // 否則從網(wǎng)絡(luò)中獲取                try {                        Bitmap bitmap = null;                        URL imageUrl = new URL(url);                        HttpURLConnection conn = (HttpURLConnection) imageUrl                                        .openConnection();                        conn.setConnectTimeout(30000);                        conn.setReadTimeout(30000);                        InputStream is = conn.getInputStream();                        OutputStream os = new FileOutputStream(f);                        // 將圖片寫到sd卡目錄中去                        ImageUtil.CopyStream(is, os);                        os.close();                        bitmap = decodeFile(f);                        return bitmap;                } catch (Exception ex) {                        ex.printStackTrace();                        return null;                }        }        // 解碼圖像和縮放以減少內(nèi)存的消耗        private Bitmap decodeFile(File f) {                try {                        // 解碼圖像尺寸                        BitmapFactory.Options o = new BitmapFactory.Options();                        o.inJustDecodeBounds = true;                        BitmapFactory.decodeStream(new FileInputStream(f), null, o);                        // 找到正確的縮放值。這應(yīng)該是2的冪。                        final int REQUIRED_SIZE = 70;                        int width_tmp = o.outWidth, height_tmp = o.outHeight;                        int scale = 1;                        while (true) {                                if (width_tmp / 2 < REQUIRED_SIZE                                                || height_tmp / 2 < REQUIRED_SIZE)                                        break;                                width_tmp /= 2;                                height_tmp /= 2;                                scale *= 2;                        }                        // 設(shè)置恰當(dāng)?shù)膇nSampleSize可以使BitmapFactory分配更少的空間                        // 用正確恰當(dāng)?shù)膇nSampleSize進(jìn)行decode                        BitmapFactory.Options o2 = new BitmapFactory.Options();                        o2.inSampleSize = scale;                        return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);                } catch (FileNotFoundException e) {                }                return null;        }        /**         * PictureToLoad類(包括圖片的地址和ImageView對象)         *         * @author loonggg         *         */        private class PictureToLoad {                public String url;                public ImageView imageView;                public PictureToLoad(String u, ImageView i) {                        url = u;                        imageView = i;                }        }        public void stopThread() {                pictureLoaderThread.interrupt();        }        // 存儲下載的照片列表        class PicturesQueue {                private Stack<PictureToLoad> picturesToLoad = new Stack<PictureToLoad>();                // 刪除這個ImageView的所有實(shí)例                public void Clean(ImageView image) {                        for (int j = 0; j < picturesToLoad.size();) {                                if (picturesToLoad.get(j).imageView == image)                                        picturesToLoad.remove(j);                                else                                        ++j;                        }                }        }        // 圖片加載線程        class PicturesLoader extends Thread {                public void run() {                        try {                                while (true) {                                        // 線程等待直到有圖片加載在隊(duì)列中                                        if (picturesQueue.picturesToLoad.size() == 0)                                                synchronized (picturesQueue.picturesToLoad) {                                                        picturesQueue.picturesToLoad.wait();                                                }                                        if (picturesQueue.picturesToLoad.size() != 0) {                                                PictureToLoad photoToLoad;                                                synchronized (picturesQueue.picturesToLoad) {                                                        photoToLoad = picturesQueue.picturesToLoad.pop();                                                }                                                Bitmap bmp = getBitmap(photoToLoad.url);                                                // 寫到手機(jī)內(nèi)存中                                                memoryCache.put(photoToLoad.url, bmp);                                                String tag = imageViews.get(photoToLoad.imageView);                                                if (tag != null && tag.equals(photoToLoad.url)) {                                                        BitmapDisplayer bd = new BitmapDisplayer(bmp,                                                                        photoToLoad.imageView);                                                        Activity activity = (Activity) photoToLoad.imageView                                                                        .getContext();                                                        activity.runOnUiThread(bd);                                                }                                        }                                        if (Thread.interrupted())                                                break;                                }                        } catch (InterruptedException e) {                                // 在這里允許線程退出                        }                }        }        // 在UI線程中顯示Bitmap圖像        class BitmapDisplayer implements Runnable {                Bitmap bitmap;                ImageView imageView;                public BitmapDisplayer(Bitmap bitmap, ImageView imageView) {                        this.bitmap = bitmap;                        this.imageView = imageView;                }                public void run() {                        if (bitmap != null)                                imageView.setImageBitmap(bitmap);                        else                                imageView.setImageResource(stub_id);                }        }        public void clearCache() {                memoryCache.clear();                fileCache.clear();        }}   
   
復(fù)制代碼   
4、緊接著是幾個實(shí)體類,一個是緩存到SD卡中的實(shí)體類,還有一個是緩存到手機(jī)內(nèi)存中的實(shí)體類。代碼如下:   
(1)、緩存到sd卡的實(shí)體類:package net.loonggg.util;import java.io.File;import android.content.Context;public class FileCache {        private File cacheDir;        public FileCache(Context context) {                // 找到保存緩存的圖片目錄                if (android.os.Environment.getExternalStorageState().equals(                                android.os.Environment.MEDIA_MOUNTED))                        cacheDir = new File(                                        android.os.Environment.getExternalStorageDirectory(),                                        "newnews");                else                        cacheDir = context.getCacheDir();                if (!cacheDir.exists())                        cacheDir.mkdirs();        }        public File getFile(String url) {                String filename = String.valueOf(url.hashCode());                File f = new File(cacheDir, filename);                return f;        }        public void clear() {                File[] files = cacheDir.listFiles();                for (File f : files)                        f.delete();        }}   
   
復(fù)制代碼   
(2)、緩存到手機(jī)內(nèi)存的實(shí)體類:package net.loonggg.util;import java.lang.ref.SoftReference;import java.util.HashMap;import android.graphics.Bitmap;public class MemoryCache {    private HashMap<String, SoftReference<Bitmap>> cache=new HashMap<String, SoftReference<Bitmap>>();    public Bitmap get(String id){        if(!cache.containsKey(id))            return null;        SoftReference<Bitmap> ref=cache.get(id);        return ref.get();    }    public void put(String id, Bitmap bitmap){        cache.put(id, new SoftReference<Bitmap>(bitmap));    }    public void clear() {        cache.clear();    }}   
   
復(fù)制代碼   
5、這個是輸入輸出流轉(zhuǎn)換的類,及方法:package net.loonggg.util;import java.io.InputStream;import java.io.OutputStream;public class ImageUtil {        public static void CopyStream(InputStream is, OutputStream os) {                final int buffer_size = 1024;                try {                        byte[] bytes = new byte[buffer_size];                        for (;;) {                                int count = is.read(bytes, 0, buffer_size);                                if (count == -1)                                        break;                                os.write(bytes, 0, count);                        }                } catch (Exception ex) {                }        }}   
   
復(fù)制代碼   
到這里基本就完成了

上一篇:Myeclipse中搭建Android開發(fā)環(huán)境 .
下一篇:一健查詢話費(fèi)
您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

Archiver|新帖|標(biāo)簽|軟件|Sitemap|ZNDS智能電視網(wǎng) ( 蘇ICP備2023012627號 )

網(wǎng)絡(luò)信息服務(wù)信用承諾書 | 增值電信業(yè)務(wù)經(jīng)營許可證:蘇B2-20221768 丨 蘇公網(wǎng)安備 32011402011373號

GMT+8, 2024-10-21 03:57 , Processed in 0.070705 second(s), 15 queries , Redis On.

Powered by Discuz!

監(jiān)督舉報:report#znds.com (請將#替換為@)

© 2007-2024 ZNDS.Com

快速回復(fù) 返回頂部 返回列表