天天看点

Android照片墙的实现

实现一个简单的照片墙。

实现原理:

1:去重复 相同的url不要下载两次,可以用set集合对封装的任务,但是我们应用使用了内存缓存即使不做判断也不会加载两次,因为LruCache对象已经帮我们实现了

2:下载图片的任务使用了AsyncTask

3: 当我们快速滑动屏幕的时候怎么做到当手指松开的时候才加载可见屏幕范围对应的图片,避免了快速滑动导致卡的问题

activity_main.xml

<RelativeLayout 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: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=".MainActivity">

    <GridView
        android:id="@+id/photo_wall"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:columnWidth="90dip"
        android:gravity="center"
        android:numColumns="auto_fit"
        android:stretchMode="columnWidth"
        android:verticalSpacing="10dip" />

</RelativeLayout>
           

Constant.java

public class Constant {

    public static String[] imgs = new String[]{
            "http://img5.douban.com/view/photo/thumb/public/p1042461956.jpg",
            "http://img5.douban.com/lpic/s28035816.jpg",
            "http://img3.douban.com/lpic/s28049685.jpg",
            "http://img5.douban.com/lpic/s28004598.jpg",
            "http://img5.douban.com/lpic/s28050639.jpg",
            "http://img3.douban.com/lpic/s28056884.jpg",
            "http://img5.douban.com/lpic/s28036379.jpg",
            "http://img5.douban.com/lpic/s28045199.jpg",
            "http://img3.douban.com/lpic/s28034923.jpg",
            "http://img5.douban.com/lpic/s28067039.jpg",
            "http://img3.douban.com/spic/s28000872.jpg",
            "http://img3.douban.com/view/movie_poster_cover/mpst/public/p2237747953.jpg",
            "http://img5.douban.com/view/movie_poster_cover/mpst/public/p2240110789.jpg",
            "http://img5.douban.com/view/movie_poster_cover/mpst/public/p2235609577.jpg",
            "http://img5.douban.com/view/movie_poster_cover/mpst/public/p2233113686.jpg",
            "http://img5.douban.com/view/movie_poster_cover/lpst/public/p2225188257.jpg",
            "http://img3.douban.com/view/movie_poster_cover/lpst/public/p2201518484.jpg",
            "http://img5.douban.com/view/movie_poster_cover/lpst/public/p2229383316.jpg",
            "http://img3.douban.com/view/movie_poster_cover/lpst/public/p2222477444.jpg",
            "http://img3.douban.com/view/movie_poster_cover/lpst/public/p2230484792.jpg",
            "http://img5.douban.com/view/movie_poster_cover/lpst/public/p2204911658.jpg",
            "http://img5.douban.com/view/movie_poster_cover/lpst/public/p2210568759.jpg",
            "http://img5.douban.com/view/movie_poster_cover/lpst/public/p2201468648.jpg",
            "http://img3.douban.com/view/movie_poster_cover/lpst/public/p2226169113.jpg",
            "http://img3.douban.com/view/movie_poster_cover/lpst/public/p2221319641.jpg",
            "http://img5.douban.com/view/movie_poster_cover/lpst/public/p2231932406.jpg",
            "http://img5.douban.com/view/movie_poster_cover/lpst/public/p2208286457.jpg",
            "http://img3.douban.com/view/movie_poster_cover/lpst/public/p2203481530.jpg",
            "http://img5.douban.com/view/movie_poster_cover/lpst/public/p2232079769.jpg",
            "http://img5.douban.com/view/movie_poster_cover/lpst/public/p2224484447.jpg",
            "http://img3.douban.com/view/movie_poster_cover/lpst/public/p2233767512.jpg",
            "http://img3.douban.com/view/movie_poster_cover/lpst/public/p2202114105.jpg",
            "http://img5.douban.com/view/movie_poster_cover/lpst/public/p2209761319.jpg",
            "http://img3.douban.com/view/movie_poster_cover/lpst/public/p2230222544.jpg",
            "http://img3.douban.com/view/movie_poster_cover/lpst/public/p2220776342.jpg",
            "http://img3.douban.com/view/movie_poster_cover/lpst/public/p2233840624.jpg",
            "http://img5.douban.com/view/movie_poster_cover/lpst/public/p2194199028.jpg",
            "http://img3.douban.com/view/movie_poster_cover/lpst/public/p2230222544.jpg",
            "http://img3.douban.com/view/movie_poster_cover/lpst/public/p2220776342.jpg",
            "http://img3.douban.com/view/movie_poster_cover/lpst/public/p2233840624.jpg",
            "http://img5.douban.com/view/movie_poster_cover/lpst/public/p2194199028.jpg",
            "http://img3.douban.com/view/movie_poster_cover/lpst/public/p2233260210.jpg",
            "http://img3.douban.com/view/movie_poster_cover/lpst/public/p2210832820.jpg",
            "http://img3.douban.com/view/movie_poster_cover/lpst/public/p2203693875.jpg",
            "http://img3.douban.com/view/movie_poster_cover/lpst/public/p2231791943.jpg",
            "http://img3.douban.com/view/movie_poster_cover/lpst/public/p2203838902.jpg",
            "http://img3.douban.com/view/movie_poster_cover/lpst/public/p2220218254.jpg",
            "http://img3.douban.com/view/movie_poster_cover/lpst/public/p2215268072.jpg",
            "http://img3.douban.com/view/movie_poster_cover/lpst/public/p2219669553.jpg",
            "http://img3.douban.com/view/movie_poster_cover/lpst/public/p2208934451.jpg",
            "http://img3.douban.com/view/movie_poster_cover/lpst/public/p2225669293.jpg",
            "http://img3.douban.com/view/movie_poster_cover/lpst/public/p2225986472.jpg",
            "http://img3.douban.com/view/movie_poster_cover/lpst/public/p2199678535.jpg",
            "http://img3.douban.com/view/movie_poster_cover/lpst/public/p2230471461.jpg",
            "http://img5.douban.com/view/movie_poster_cover/lpst/public/p2204888387.jpg",
            "http://img3.douban.com/view/movie_poster_cover/lpst/public/p2224389662.jpg",
            "http://img5.douban.com/view/movie_poster_cover/lpst/public/p2207808539.jpg",
            "http://img5.douban.com/view/movie_poster_cover/lpst/public/p2225291257.jpg",
            "http://img3.douban.com/view/movie_poster_cover/lpst/public/p2230505723.jpg"
    };
}
           

ImageLoaderAdapter.java

package com.jackie.photowall;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.util.LruCache;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.ImageView;

import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashSet;
import java.util.Set;

/**
 * Created by Jackie on 5/14/15.
 */
public class ImageLoaderAdapter extends BaseAdapter implements AbsListView.OnScrollListener {

    private Activity mActivity;
    private GridView mGridView;
    private LayoutInflater mInflater;

    /**
     * 图片缓存技术的核心类,用于缓存所有下载好的图片,在程序内存达到设定值时会将最少最近使用的图片移除掉。
     */
    private LruCache<String, Bitmap> mMemoryCache;
    /**
     * 记录所有正在下载或等待下载的任务。
     */
    private Set<ImageLoaderTask> mImageLoaderTasks;
    /**
     * 第一张可见图片的下标
     */
    private int mFirstVisibleItem;
    /**
     * 可见区域一屏有多少张图片
     */
    private int mVisibleItemCount;
    /**
     * 代表第一次进来不滑动的时候自动加载图片
     */
    private boolean mIsFirstLoader = true;


    public ImageLoaderAdapter(GridView mGridView, Activity mActivity) {
        this.mActivity = mActivity;
        this.mGridView = mGridView;
        mInflater = LayoutInflater.from(mActivity);
        mImageLoaderTasks = new HashSet<ImageLoaderTask>();
        /**
         * 获取应用给app分配的内存空间
         */
        int maxMemory = (int) Runtime.getRuntime().maxMemory();
        /**
         * 给图片分配合理的内容空间
         */
        int cacheSize = maxMemory / 8;
        mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
            @Override
            protected int sizeOf(String key, Bitmap bitmap) {
                return bitmap.getByteCount();
            }
        };
        mGridView.setOnScrollListener(this);
    }

    @Override
    public int getCount() {
        return Constant.imgs != null && Constant.imgs.length > 0 ? Constant.imgs.length : 0;
    }


    @Override
    public Object getItem(int position) {
        return Constant.imgs[position];
    }


    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup arg2) {
        final String url = (String) getItem(position);
        ViewHolder holder = null;
        if (convertView == null) {
            convertView = mInflater.inflate(R.layout.img_item, null);
            holder = new ViewHolder();
            holder.imageview = (ImageView) convertView.findViewById(R.id.imageview);
            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }
        /**
         * 给ImageView设置一个Tag,保证异步加载图片时不会乱序
         */
        holder.imageview.setTag(url);
        setImageView(url, holder.imageview);
        return convertView;
    }

    /**
     * 首先用url到缓存中找 如果没有就显示默认图片  如果缓存中有 就显示
     *
     * @param url 要显示图片的url
     * @param imageview
     */
    private void setImageView(String url, ImageView imageview) {
        Bitmap bitmap = mMemoryCache.get(url);
        if (bitmap != null && imageview != null) {
            imageview.setImageBitmap(bitmap);
        } else {
//            imageview.setImageResource(R.drawable.empty_photo);
        }
    }

    class ViewHolder {
        ImageView imageview;
    }

    /**
     * view  就是GridView
     * firstVisibleItem 可见 第一个条目
     * visibleItemCount 可见的总条目
     * totalItemCount 要加载的总条目
     */
    @Override
    public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
        mFirstVisibleItem = firstVisibleItem;
        mVisibleItemCount = visibleItemCount;
        if (mIsFirstLoader && visibleItemCount > 0) {
            loadImages(firstVisibleItem, visibleItemCount);
            mIsFirstLoader = false;
        }
    }

    @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        // 仅当GridView静止时才去下载图片,GridView滑动时取消所有正在下载的任务
        if (scrollState == SCROLL_STATE_IDLE) {
            loadImages(mFirstVisibleItem, mVisibleItemCount);
        } else {
            cancelAllTasks();
        }
    }

    private void cancelAllTasks() {
        if (mImageLoaderTasks != null) {
            for (ImageLoaderTask task : mImageLoaderTasks) {
                task.cancel(false);
            }
        }
    }

    private void loadImages(int firstVisibleItem, int visibleItemCount) {
        for (int i = firstVisibleItem; i < firstVisibleItem + visibleItemCount; i++) {
            String imagUrl = Constant.imgs[i];
            Bitmap bitmap = getBitmapFromMemory(imagUrl);
            if (bitmap == null) {//从网络获取
                ImageLoaderTask task = new ImageLoaderTask();
                mImageLoaderTasks.add(task);
                task.execute(imagUrl);
            } else {//从缓存获取
                ImageView imageView = (ImageView) mGridView.findViewWithTag(imagUrl);
                if (imageView != null && bitmap != null) {
                    imageView.setImageBitmap(bitmap);
                }
            }
        }
    }

    private Bitmap getBitmapFromMemory(String key) {
        return mMemoryCache.get(key);
    }

    private class ImageLoaderTask extends AsyncTask<String, Void, Bitmap> {
        String url = null;

        @Override
        protected Bitmap doInBackground(String... param) {
            url = param[0];
            /**
             * 从网络上加载的图片 如果bitmap不为null  就加载到内存之中
             */
            Bitmap bitmap = downLoadImage(url);
            if (bitmap != null) {
                // 图片下载完成后缓存到LrcCache中
                addBitmapToMemoryCache(url, bitmap);
            }
            return bitmap;
        }

        @Override
        protected void onPostExecute(Bitmap bitmap) {
            super.onPostExecute(bitmap);
            ImageView imageView = (ImageView) mGridView.findViewWithTag(url);
            if (imageView != null && bitmap != null) {
                imageView.setImageBitmap(bitmap);
            }
            /**
             * 下载完了以后把该任务从集合中移除  可能有些人会说为什么要用hashset集合  因为他可以的任务不重复
             */
            mImageLoaderTasks.remove(this);
        }
    }

    public Bitmap downLoadImage(String imgUrl) {
        Bitmap bitmap = null;
        HttpURLConnection connection = null;
        try {
            URL url = new URL(imgUrl);
            connection = (HttpURLConnection) url.openConnection();
            connection.setConnectTimeout(5 * 1000);
            connection.setReadTimeout(10 * 1000);
            connection.setDoInput(true);
            bitmap = BitmapFactory.decodeStream(connection.getInputStream());
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (connection != null) {
                connection.disconnect();
            }
        }
        return bitmap;

    }

    /**
     * 把图片加载到内存之中
     *
     * @param url    图片的url
     * @param bitmap url对应的图片
     */
    public void addBitmapToMemoryCache(String url, Bitmap bitmap) {
        if (getBitmapFromMemory(url) == null) {
            mMemoryCache.put(url, bitmap);
        }
    }
}
           

效果图:

Android照片墙的实现