Android照片墙应用实现,再多的图片也不怕崩溃(2)

图片源已经有了,现在我们就该考虑在哪里放置这些图片了。新建或打开activity_main.xml作为程序的主布局,加入如下代码:

<LinearLayout xmlns:Android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" >
 
    <GridView
        android:id="@+id/photo_wall"
        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>
   
</LinearLayout>

可以看到,我们在这个布局文件中仅加入了一个GridView,这也就是我们程序中的“墙”,所有的图片都将贴在这个“墙”上。

接着我们定义GridView中每一个子View的布局,新建一个photo_layout.xml布局,加入如下代码:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content" >

<ImageView
        android:id="@+id/photo"
        android:layout_width="90dip"
        android:layout_height="90dip"
        android:src="@drawable/empty_photo"
        android:layout_centerInParent="true"
        />

</RelativeLayout>

在每一个子View中我们就简单使用了一个ImageView来显示一张图片。这样所有的布局就已经定义好了。

接下来新建PhotoWallAdapter做为GridView的适配器,代码如下所示:

public class PhotoWallAdapter extends ArrayAdapter<String> implements OnScrollListener {

/**
  * 记录所有正在下载或等待下载的任务。
  */
 private Set<BitmapWorkerTask> taskCollection;

/**
  * 图片缓存技术的核心类,用于缓存所有下载好的图片,在程序内存达到设定值时会将最少最近使用的图片移除掉。
  */
 private LruCache<String, Bitmap> mMemoryCache;

/**
  * GridView的实例
  */
 private GridView mPhotoWall;

/**
  * 第一张可见图片的下标
  */
 private int mFirstVisibleItem;

/**
  * 一屏有多少张图片可见
  */
 private int mVisibleItemCount;

/**
  * 记录是否刚打开程序,用于解决进入程序不滚动屏幕,不会下载图片的问题。
  */
 private boolean isFirstEnter = true;

public PhotoWallAdapter(Context context, int textViewResourceId, String[] objects,
   GridView photoWall) {
  super(context, textViewResourceId, objects);
  mPhotoWall = photoWall;
  taskCollection = new HashSet<BitmapWorkerTask>();
  // 获取应用程序最大可用内存
  int maxMemory = (int) Runtime.getRuntime().maxMemory();
  int cacheSize = maxMemory / 8;
  // 设置图片缓存大小为程序最大可用内存的1/8
  mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
   @Override
   protected int sizeOf(String key, Bitmap bitmap) {
    return bitmap.getByteCount();
   }
  };
  mPhotoWall.setOnScrollListener(this);
 }

@Override
 public View getView(int position, View convertView, ViewGroup parent) {
  final String url = getItem(position);
  View view;
  if (convertView == null) {
   view = LayoutInflater.from(getContext()).inflate(R.layout.photo_layout, null);
  } else {
   view = convertView;
  }
  final ImageView photo = (ImageView) view.findViewById(R.id.photo);
  // 给ImageView设置一个Tag,保证异步加载图片时不会乱序
  photo.setTag(url);
  setImageView(url, photo);
  return view;
 }

/**
  * 给ImageView设置图片。首先从LruCache中取出图片的缓存,设置到ImageView上。如果LruCache中没有该图片的缓存,
  * 就给ImageView设置一张默认图片。
  *
  * @param imageUrl
  *            图片的URL地址,用于作为LruCache的键。
  * @param imageView
  *            用于显示图片的控件。
  */
 private void setImageView(String imageUrl, ImageView imageView) {
  Bitmap bitmap = getBitmapFromMemoryCache(imageUrl);
  if (bitmap != null) {
   imageView.setImageBitmap(bitmap);
  } else {
   imageView.setImageResource(R.drawable.empty_photo);
  }
 }

/**
  * 将一张图片存储到LruCache中。
  *
  * @param key
  *            LruCache的键,这里传入图片的URL地址。
  * @param bitmap
  *            LruCache的键,这里传入从网络上下载的Bitmap对象。
  */
 public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
  if (getBitmapFromMemoryCache(key) == null) {
   mMemoryCache.put(key, bitmap);
  }
 }

/**
  * 从LruCache中获取一张图片,如果不存在就返回null。
  *
  * @param key
  *            LruCache的键,这里传入图片的URL地址。
  * @return 对应传入键的Bitmap对象,或者null。
  */
 public Bitmap getBitmapFromMemoryCache(String key) {
  return mMemoryCache.get(key);
 }

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

@Override
 public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
   int totalItemCount) {
  mFirstVisibleItem = firstVisibleItem;
  mVisibleItemCount = visibleItemCount;
  // 下载的任务应该由onScrollStateChanged里调用,但首次进入程序时onScrollStateChanged并不会调用,
  // 因此在这里为首次进入程序开启下载任务。
  if (isFirstEnter && visibleItemCount > 0) {
   loadBitmaps(firstVisibleItem, visibleItemCount);
   isFirstEnter = false;
  }
 }

/**
  * 加载Bitmap对象。此方法会在LruCache中检查所有屏幕中可见的ImageView的Bitmap对象,
  * 如果发现任何一个ImageView的Bitmap对象不在缓存中,就会开启异步线程去下载图片。
  *
  * @param firstVisibleItem
  *            第一个可见的ImageView的下标
  * @param visibleItemCount
  *            屏幕中总共可见的元素数
  */
 private void loadBitmaps(int firstVisibleItem, int visibleItemCount) {
  try {
   for (int i = firstVisibleItem; i < firstVisibleItem + visibleItemCount; i++) {
    String imageUrl = Images.imageThumbUrls[i];
    Bitmap bitmap = getBitmapFromMemoryCache(imageUrl);
    if (bitmap == null) {
     BitmapWorkerTask task = new BitmapWorkerTask();
     taskCollection.add(task);
     task.execute(imageUrl);
    } else {
     ImageView imageView = (ImageView) mPhotoWall.findViewWithTag(imageUrl);
     if (imageView != null && bitmap != null) {
      imageView.setImageBitmap(bitmap);
     }
    }
   }
  } catch (Exception e) {
   e.printStackTrace();
  }
 }

/**
  * 取消所有正在下载或等待下载的任务。
  */
 public void cancelAllTasks() {
  if (taskCollection != null) {
   for (BitmapWorkerTask task : taskCollection) {
    task.cancel(false);
   }
  }
 }

/**
  * 异步下载图片的任务。
  *
  * @author guolin
  */
 class BitmapWorkerTask extends AsyncTask<String, Void, Bitmap> {

/**
  * 图片的URL地址
  */
  private String imageUrl;

@Override
  protected Bitmap doInBackground(String... params) {
   imageUrl = params[0];
   // 在后台开始下载图片
   Bitmap bitmap = downloadBitmap(params[0]);
   if (bitmap != null) {
    // 图片下载完成后缓存到LrcCache中
    addBitmapToMemoryCache(params[0], bitmap);
   }
   return bitmap;
  }

@Override
  protected void onPostExecute(Bitmap bitmap) {
   super.onPostExecute(bitmap);
   // 根据Tag找到相应的ImageView控件,将下载好的图片显示出来。
   ImageView imageView = (ImageView) mPhotoWall.findViewWithTag(imageUrl);
   if (imageView != null && bitmap != null) {
    imageView.setImageBitmap(bitmap);
   }
   taskCollection.remove(this);
  }

/**
  * 建立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);
    con.setDoInput(true);
    con.setDoOutput(true);
    bitmap = BitmapFactory.decodeStream(con.getInputStream());
   } catch (Exception e) {
    e.printStackTrace();
   } finally {
    if (con != null) {
     con.disconnect();
    }
   }
   return bitmap;
  }

}

}

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/f5458f79f93c5965d28c81d5882b09ec.html