异步加载图片到GridView上,防止OOM

时间:2021-03-09 20:53:17

图片资源:

private int fore[];
private int back[];
fore = new int[]{R.drawable.a0, R.drawable.a1, R.drawable.a2,
				R.drawable.a3, R.drawable.a4, R.drawable.a5,
				R.drawable.a6, R.drawable.a7, R.drawable.a8,
				R.drawable.a9, R.drawable.a910, R.drawable.a911,
				R.drawable.a912, R.drawable.a913, R.drawable.a914};
back = new int[]{R.drawable.b0, R.drawable.b1, R.drawable.b2,
				R.drawable.b3, R.drawable.b4, R.drawable.b5,
				R.drawable.b6, R.drawable.b7, R.drawable.b8,
				R.drawable.b9, R.drawable.b910, R.drawable.b911,
				R.drawable.b912, R.drawable.b913, R.drawable.b914};
//用户保存加载的图片
private List<Bitmap> bitmapResource = new ArrayList<BitMap>();
GridView grid;//声明 图片显示 类似九宫格 的 控件
Handler handler; //声明 Handler 用来传递消息

计算方法:
int width = (int) (getWindowManager().getDefaultDisplay().getWidth()/density);//取得屏幕的宽度 
ImageResource ir = new ImageResource();
//使用getPicture()方法 加载图片
 public void getPicture(){
    	new AsyncTask<Object, Object, Object>() {//	进度条类 异步处理
			@Override
			protected Object doInBackground(Object... params) {//后台执行,比较耗时的操作都可以放在这里。
				publishProgress();//来更新任务的进度。
				loadingBitmap(getResources(), width, 3);//对图片进行缩放的方法 ,这里3为要显示的列数
				return null;
			}


			@Override
			protected void onPostExecute(Object result) {//在doInBackground 执行完成后,onPostExecute 方法将被UI thread调用,后台的计算结果将通过该方法传递到UI thread. 
				handler.removeCallbacks(update);//removeCallbacks方法是删除指定的Runnable对象,使线程对象停止运行。
				message.setVisibility(View.GONE);//message设置为不可见
				author_message.setVisibility(View.GONE);//author_message设置为不可见
				grid.setVisibility(View.VISIBLE);//grid设置为可见
				grid.setNumColumns(3);//设置GridView的列数
				grid.setHorizontalSpacing(20);//两列之间的间距
				grid.setVerticalSpacing(40);//两行之间的间距
				grid.setAdapter(adapter);//使用适配器
				grid.setOnItemClickListener(new OnItemClickListener() {//GridView 的监听器
					
					public void onItemClick(AdapterView<?> arg0, View arg1,
							int position, long arg3) {
						Intent intent = new Intent();//实例化Intent
						intent.setClass(MenuActivity.this, ShowActivity.class);//设置跳转路径
						Bundle bundle = new Bundle();//实例化Bundle类 传值
						bundle.putInt("num",position);//传 列表的 位置值 到ShowActivity
						intent.putExtras(bundle);//intent发送Bundle
						MenuActivity.this.startActivity(intent);//开始跳转
					}
				});
				adapter.notifyDataSetChanged();//在adapter的数据发生变化以后通知UI主线程根据新的数据重新画图。
				super.onPostExecute(result);
			}


			
			protected void onProgressUpdate(Object... values) {//在publishProgress方法被调用后,UI thread将调用这个方法从而在界面上展示任务的进展情况
				
				handler = new Handler();//实例化handler
				//显示加载进度
				handler.post(update);//根据线程来更新进度
				
				super.onProgressUpdate(values);
			}
		}.execute();//执行 异步操作
    }

public void loadingBitmap(Resources resources, int width, int num){


		BitmapFactory.Options opts = new BitmapFactory.Options();//BitmapFactory.Options这个类
		//仅返回图片的 宽高  这样就不会占用太多的内存,也就不会那么频繁的发生OOM了。
		opts.inJustDecodeBounds = true;//该值设为true那么将不返回实际的bitmap对象,不给其分配内存空间但是可以得到一些解码边界信息即图片大小等信息。
		Bitmap temp = BitmapFactory.decodeResource(resources, fore[0], opts);//加载图片 缩放 从fore【】中第一位开始
		int radio = (int) Math.ceil(opts.outWidth / (width*1.0 / num - 30));//向上取整 结果是7,得到缩放比例radio
		//Math.ceil(12.2)//返回13
		//Math.ceil(12.7)//返回13
		//Math.ceil(12.0)// 返回12
		opts.inSampleSize = radio;//属性值inSampleSize表示缩略图大小为原始图片大小的几分之一
		if(null != temp){
			temp.recycle();//回收
		}
		System.out.println(radio);
		
		opts.inJustDecodeBounds = false;//inJustDecodeBounds设为false,就可以根据已经得到的缩放比例得到自己想要的图片缩放图了。
		
		for(int i = 0; i < fore.length; i++){
			Bitmap bitmap = BitmapFactory.decodeResource(resources, fore[i], opts);//载入图片
			bitmapResource.add(bitmap);//循环添加到集合中
		}
	}
使用适配器:
 BaseAdapter adapter = new BaseAdapter() {
		
		
		public View getView(int position, View convertView, ViewGroup parent) {
			ImageView iv = new ImageView(MenuActivity.this);//显示任意图像
			iv.setMaxWidth(width / 3 - 30);//设置宽度
			iv.setAdjustViewBounds(true);//是否保持宽高比
			iv.setImageBitmap(ir.getIconBitmap(position));//设置图片 使用ImageResource类中集合当中的图片
			return iv;
		}
		
		@Override
		public long getItemId(int position) {//得到ID
			return position;
		}
		
		@Override
		public Object getItem(int arg0) {//得到位置
			return arg0;
		}
		
		@Override
		public int getCount() {//得到大小
			return ir.size();
		}
	};
Runnable update = new Runnable() {//实例化线程
		@Override
		public void run() {
			int progress = ir.getProgress();//得到文件的总大小
			if(null != message){
				message.setText("数据加载中("+progress+"%),请稍等……\n\n");//如果message不是空,就让显示文本
			}
			if(100 == progress){
				handler.removeCallbacks(update);//等于100 也即是说 加载完毕 就停止线程,也就是关闭此定时器
			} else {
				handler.postDelayed(update, 200);//使用PostDelayed方法,两秒后调用此Runnable对象,实际上也就实现了一个0.2s的一个定时器
			}
		}
	};