一、概述
Android中异步加载图片的方式有俩种,此文通过从服务器取出的Json数据后,通过这俩种方式去加载服务器的图片数据。
二、案例描述:
三、实现编码思路
1、写布局
2、取到服务器的Json转成JavaBean保存在List中当数据源
3、在适配器中把数据源对应显示在ListView
4、在适配器显示图片时开启异步线程去服务器读取照片
5、图片缓存优化下
1、布局xml文件代码
就一个简单的ListView + 每一个Item的布局
ListView在主布局
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.kuxiao.tran.studyActivity.MainActivity">
<ListView
android:id="@+id/id_lv_news"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
每一个Item的布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:orientation="horizontal"
android:padding="4dp"
android:layout_height="wrap_content">
<ImageView
android:layout_marginLeft="5dp"
android:layout_width="64dp"
android:layout_height="64dp"
android:id="@+id/id_iv_icon"
android:src="@mipmap/ic_launcher"/>
<LinearLayout
android:layout_marginLeft="3dp"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_marginTop="5dp"
android:id="@+id/id_tv_title"
android:textSize="18dp"
android:text="标题"
android:paddingLeft="3dp"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:layout_marginTop="3dp"
android:id="@+id/id_tv_context"
android:textSize="15dp"
android:paddingLeft="4dp"
android:text="内容"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
2、取到服务器的Json转成JavaBean保存在List中当数据源
package com.kuxiao.tran.studyActivity;
import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.ListView;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.String;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private ListView mListView;
//访问服务器url
private static final String url_news = "http://172.46.159.87:8080/News/NewsAction";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mListView = (ListView) findViewById(R.id.id_lv_news);
new MyAsynctask().execute(url_news);
}
//利用异步线程访问服务取到数据源
class MyAsynctask extends AsyncTask<String, Void, List<NewsBean>> {
@Override
protected List<NewsBean> doInBackground(String... params) {
String url = params[0];
return getNewsBean(url);
}
@Override
protected void onPostExecute(List<NewsBean> newsBeans) {
MyAdapter myAdapter = new MyAdapter(MainActivity.this,newsBeans);
mListView.setAdapter(myAdapter);
}
}
//解析Json数据成NewsBean
private List<NewsBean> getNewsBean(String url) {
List<NewsBean> mList = new ArrayList<>();
InputStream mIs = null;
try {
URL mUrl = new URL(url);
mIs = mUrl.openStream();
String json = getJsonFromInputStream(mIs);
Log.i("text",json);
JSONObject jsonObject = new JSONObject(json);
JSONArray jsonArray = jsonObject.getJSONArray("data");
for (int i = 0; i <jsonArray.length();i++)
{
jsonObject = (JSONObject) jsonArray.get(i);
NewsBean newsBean = new NewsBean();
newsBean.setStr_context(jsonObject.getString("context"));
newsBean.setStr_icon(jsonObject.getString("Str_icon"));
newsBean.setStr_title(jsonObject.getString("title"));
mList.add(newsBean);
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
} catch (JSONException e) {
e.printStackTrace();
}
return mList;
}
//将流读取成Json字符串
private String getJsonFromInputStream(InputStream inputStream) {
String json = "";
String str;
InputStreamReader mIsr = new InputStreamReader(inputStream);
BufferedReader mBfr = new BufferedReader(mIsr);
try {
while (null != (str = mBfr.readLine())) {
json += str;
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
mBfr.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return json;
}
}
JavaBean代码
package com.kuxiao.tran.studyActivity;
public class NewsBean {
private String Str_title;
private String str_context;
private String str_icon;
public String getStr_title() {
return Str_title;
}
public void setStr_title(String str_title) {
Str_title = str_title;
}
public String getStr_icon() {
return str_icon;
}
public void setStr_icon(String str_icon) {
this.str_icon = str_icon;
}
public String getStr_context() {
return str_context;
}
public void setStr_context(String str_context) {
this.str_context = str_context;
}
}
3、在适配器中把数据源对应显示在ListView上
package com.kuxiao.tran.studyActivity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;
public class MyAdapter extends BaseAdapter {
private List<NewsBean> mList;//数据源
private LayoutInflater mInflater;//每一个item布局的转化
private BitmapCache mBitmapCache = null;//缓存
public MyAdapter(Context context, List<NewsBean> params) {
mInflater = LayoutInflater.from(context);
this.mList = params;
mBitmapCache = new BitmapCache();
}
@Override
public int getCount() {
return mList.size();
}
@Override
public Object getItem(int position) {
return mList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder mViewHolder;
//ListView的缓存机制中判断convertView是否存在
if (convertView == null) {
mViewHolder = new ViewHolder();
convertView = mInflater.inflate(R.layout.item, null);
mViewHolder.iv_icon = (ImageView) convertView.findViewById(R.id.id_iv_icon);
mViewHolder.tv_title = (TextView) convertView.findViewById(R.id.id_tv_title);
mViewHolder.tv_context = (TextView) convertView.findViewById(R.id.id_tv_context);
convertView.setTag(mViewHolder);
} else {
mViewHolder = (ViewHolder) convertView.getTag();
}
//给对应的viewHolder对象保存的控件赋值
mViewHolder.tv_context.setText(mList.get(position).getStr_context());
mViewHolder.tv_title.setText(mList.get(position).getStr_title());
new MyAsnyctask(mViewHolder.iv_icon, position,mBitmapCache).execute(mList.get(position).getStr_icon());
return convertView;
}
//利用ViewHolder对象避免重复的findViewById寻找控件的操作
class ViewHolder {
ImageView iv_icon;
TextView tv_context;
TextView tv_title;
}
}
4、在适配器显示图片时开启异步线程去服务器读取照片(第一种方式,利用Asynctask类)
在MyAdapter类中写一个内部类,代码如下
class MyAsnyctask extends AsyncTask<String, Void, Bitmap> {
private ImageView imageView;
private int position;
private static final String url = "http://172.46.159.87:8080/News/NewsImage/";
private BitmapCache mBitmapCache = null;
public MyAsnyctask(ImageView imageView, int position,BitmapCache mBitmapCache) {
this.imageView = imageView;
this.position = position;
imageView.setTag(this.position);
this.mBitmapCache = mBitmapCache;
}
@Override
protected Bitmap doInBackground(String... params) {
Bitmap bitmap;
if (mBitmapCache.getBitmap(this.position + "") == null) {
String imageName = params[0];
bitmap = getBitmap(imageName);
} else {
bitmap = mBitmapCache.getBitmap(position + "");
}
return bitmap;
}
//通过Url向服务器取图片
private Bitmap getBitmap(String imageName) {
Bitmap bitmap = null;
InputStream mIs = null;
try {
URL url = new URL(MyAsnyctask.url + imageName);
mIs = url.openStream();
bitmap = BitmapFactory.decodeStream(mIs);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
mIs.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return bitmap;
}
@Override
protected void onPostExecute(Bitmap bitmap) {
if (null != imageView && null != bitmap) {
if (imageView.getTag() == position) {
imageView.setImageBitmap(bitmap);
}
}
}
}
5、另一种方式使用Handller+子线线程的方式实现异步加载,代码如下
package com.kuxiao.tran.studyActivity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Message;
import android.widget.ImageView;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
public class ImageLoader extends Thread {
private ImageView mImageView;
private String mImageName;
private int position;
private static final String url = "http://172.46.130.144:8080/News/NewsImage/";
public ImageLoader(ImageView mImageView, String imageName, int position) {
this.mImageName = imageName;
this.mImageView = mImageView;
this.position = position;
}
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == 0) {
if (mImageView.getTag() == ImageLoader.this.position) {
Bitmap bitmap = (Bitmap) msg.obj;
mImageView.setImageBitmap(bitmap);
}
}
}
};
@Override
public void run() {
try {
URL url1 = new URL(url + mImageName);
HttpURLConnection urlConnection = (HttpURLConnection) url1.openConnection();
if (urlConnection.getResponseCode() == 200) {
InputStream mIs = url1.openStream();
Bitmap bitmap = BitmapFactory.decodeStream(mIs);
this.mImageView.setTag(this.position);
handler.obtainMessage(0, bitmap).sendToTarget();
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
6、利用BitmapCache类进行下缓存优化,代码如下
package com.kuxiao.tran.studyActivity;
import android.graphics.Bitmap;
import android.util.Log;
import android.util.LruCache;
public class BitmapCache {
private LruCache<String, Bitmap> mLruCache;
public BitmapCache() {
//获取最大运行时的最大内存
int max = (int) (Runtime.getRuntime().maxMemory() / 8);
mLruCache = new LruCache<String, Bitmap>(max) {
@Override
protected int sizeOf(String key, Bitmap value) {
//设置每一次缓存的大小
return value.getByteCount();
}
};
}
//缓存一个Bitmap对象
public void saveBitmap(String key, Bitmap value) {
mLruCache.put(key, value);
}
//取出一个Bitmap对象
public Bitmap getBitmap(String key) {
return mLruCache.get(key);
}
}
四、特别说明:本人大四的小白,自学的android编程,如有不妥之处,多谢指出,服务器端的代码我就不贴出来了,有需要的朋友可以联系我QQ:953751759,Json数据生成不懂的,可以看我博客中的Json数据生成。
上述中在给ImageView设置Tag的是用的ListView中的位置,并没有用照片的URL,是因为本人服务器生成的Json数据的照片的名字相同,图片只有一张,所以Url不适合设置成Tag,大家在练习的时候注意下。
作者:qq_15562815 发表于2016/12/13 17:23:24 原文链接
阅读:24 评论:0 查看评论