前言
近日需要在安卓上面显示图片,于是查了一些资料,下面可以参考一下:
Android高效显示图片详解(一)
Android高效显示图片详解(二)
Android高效显示图片详解(三)
但是问题在于,这个不是很科学,不踩一下坑不心熄,于是就有了这个文章。
使用原始方式加载显示本地图片列表
xml文件:imgtest_localimages.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="请选择要显示的图片"/>
<Spinner android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/spinner_images">
</Spinner>
<Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="添加图片" android:id="@+id/btn_append_img"/>
<ScrollView android:layout_width="fill_parent" android:layout_height="wrap_content">
<LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="vertical" android:id="@+id/img_list"></LinearLayout>
</ScrollView>
</LinearLayout>
java后台代码:imgtest_localImages.java
package com.example.MyStudyAndroid;
import android.app.Activity;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Bundle;
import android.provider.MediaStore;
import android.util.Log;
import android.view.View;
import android.widget.*;
import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* Created by Administrator on 2015/6/30.
*/
public class imgtest_localImages extends Activity {
List<String> _imageList;
private Spinner spinner_images;
private Button btn_append_img;
private LinearLayout layout_imglist;
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.imgtest_localimages);
initUI();
initEvents();
initDatas();
}
private void initUI(){
spinner_images=(Spinner)findViewById(R.id.spinner_images);
btn_append_img=(Button)findViewById(R.id.btn_append_img);
layout_imglist=(LinearLayout)findViewById(R.id.img_list);
}
private void initEvents(){
final BitmapFactory.Options bf_opts = new BitmapFactory.Options();
bf_opts.inJustDecodeBounds = true;
//BitmapFactory.decodeFile("/sdcard/picturetest/a1.jpg", opts);
//bf_opts.inSampleSize = computeSampleSize(opts, -1, 480*800);
bf_opts.inJustDecodeBounds = false;
btn_append_img.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
try{
String imgpath=_imageList.get(spinner_images.getSelectedItemPosition());
ImageView imageView=new ImageView(view.getContext());
Bitmap bmp1 = BitmapFactory.decodeFile(imgpath, bf_opts);
layout_imglist.addView(imageView);
imageView.setImageBitmap(bmp1);
} catch (OutOfMemoryError err) {
Toast.makeText(imgtest_localImages.this,err.toString(),Toast.LENGTH_SHORT);
}
}
});
}
private void initDatas(){
_imageList=scanImages();
_imageList=_imageList.subList(0,50);
ArrayAdapter adpt_chooser=new ArrayAdapter(this,android.R.layout.simple_spinner_item,_imageList);
spinner_images.setAdapter(adpt_chooser);
spinner_images.setOnItemSelectedListener(new Spinner.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int i, long l) {
String path=_imageList.get(i);
Log.e("fffffff","选择了:"+path);
}
@Override
public void onNothingSelected(AdapterView<?> adapterView) {
Log.e("xxxx","没有选中任何东西。");
}
});
}
//--浏览本地文件。
private List<String> scanImages()
{
List<String> _imgInfos=new ArrayList<String>();
HashMap<String,List<String>> imgInfos=new HashMap<String, List<String>>();
Uri mImageUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
//Uri.parse("content://media/internal/images");
String[] columns=new String[]{"*"};
Cursor cur = managedQuery(mImageUri,columns,MediaStore.Images.Media.MIME_TYPE + "=? or "
+ MediaStore.Images.Media.MIME_TYPE + "=?",
new String[] { "image/jpeg", "image/png" }, MediaStore.Images.Media.DATE_MODIFIED);
if(cur==null){
return _imgInfos;
}
while (cur.moveToNext()){
String imgPath=cur.getString(cur.getColumnIndex(MediaStore.Images.Media.DATA));
String parentName=new File(imgPath).getParentFile().getName();
if(imgInfos.containsKey(parentName)){
List<String> childList=imgInfos.get(parentName);
childList.add(imgPath);
}
else{
ArrayList<String> childList=new ArrayList<String>();
childList.add(imgPath);
imgInfos.put(parentName,childList);
}
_imgInfos.add(imgPath);
}
cur.close();
return _imgInfos;
}
}
大家可以试试不停选择任意一张图片不停添加图片,反正我这边会报错,而且假如图片大的话,会有卡顿现象:
结论
安卓程序里面的内存是有限的,没办法无限加载图片,这跟网页不一样,而且app里面加载图片会有卡顿现象,现在一种比较好的设想是,加载到图片时候或什么的,先给一张默认图片,然后另外开一个现成慢慢拉取图片,这样才比较好。
使用原始方式加载远程图片列表
上面用本地图片加载起来看了效果,发现卡顿及内存溢出的问题,那么,现在批量加载显示网上的远程图片看看效果。–这里先随便加载几个图片,不需要特意弄内存溢出了。
遗憾的是,测试得到的结果是报错,没办法重现阻塞ui线程的现象,这里说明一下,在4.0以后在主线程使用http请求都会出这种错。
代码内容如下
imgtest_remoteimages.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="下面是远程列表图片。"/>
<ScrollView android:layout_width="fill_parent" android:layout_height="wrap_content">
<LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="vertical" android:id="@+id/panel_imgList">
</LinearLayout>
</ScrollView>
</LinearLayout>
对应后台java文件
package com.example.MyStudyAndroid;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.util.Log;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Toast;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
/**
* Created by Administrator on 2015/6/30.
*/
public class imgtest_remoteImages extends Activity {
private LinearLayout panel_imgList;
final BitmapFactory.Options bf_opts = new BitmapFactory.Options();
@Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView(R.layout.imgtest_remoteimages);
initUI();
initEvents();
bf_opts.inJustDecodeBounds = false;
fetchRemoteImages();
}
private void initUI(){
panel_imgList=(LinearLayout)findViewById(R.id.panel_imgList);
}
private void initEvents(){}
private void fetchRemoteImages(){
appendRemoteImage("http://news.9duw.com/UploadPic/2013-4/201342922121240199.jpg");
}
public void appendRemoteImage(String path) {
try{
String imgpath=path;
ImageView imageView=new ImageView(this);
byte[] imgbytes=getimage(path);
Bitmap bmp1 = BitmapFactory.decodeByteArray(imgbytes,0,imgbytes.length,bf_opts);
panel_imgList.addView(imageView);
imageView.setImageBitmap(bmp1);
} catch (Exception err) {
err.printStackTrace();
Toast.makeText(this, err.toString(), Toast.LENGTH_SHORT).show();
}
}
public byte[] getimage(String path) throws Exception{ //连接远程网址
URL url=new URL(path);
HttpURLConnection conn=(HttpURLConnection) url.openConnection();
conn.setConnectTimeout(5000);
conn.setRequestMethod("GET");
if(conn.getResponseCode()==200){
InputStream instream=conn.getInputStream();
return read(instream);
}
return null;
}
private byte[] read(InputStream instream) throws Exception{ // 读取数据流,返回字节数据流
ByteArrayOutputStream outstream=new ByteArrayOutputStream();
byte[] buffer=new byte[1024];
while( (instream.read(buffer))!=-1){
outstream.write(buffer);
}
instream.close();
return outstream.toByteArray();
}
}
结论
看来,另开线程下载图片文件,然后将图片缓存到本地也是必须的。
改进图片图片列表的加载方式
改进方式有点多,下一篇详细说明。