«

android 手把手教你照片墙应用实现,再多的图片也不怕OOM

时间:2024-3-2 17:25     作者:韩俊     分类: Android


今天讲一个照片墙的应用,这个在去年还算是比较流行的,现在不忙,也准备简单的实现以下,之所以说是照片墙是好像图片加载出来后贴上去的感觉,这个用GridView控件,然后加载出来的图片放上去即可!


实现原理:

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

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

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


在这些例子中使用到了很多图片,这些图片都是我从豆瓣网上辛苦的搞过来的,copy也是体力活啊,不容易,给自己点个赞

首先看下activity_main.xml 很简单就一个GridView控件

<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"
 >
   <GridView 
        android:id="@+id/gv"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:columnWidth="90dip"
        android:stretchMode="columnWidth"
        android:numColumns="auto_fit"
        android:verticalSpacing="10dip"
        android:gravity="center"
        ></GridView>
</RelativeLayout>

Constan.java存放图片

package com.example.zgzphotodemo;
public class Constan {
    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"
    };
}

具体的业务逻辑全部在ImageLoadAdapter中

package com.example.zgzphotodemo.adapter;
import java.io.IOException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashSet;
import java.util.Set;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.support.v4.util.LruCache;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.BaseAdapter;
import android.widget.GridView;
import android.widget.ImageView;
import com.example.zgzphotodemo.Constan;
import com.example.zgzphotodemo.R;
public class ImageLoadAdapter extends BaseAdapter implements OnScrollListener {
private Activity activity;
private GridView gv;
private LayoutInflater inflater;
/**
* 图片缓存技术的核心类,用于缓存所有下载好的图片,在程序内存达到设定值时会将最少最近使用的图片移除掉。
*/
private LruCache<String, Bitmap> mMemoryCache;
/**
* 记录所有正在下载或等待下载的任务。
*/
private Set<ImageLoadTask> imageLoadTasks;
/**
* 第一张可见图片的下标
*/
private int mFirstVisibleItem;
/**
* 可见区域一屏有多少张图片
*/
private int mVisibleItemCount;
/**
* 代表第一次进来不滑动的时候自动加载图片
*/
private boolean isFirstLoad = true;


public ImageLoadAdapter(GridView gv,Activity activity){
this.activity = activity;
this.gv = gv;
inflater = LayoutInflater.from(activity);
imageLoadTasks = new HashSet<ImageLoadAdapter.ImageLoadTask>();
/**
* 获取应用给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();
}
};
gv.setOnScrollListener(this);
}
@Override
public int getCount() {
return Constan.imgs!=null&&Constan.imgs.length>0?Constan.imgs.length:0;
}


@Override
public Object getItem(int position) {
return Constan.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 = inflater.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 (isFirstLoad && visibleItemCount > 0) {
loadImages(firstVisibleItem, visibleItemCount);
isFirstLoad = 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 (imageLoadTasks != null) {
for (ImageLoadTask task : imageLoadTasks) {
task.cancel(false);
}
}
}
private void loadImages(int firstVisibleItem, int visibleItemCount) {
for(int i=firstVisibleItem;i<firstVisibleItem+visibleItemCount;i++){
String imagUrl = Constan.imgs[i];
Bitmap bitmap = getBitmapFromMemory(imagUrl);
if(bitmap==null){//从网络获取
ImageLoadTask task = new ImageLoadTask();
imageLoadTasks.add(task);
task.execute(imagUrl);
}else{//从缓存获取
ImageView imageView = (ImageView) gv.findViewWithTag(imagUrl);
if (imageView != null && bitmap != null) {
imageView.setImageBitmap(bitmap);
}
}
}
}
private Bitmap getBitmapFromMemory(String key) {
return mMemoryCache.get(key);
}

class ImageLoadTask 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) gv.findViewWithTag(url);
if (imageView != null && bitmap != null) {
imageView.setImageBitmap(bitmap);
}
/**
* 下载完了以后把该任务从集合中移除 可能有些人会说为什么要用hashset集合 因为他可以的任务不重复
*/
imageLoadTasks.remove(this);
}
}
public Bitmap downLoadImage(String imgUrl) {
Bitmap bitmap = null;
HttpURLConnection conn = null;
try {
URL url = new URL(imgUrl);
conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5 * 1000);
conn.setReadTimeout(10 * 1000);
conn.setDoInput(true);
bitmap = BitmapFactory.decodeStream(conn.getInputStream());
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
if (conn != null) {
conn.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

热门推荐