大家好 我是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.youkuaiyun.com/detail/mtgodd/8091087
http://download.youkuaiyun.com/detail/mtgodd/8091097