学习andriod开发之 自己动手写图片查看器(三)

        大家好 我是akira 上一讲 我们说了如何网络加载大图防止其oom也就是内存溢出的一种简单方式

这也是面试经常问到的问题 这一次我们首先要对代码进行重构 其次完成进度条的调整 最后引用目前最火的框架ImageLoader来看看它

加载到底怎么做 好的废话不多说开始今天的学习.

        首先还是上次的代码 代码我已经上传过了这次要进行一部分的调整

首先主活动

     

public class MainActivity extends Activity {

	protected static final int GETPIC = 0;
	protected static final String TAG = "AKIRA";
	private static final int CACHE = 1;
	
	private ImageView pic;
	private TextView name;
	private EditText et_address;
	private Button bt_load;
	private String path;
	private Context ct = MainActivity.this;
	
	private Handler mHandler = new Handler(){
		public void handleMessage(android.os.Message msg) {
			
			switch (msg.what) {
			case GETPIC:
				//已经拿到图片
				Bitmap bit = (Bitmap) msg.obj;
				name.setText(getPicName(path));
				ProgressBarUtils.hidePro(rl);
				showToast(MainActivity.this, "成功获取", Toast.LENGTH_SHORT);
				pic.setImageBitmap(bit);
				break;
			case CACHE:
				//已经拿到图片
				name.setText(getPicName(path));
//				ProgressBarUtils.hidePro(rl);
				break;

			default:
				break;
			}
			
		};
		
		
	};
	private File file;
//	private Button bt_next;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		findview();
		setListener();
		
			
	}
	
	private void setListener() {
		bt_load.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				path = et_address.getText().toString().trim();
				if(path.equals("")){
					showToast(MainActivity.this, "输入不能为空!", Toast.LENGTH_SHORT);
					return;
				}
				loadData(path);
				
			}
		});
		/*bt_next.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				startActivity(new Intent(MainActivity.this, SmartAct.class));
				
			}
		});*/
		
	}
	Bitmap smallbit ;
	/**
	 * 加载数据(关键方法)
	 * @param path
	 */
	private void loadData(final String path) {
		 if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
		 file = new File(Environment.getExternalStorageDirectory(),getPicName(path));
		    if(file.exists()){
		    	pic.setImageURI(Uri.fromFile(file));
		    	Message msg = Message.obtain();
		 		msg.what = CACHE;
		 		mHandler.sendEmptyMessageAtTime(CACHE, 0);
	    	}
		 	else{
		 		if(smallbit==null)
		 		smallbit = BitMapUtils.downloadPic(ct, path, pic.getHeight(), pic.getWidth(),file);
		 		ProgressBarUtils.showPro(ct, rl);
		 		try {
				Message msg = Message.obtain();
		 		msg.obj =smallbit;
		 		msg.what = GETPIC;
		 		mHandler.sendMessage(msg);
				} catch (Exception e) {
					e.printStackTrace();
				}
		 	}
		 }
		
	
	}
	
	
	

	private void findview() {
		pic = (ImageView) findViewById(R.id.pic);
		name = (TextView) findViewById(R.id.name);
		et_address = (EditText) findViewById(R.id.et_address);
		bt_load = (Button) findViewById(R.id.bt_load);
		rl = (RelativeLayout) findViewById(R.id.rl);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.activity_main, menu);
		return true;
	}
	
	public void showToast(Context ct,String text,int duration){
		
		Toast.makeText(ct, text, duration).show();
	}
	/**
	 * 得到图片名字
	 * @param path
	 * @return
	 */
	private String getPicName(String path){
		String newpath = path.substring(path.lastIndexOf("/")+1);
		if(newpath.length()>=8){
			newpath = newpath.substring(8, newpath.length());
		}
		return newpath;
	}
	
	private RelativeLayout rl;
	
	

}
这里 关键方法仍然是loadData 我们看到 这次利用自定义的工具类来完成下载和压缩情况 

其他的代码分别也没什么好说的 

OK 来看下bitmap工具类代码

public class BitMapUtils {
	
	


	/**
	 * 下载
	 * @param path
	 */
	private static Bitmap bits;
		
	public static Bitmap downloadPic(final Context ct, final String path,final int ivHeight,final int ivWidth,final File file){
		
		new Thread(){
			public void run() {
				try {
					HttpClient client = new DefaultHttpClient();
					HttpGet get = new HttpGet(path);
					HttpResponse httpResponse = client.execute(get);
					if(httpResponse.getStatusLine().getStatusCode()==200){
						InputStream is = httpResponse.getEntity().getContent();
					bits = scalePic(is, ivHeight, ivWidth);
					OutputStream os = new FileOutputStream(file);
					bits.compress(CompressFormat.JPEG, 100, os);
					}
					} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
			};
			
		}.start();
		return bits;
		
	}
	
	
	/**
	 * 缩放
	 * @param is
	 * @param imageHeight
	 * @param imageWidth
	 * @return
	 */
	private static Bitmap scalePic(InputStream is, int imageHeight, int imageWidth){
		Options opts = new Options();
		opts.inJustDecodeBounds = true;
        opts.outHeight = imageHeight;
        opts.outWidth = imageWidth;
        opts.inSampleSize =4;// 16分之一
        opts.inJustDecodeBounds = false;
		Bitmap smallbit = BitmapFactory.decodeStream(is, null, opts);
		return smallbit;
	}

}

这里我把下载和压缩都放到了这里 而值分别作为参数传进来 

好的 再看下进度条工具类代码

public class ProgressBarUtils {
	
	private static ProgressBar pb;

	public static void showPro(Context ct,ViewGroup vg){
		if(pb==null){
		pb = new ProgressBar(ct);
		vg.addView(pb);
		pb.setVisibility(View.VISIBLE);
		}
		
	
	}
	
	public static void hidePro(ViewGroup vg){
		pb.setVisibility(View.GONE);
		vg.removeView(pb);
		pb=null;
	}

}

一目了然 我们利用MVC思想 干净的完成了解耦 


进度条的调整

由于 前面的进度条看起来不是那么完美 这次我们进行部分调整

首先 这次不new进度条 去布局里加载一个 改动布局文件

  <FrameLayout 
        android:layout_width="match_parent"
        android:layout_height="300dp"
        >
       <ImageView 
        android:id="@+id/pic"
        android:layout_width="match_parent"
        android:layout_height="300dp"
        android:contentDescription="@null"
        />
       <ProgressBar 
           android:visibility="gone"
            android:id="@+id/mypro"
        	android:layout_width="30dp"
        	android:layout_height="30dp"
        	android:layout_gravity="center"
        	android:indeterminate="false"
       	 	android:indeterminateDrawable="@drawable/myloading"
         />
       <TextView 
           android:visibility="gone"
           android:id="@+id/tv_load"
          android:layout_gravity="center_horizontal|center_vertical"
          android:layout_marginTop="50dp"
           android:layout_width="wrap_content"
           android:layout_height="wrap_content"
           android:text="加载中..."
           />
    </FrameLayout>

这里我引用了一个帧布局 控制进度条的是一个indeterminateDrawble 里面是加载了一个动画的 

当然也是帧动画 

看下帧动画的代码

<?xml version="1.0" encoding="UTF-8"?>
<animation-list
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:oneshot="false">
    <item
        android:duration="100"
        android:drawable="@drawable/loading_01" />
    <item
        android:duration="100"
        android:drawable="@drawable/loading_02" />
    <item
        android:duration="100"
        android:drawable="@drawable/loading_03" />
    <item
        android:duration="100"
        android:drawable="@drawable/loading_04" />
    <item
        android:duration="100"
        android:drawable="@drawable/loading_05" />
    <item
        android:duration="100"
        android:drawable="@drawable/loading_06" />
    <item
        android:duration="100"
        android:drawable="@drawable/loading_07" />
</animation-list>

因为每个帧动画都是animationlist嵌套item的形式 这里的oneshot表示是否循环 true的话是只有一次播放的 

因为我们不知道用户的网速快慢 所以是false drawable就是引用的图 duration就是播放时长 

好的 然后我们去引用progressbar就可以 

改动的无非是findview和在下载图的时候 setVisible 过于简单就不看了

  

最后介绍一个框架 imageLoader 

我们看看怎么用 

新建一个工程

首先 找到githup上 imageLoader的压缩包

https://github.com/nostra13/Android-Universal-Image-Loader

选择


下载解压完之后 在download文件夹中找到 

universal-image-loader-1.9.3.jar 

然后就是喜闻乐见的buildpath 

加载好jar之后 我们就可以使用imageLoader了 

这里 我们布局文件就不看了 

看下主代码 首先你要知道 用imageLoader之前 官方教程要在application中

完成初始化操作 我们看下application的代码

public class MyApplication extends Application {
	
	@Override
	public void onCreate() {
		// TODO Auto-generated method stub
		super.onCreate();
		ImageLoaderConfiguration configuration = ImageLoaderConfiguration.createDefault(getApplicationContext());
		ImageLoader.getInstance().init(configuration);
	}

}

已经简单到不行 getIntance你是不是很熟悉?  没错我们在单例模式中也看到过 拿到对象初始化 

看下主活动的代码

public class MainActivity extends Activity {

	private ImageView pic;
	private Button bt_load;
	private String url = "http://pic10.nipic.com/20101007/5917874_083244018622_2.jpg";
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		findview();
		setListener();
	}

	private void setListener() {
		bt_load.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				DisplayImageOptions opts = new DisplayImageOptions.Builder()
				.showImageOnLoading(R.drawable.ic_launcher).cacheInMemory(true).cacheOnDisc(true).bitmapConfig(Config.ARGB_8888).build();
				ImageLoader.getInstance().displayImage(url, pic, opts);
			}
		});
		
	}

	private void findview() {
		pic = (ImageView) findViewById(R.id.pic);
		bt_load = (Button) findViewById(R.id.bt_load);
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.activity_main, menu);
		return true;
	}

}

这里核心代码都在 onclick中 首先跟bitmap一样 拿到options 利用Builder方法 然后

设置正在加载图片 showImageOnLoading 当然你也可以利用上面的进度条 这里我就偷了个懒 

其次就是缓存内存和硬盘 最后设置config 我这里设置8888的 用build方法创造出来 

最后利用displayXXX传入url 图 和options即可 

别忘了清单文件的application节点中加入name

android:name="com.akira.picimageloader.app.MyApplication"

以及两个权限

 <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

看下最后的效果

小图


 

大图


至此关于图片部分先高一段落 然而imageLoader的用法远不止这么少 

它的强大之处 后期咱继续讲 

本期代码下载

http://download.csdn.net/detail/mtgodd/8091087

http://download.csdn.net/detail/mtgodd/8091097


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值