Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android瀑布流,解決oom

Android瀑布流,解決oom

編輯:關於Android編程

這是一個Android瀑布流的實現demo。

瀑布流我的實現是定義三個linearlayout,然後向裡面addView(),如果多了會出現oom異常,所以做了一些處理。

1.lrucache緩存

2.只顯示當前屏的圖片

3.滑動過程中不加載圖片

4.大圖縮放成小圖


直接看代碼:

PhotoFallScrollView.java主類 自定義的ScrollView.

package com.pangzaifei.falls;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnTouchListener;
import android.widget.ImageView;
import android.widget.ImageView.ScaleType;
import android.widget.LinearLayout;
import android.widget.ScrollView;
import android.widget.Toast;

/**
 * 瀑布流類
 * 
 * 原理: 1:創建3個linearlayout,設置他們的寬度,將獲得的圖片壓縮成和3個linearlayout一樣的寬度,
 * 然後根據3個linearlayout的高度來判斷,將bitmap添加到哪一個linearlayout中
 * 2:翻頁處理,根據手勢抬起的位置和滑動的末尾處來進行翻頁
 * 
 * @author pangzf
 * @date 2014年7月15日 上午10:33:05
 */
public class PhotoFallScrollView extends ScrollView implements OnTouchListener {
    /**
     * 頁數
     */
    private static int page;
    /**
     * 每頁顯示多少張
     */
    private static final int PAGE_SIZE = 8;
    private Context mContext;
    /**
     * 數據源圖片
     */
    private Images mImagesThoumb;
    /**
     * task請求集合
     */
    private Set mTasks;
    boolean isFirstEntr = true;
    private LinearLayout mFirstColumn;
    private LinearLayout mSecondColumn;
    private LinearLayout mThirdColumn;
    private int mFirstColumnHeight;
    private int mSecondColumnHeight;
    private int mThirdColumnHeight;
    private int mClolumnWidth;

    private long mDelay = 5;
    /**
     * 上次滑動的最後位置
     */
    private static int lastScrollY = -1;

    /**
     * 是否已加載過一次layout,這裡onLayout中的初始化只需加載一次
     */
    private boolean loadOnce;
    /**
     * 存放圖片的集合
     */
    private List mImageViewList = new ArrayList();

    public PhotoFallScrollView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        this.mContext = context;
        init();
    }

    public PhotoFallScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
        this.mContext = context;
        init();
    }

    public PhotoFallScrollView(Context context) {
        super(context);
        this.mContext = context;
        init();
    }

    /**
     * 初始化
     */
    private void init() {
        mImagesThoumb = Images.getInstance();
        mTasks = new HashSet();
        setOnTouchListener(this);
    }

    @Override
    protected void onLayout(boolean changed, int l, int t, int r, int b) {
        super.onLayout(changed, l, t, r, b);

        // 第一次進入就加載第一頁的圖片
        if (changed && !loadOnce) {
            mScrollViewHeight = this.getHeight();
            mScrollLayout = this.getChildAt(0);
            mFirstColumn = (LinearLayout) findViewById(R.id.first_column);
            mSecondColumn = (LinearLayout) findViewById(R.id.second_column);
            mThirdColumn = (LinearLayout) findViewById(R.id.third_column);
            mClolumnWidth = mFirstColumn.getWidth();
            loadOnce = true;
            loadMoreImages();
        }
    }

    /**
     * 加載圖片
     */
    private void loadMoreImages() {
        if (hashSdcard()) {

            // 根據頁數加載圖片
            int startIndex = page * PAGE_SIZE;
            int endIndex = page * PAGE_SIZE + PAGE_SIZE;

            if (startIndex < mImagesThoumb.imageThumbs.length) {
                if (endIndex > mImagesThoumb.imageThumbs.length) {
                    endIndex = mImagesThoumb.imageThumbs.length;
                }
                for (int i = startIndex; i < endIndex; i++) {
                    String imageUrl = mImagesThoumb.imageThumbs[i].toString();
                    if (imageUrl != null && !"".equals(imageUrl)) {
                        downLoadData(imageUrl);
                    }
                }
                page++;
            } else {
                Toast.makeText(mContext, "沒有更多圖片了", 0).show();
            }
        } else {
            Toast.makeText(mContext, "無sdcard", 0).show();
        }
    }

    /**
     * 下載
     * 
     * @param imageUrl
     */
    private void downLoadData(String imageUrl) {
        DownLoadTask task = new DownLoadTask();
        mTasks.add(task);
        task.execute(imageUrl);
    }

    public class DownLoadTask extends AsyncTask {

        private String mImageUrl;

        @Override
        protected Bitmap doInBackground(String... params) {
            try {
                mImageUrl = params[0];
                Bitmap bitmapFromMemory = mImagesThoumb
                        .getMemoryCache(mImageUrl);
                if (bitmapFromMemory != null) {
                    return bitmapFromMemory;
                }
                if (hashSdcard()) {
                    Bitmap bitmap = loadImage(mImageUrl);
                    return bitmap;
                } else {
                    Toast.makeText(mContext, "無sdcard,無法獲取圖片", 0).show();
                }

            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }

        @Override
        protected void onPostExecute(Bitmap bitmap) {
            super.onPostExecute(bitmap);
            // 展示圖片
            if (bitmap != null) {
                // 1.縮放圖片
                // 2.新建ImageView
                // 3.找到需要的linerlayout添加imageView
                float width = bitmap.getWidth();
                float radio = width / mFirstColumn.getWidth();
                float scaleHeight = bitmap.getHeight() / radio;
                addImage(bitmap, mFirstColumn.getWidth(), scaleHeight);
            }
            mTasks.remove(this);
        }

        /**
         * 將圖片添加到linearlayout中
         * 
         * @param bitmap
         * @param scaleHeight
         */
        public void addImage(Bitmap bitmap, float width, float scaleHeight) {
            // 生成縮放的iv
            ImageView iv = new ImageView(mContext);
            android.view.ViewGroup.LayoutParams params = new LayoutParams(
                    (int) width, (int) scaleHeight);
            iv.setLayoutParams(params);
            if (bitmap != null) {
                // 解決默認圖片有大有小的問題
                iv.setScaleType(ScaleType.FIT_XY);
                iv.setPadding(5, 5, 5, 5);

                iv.setImageBitmap(bitmap);
                iv.setTag(R.string.iamgurl, mImageUrl);
                findColumnToAdd(iv, (int) scaleHeight).addView(iv);
                mImageViewList.add(iv);
            }
        }

    }

    private Bitmap downLoad(String imageUrl) throws IOException {
        BufferedInputStream bis = null;
        FileOutputStream fos = null;
        BufferedOutputStream bos = null;
        HttpURLConnection conn = null;
        File imageFile = null;
        try {
            URL url = new URL(imageUrl);
            conn = (HttpURLConnection) url.openConnection();
            conn.setReadTimeout(10000);
            conn.setConnectTimeout(5000);
            conn.setDoInput(true);
            conn.setDoOutput(true);
            InputStream is = conn.getInputStream();
            imageFile = new File(getImagePath(imageUrl));
            bis = new BufferedInputStream(is);
            fos = new FileOutputStream(imageFile);
            bos = new BufferedOutputStream(fos);
            int len = 0;
            byte[] buffer = new byte[1024];
            while ((len = bis.read(buffer)) != -1) {
                bos.write(buffer, 0, len);
                bos.flush();
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (bis != null) {
                bis.close();
            }
            if (bos != null) {
                bos.close();
            }
            if (conn != null) {
                conn.disconnect();
            }
        }
        // 如果imageFile不為null,將圖片添加到memory中
        if (imageFile != null) {
            Bitmap bitmap = BitmapFactory.decodeFile(imageFile.getPath());
            mImagesThoumb.addBitmapToMemoryCache(imageUrl, bitmap);
            return bitmap;
        }
        return null;

    }

    /**
     * 判斷圖片sdcard是否有圖片,如果有就用,沒有就下載
     * 
     * @param mImageUrl
     * @return
     */
    public Bitmap loadImage(String mImageUrl) throws Exception {
        File file = new File(getImagePath(mImageUrl));
        if (!file.exists()) {
            downLoad(mImageUrl);
        }

        if (mImageUrl != null) {
            // 處理本地圖片,設置大小防止oom
            Bitmap bitmap = mImagesThoumb.decodeSimpleBitMapFromResource(
                    file.getPath(), mClolumnWidth);
            // Bitmap bitmap = BitmapFactory.decodeFile(file.getPath());
            if (bitmap != null) {
                mImagesThoumb.addBitmapToMemoryCache(mImageUrl, bitmap);
                return bitmap;
            }
        }
        return null;
    }

    /**
     * 查找要添加的column
     * 
     * @param iv
     */
    private LinearLayout findColumnToAdd(ImageView iv, int imageHeight) {
        if (mFirstColumnHeight <= mSecondColumnHeight) {
            if (mFirstColumnHeight <= mThirdColumnHeight) {
                iv.setTag(R.string.border_top, mFirstColumnHeight);
                mFirstColumnHeight += imageHeight;
                iv.setTag(R.string.border_bottom, mFirstColumnHeight);
                return mFirstColumn;
            }
            iv.setTag(R.string.border_top, mThirdColumnHeight);
            mThirdColumnHeight += imageHeight;
            iv.setTag(R.string.border_bottom, mThirdColumnHeight);
            return mThirdColumn;

        } else {
            if (mSecondColumnHeight <= mThirdColumnHeight) {
                iv.setTag(R.string.border_top, mSecondColumnHeight);
                mSecondColumnHeight += imageHeight;
                iv.setTag(R.string.border_bottom, mSecondColumnHeight);
                return mSecondColumn;
            }
            iv.setTag(R.string.border_top, mThirdColumnHeight);
            mThirdColumnHeight += imageHeight;
            iv.setTag(R.string.border_bottom, mThirdColumnHeight);
            return mThirdColumn;
        }
    }

    /**
     * 獲得file地址
     * 
     * @param imageUrl
     * @return
     */
    private String getImagePath(String imageUrl) {
        int lastIndexOf = imageUrl.lastIndexOf("/");
        String imageName = imageUrl.substring(lastIndexOf + 1);
        String imageDir = Environment.getExternalStorageDirectory().getPath()
                + "/pangzaifei/";
        File file = new File(imageDir);
        if (!file.exists()) {
            file.mkdir();
        }
        String imagePath = imageDir + imageName;
        return imagePath;
    }

    /**
     * 獲得圖片的名字
     * 
     * @param imageUrl
     */

    private boolean hashSdcard() {
        if (Environment.getExternalStorageState().equals(
                Environment.MEDIA_MOUNTED)) {
            return true;
        }
        return false;
    }

    @Override
    /**
     * 當手勢抬起時,開始每個5毫秒計算位置
     */
    public boolean onTouch(View v, MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_UP) {
            // 發送handler
            Message msg = mHandler.obtainMessage();
            msg.obj = this;
            mHandler.sendMessageDelayed(msg, mDelay);
        }
        return false;
    }

    private Handler mHandler = new Handler() {

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            // 判斷是否已經滑到了最低處,如果滑到了最低處,則加載更多頁面,否則繼續發送handler掃描
            PhotoFallScrollView scrollView = (PhotoFallScrollView) msg.obj;
            int scrollY = scrollView.getScrollY();
            if (scrollY == lastScrollY) {
                if (mScrollViewHeight + scrollY >= mScrollLayout.getHeight()
                        && mTasks.isEmpty()) {
                    scrollView.loadMoreImages();
                }
                scrollView.checkVisibile();
            } else {
                lastScrollY = scrollY;
                Message message = new Message();
                message.obj = scrollView;
                mHandler.sendMessageDelayed(message, mDelay);
            }
        }

    };
    private int mScrollViewHeight;
    private View mScrollLayout;

    /**
     * 想不可見的變為空圖片
     */
    protected void checkVisibile() {
        if (mImageViewList != null && mImageViewList.size() > 0) {
            for (int i = 0; i < mImageViewList.size(); i++) {
                ImageView iv = mImageViewList.get(i);
                int borderTop = (int) iv.getTag(R.string.border_top);
                int borderBottom = (int) iv.getTag(R.string.border_bottom);
                if (borderBottom > getScrollY()
                        && borderTop < getScrollY() + mScrollViewHeight) {
                    String imageUrl = (String) iv.getTag(R.string.iamgurl);
                    if (imageUrl != null && !"".equals(imageUrl)) {
                        Bitmap bitmap = mImagesThoumb.getMemoryCache(imageUrl);
                        if (bitmap != null) {
                            iv.setImageBitmap(bitmap);
                        } else {
                            downLoadData(imageUrl);
                        }
                    }
                } else {
                    iv.setImageResource(R.drawable.empty_photo);
                }

            }
        }
    }
}
上面是主要的東西,思路和注釋已經添加。其中imageView中的tag我要解釋一下,主要保存了每一列的上邊距和下邊距和圖片的url,這個方法,就是只顯示當前頁的圖片。

布局文件:



    

        

            
            

            
            

            
            
        
    

效果圖:

n塊ズ…?/ym/源碼地址:

http://download.csdn.net/detail/pangzaifei/7639423





  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved