//布局
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
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"
tools:context="com.example.wz.cachedemo.MainActivity">
<me.maxwin.view.XListView
android:id="@+id/xlistview"
android:layout_width="match_parent"
android:layout_height="match_parent">
</me.maxwin.view.XListView>
</LinearLayout>
//布局2
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<ImageView
android:id="@+id/image"
android:layout_width="0dp"
android:layout_height="80dp"
android:layout_weight="1"
android:src="@mipmap/ic_launcher"/>
<LinearLayout
android:layout_width="0dp"
android:layout_weight="2"
android:layout_height="80dp"
android:orientation="vertical">
<TextView
android:id="@+id/name"
android:layout_width="match_parent"
android:layout_height="50dp"
android:textSize="20sp"
android:gravity="center_vertical"
android:text="123"/>
<TextView
android:id="@+id/desc"
android:layout_width="match_parent"
android:layout_height="30dp"
android:maxLines="1"
android:textSize="14sp"
android:gravity="center_vertical"
android:text="123"/>
</LinearLayout>
</LinearLayout>
//MainActivity
package com.example.wz.cachedemo;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import com.google.gson.Gson;
import Java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import me.maxwin.view.XListView;
public class MainActivity extends AppCompatActivity implements XListView.IXListViewListener{
private XListView mXListView;
private String urlPath="http://www.yulin520.com/a2a/impressApi/news/" +
"mergeList?sign=C7548DE604BCB8A17592EFB9006F9265&pageSize=200&gender=2" +
"&ts=1871746850&page=";
private int page = 1;
private List<Data.DataBean> list=new ArrayList<>();
private MyAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
mXListView=(XListView)findViewById(R.id.xlistview);
mXListView.setPullLoadEnable(true);
mXListView.setXListViewListener(this);
adapter=new MyAdapter(this,list);
mXListView.setAdapter(adapter);
onRefresh();
}
public void stopLoad(){
Date date=new Date();
SimpleDateFormat format=new SimpleDateFormat("HH:mm:ss");
mXListView.stopRefresh();
mXListView.stopLoadMore();
mXListView.setRefreshTime(format.format(date));
page++;
}
@Override
public void onRefresh() {
page=1;
loadData();
}
@Override
public void onLoadMore() {
loadData();
}
public void loadData(){
//根据url生成一个MD5文件名
String url = urlPath+page;
String md5 = MD5.encryptByMD5(url);
File cache = getExternalCacheDir();
File file =new File(cache,md5+".json");
//判断这个文件是否存在
if(file.exists()){
//读取这个文件的内容就是这次请求的数据 那么不用再从网络上获取
String result = readFile(file);
//解析内容
parse(result);
}else{
//从网络获取
loadDataByNet();
}
}
private void loadDataByNet() {
new Thread(){
@Override
public void run() {
//网络请求结果字符串
final String result = HttpUrlUtils.getUrlConnect(urlPath+page);
//根据url生成MD5的文件名
File cache = getExternalCacheDir();
File file=new File(cache,MD5.encryptByMD5(urlPath+page)+".json");
//把网络请求的内容写入到这个文件中 作为该请求的文件缓存
if(result!=null)
writeFile(file,result);
//解析更新ui
runOnUiThread(new Runnable() {
@Override
public void run() {
if(result!=null)
parse(result);
}
});
}
}.start();
}
private void writeFile(File file, String result) {
try {
BufferedWriter bw=new BufferedWriter(
new OutputStreamWriter(new FileOutputStream(file)));
bw.write(result);
bw.flush();
bw.close();
} catch (Exception e) {
e.printStackTrace();
}
}
private String readFile(File file) {
try {
BufferedReader br=new BufferedReader(new InputStreamReader(
new FileInputStream(file)));
String line =null;
StringBuffer sb=new StringBuffer();
while((line=br.readLine())!=null){
sb.append(line);
}
br.close();
return sb.toString();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
private void parse(String result) {
Gson gson=new Gson();
Data data = gson.fromJson(result,Data.class);
if(page==1)
list.clear();
list.addAll(data.getData());
Log.e("parse", "parse: "+list.size());
adapter.notifyDataSetChanged();
stopLoad();
}
}
//MyAdapter
package com.example.wz.cachedemo;
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.List;
/**
* 类描述:
* 创建人:yekh
* 创建时间:2017/5/18 11:24
*/
public class MyAdapter extends BaseAdapter{
private Context mContext;
private List<Data.DataBean> mList;
private ImageUtils mImageUtils;
public MyAdapter(Context context, List<Data.DataBean> list) {
mContext = context;
mList = list;
mImageUtils=new ImageUtils();
}
@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 holder=null;
if(convertView==null){
holder=new ViewHolder();
convertView=View.inflate(mContext,R.layout.item,null);
holder.name=(TextView)convertView.findViewById(R.id.name);
holder.desc=(TextView)convertView.findViewById(R.id.desc);
holder.photo=(ImageView) convertView.findViewById(R.id.image);
convertView.setTag(holder);
}else{
holder=(ViewHolder)convertView.getTag();
}
Data.DataBean bean=mList.get(position);
holder.name.setText(bean.getUserName());
holder.desc.setText(bean.getIntroduction());
//Glide.with(mContext).load(bean.getUserImg()).into(holder.photo);
mImageUtils.loadImage(position,bean.getUserImg(),holder.photo);
return convertView;
}
class ViewHolder{
TextView name;
TextView desc;
ImageView photo;
}
}
//HttpUrlUtils
package com.example.wz.cachedemo;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;
import java.io.InputStream;
import java.io.OutputStream;
import java.NET.HttpURLConnection;
import java.net.URL;
import java.util.Map;
/**
* 类描述:
* 创建人:yekh
* 创建时间:2017/5/18 11:16
*/
public class HttpUrlUtils {
/**
* HttpURLConnection的post请求
* @param urlPath
* @param map
* @return
*/
public static String postUrlConnect(String urlPath, Map<String,Object> map){
StringBuffer sbRequest =new StringBuffer();
if(map!=null&&map.size()>0){
for (String key:map.keySet()){
sbRequest.append(key+"="+map.get(key)+"&");
}
}
String request = sbRequest.substring(0,sbRequest.length()-1);
try {
//创建URL
URL url = new URL(urlPath);
//由URL的openConnection方法得到一个HttpURLConnection(需要强转)
HttpURLConnection httpURLConnection =
(HttpURLConnection) url.openConnection();
//设置post提交
httpURLConnection.setRequestMethod("POST");
//设置超时时间
httpURLConnection.setConnectTimeout(30000);
httpURLConnection.setReadTimeout(30000);
httpURLConnection.setDoInput(true);
httpURLConnection.setDoOutput(true);
//把请求正文通过OutputStream发出去
OutputStream os =httpURLConnection.getOutputStream();
os.write(request.getBytes());
os.flush();
//判断响应码 200 代表成功
if(httpURLConnection.getResponseCode()==200){
//由HttpURLConnection拿到输入流
InputStream in=httpURLConnection.getInputStream();
StringBuffer sb=new StringBuffer();
//根据输入流做一些IO操作
byte [] buff =new byte[1024];
int len=-1;
while((len=in.read(buff))!=-1){
sb.append(new String(buff,0,len,"utf-8"));
}
in.close();
os.close();
httpURLConnection.disconnect();
return sb.toString();
}else{
return null;
}
}catch (Exception e){
Log.e("post","code:"+e.getMessage());
return null;
}
}
/**
* HttpURLConnection的get请求
* @param urlPath
* @return
*/
public static String getUrlConnect(String urlPath){
try {
//创建URL
URL url = new URL(urlPath);
//由URL的openConnection方法得到一个HttpURLConnection(需要强转)
HttpURLConnection httpURLConnection =
(HttpURLConnection) url.openConnection();
//设置连接
httpURLConnection.connect();
//判断响应码 200 代表成功
if(httpURLConnection.getResponseCode()==200){
//由HttpURLConnection拿到输入流
InputStream in=httpURLConnection.getInputStream();
StringBuffer sb=new StringBuffer();
//根据输入流做一些IO操作
byte [] buff =new byte[1024];
int len=-1;
while((len=in.read(buff))!=-1){
sb.append(new String(buff,0,len,"utf-8"));
}
in.close();
httpURLConnection.disconnect();
return sb.toString();
}else{
return null;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* HttpURLConnection的get请求
* @param urlPath
* @return
*/
public static Bitmap loadImage2Bitmap(String urlPath){
try {
//创建URL
URL url = new URL(urlPath);
//由URL的openConnection方法得到一个HttpURLConnection(需要强转)
HttpURLConnection httpURLConnection =
(HttpURLConnection) url.openConnection();
//设置连接
httpURLConnection.connect();
//判断响应码 200 代表成功
if(httpURLConnection.getResponseCode()==200){
//由HttpURLConnection拿到输入流
InputStream in=httpURLConnection.getInputStream();
BitmapFactory.Options options=new BitmapFactory.Options();
options.inSampleSize=4;
Bitmap bitmap = BitmapFactory.decodeStream(in,null,options);
in.close();
httpURLConnection.disconnect();
return bitmap;
}else{
return null;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
//ImageReuqest
package com.example.wz.cachedemo;
import android.widget.ImageView;
/**
* 类描述:
* 创建人:yekh
* 创建时间:2017/5/19 19:35
*/
public class ImageReuqet {
int pos;
public ImageReuqet(String imageUrl, ImageView imageView) {
this.imageUrl = imageUrl;
this.imageView = imageView;
}
String imageUrl;
ImageView imageView;
}
//ImageUtils
package com.example.wz.cachedemo;
import android.graphics.Bitmap;
import android.util.Log;
import android.widget.ImageView;
import java.util.Vector;
/**
* 类描述:
* 创建人:yekh
* 创建时间:2017/5/19 18:57
*/
public class ImageUtils {
//最大10个 10个窗口
private Vector<Thread> listThread;
//排号系统 后进先出
private Vector<ImageReuqet> list;
private int size = 10;
private int sizeThread = 10;
public ImageUtils() {
listThread=new Vector<>(sizeThread);
list=new Vector<>(size);
}
public void add(int pos,String imageUrl,ImageView imageView){
ImageReuqet reuqest=new ImageReuqet(imageUrl,imageView);
reuqest.pos=pos;
if(list.size()>=size){
list.remove(0);
}
list.add(reuqest);
if(listThread.size()<sizeThread){
ImageReuqet reuqet=list.remove(list.size()-1);
DownloadImage downloadImage=new DownloadImage(reuqet);
listThread.add(downloadImage);
downloadImage.start();
}
}
private void remove(Thread thread){
listThread.remove(thread);
if(list.size()>0){
ImageReuqet reuqet=list.remove(list.size()-1);
DownloadImage downloadImage=new DownloadImage(reuqet);
listThread.add(downloadImage);
downloadImage.start();
}else{
Log.e("remove", "remove----------等待队列为空");
}
}
public void loadImage(int pos,String imageUrl, ImageView imageView){
imageView.setImageResource(R.mipmap.ic_launcher);
imageView.setTag(imageUrl);
add(pos,imageUrl,imageView);
}
class DownloadImage extends Thread{
private String imageUrl;
private ImageView imageView;
private int pos;
public DownloadImage(ImageReuqet reuqet) {
Log.e("DownloadImage", "DownloadImage----------"+reuqet.pos);
pos=reuqet.pos;
imageUrl=reuqet.imageUrl;
imageView=reuqet.imageView;
}
@Override
public void run() {
final Bitmap bitmap= HttpUrlUtils.loadImage2Bitmap(imageUrl);
if(bitmap!=null){
if(imageUrl.equals(imageView.getTag())){
imageView.post(new Runnable() {
@Override
public void run() {
imageView.setImageBitmap(bitmap);
}
});
}
Log.e("DownloadImage", "DownloadImage----------"+pos+"任务完成");
remove(DownloadImage.this);
}
}
}
}
//MD5
package com.example.wz.cachedemo;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
/**
* 类描述:
* 创建人:yekh
* 创建时间:2017/5/18 15:28
*/
public class MD5 {
private static final String MD5_SUFFIX = "_dengsilinming";
/**
* 字符加密
*
* @param str 明文
* @return 返回加了后缀的加密字符
*/
public static String encryptByMD5(String str) {
try {
if (str == null || str.length() < 1 || "0".equals(str))
str = "0";
String tmp = md5(str + MD5_SUFFIX, "UTF-8");
if (null != tmp) {
return replace(tmp, ":", "", -1).toLowerCase();
}
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return "";
}
/**
* md5加密方法,不可逆转
*
* @param str 明文
* @param charset 字符编码
* @return
* @throws NoSuchAlgorithmException
* @throws UnsupportedEncodingException
*/
public static String md5(String str, String charset)
throws NoSuchAlgorithmException, UnsupportedEncodingException {
byte[] tmpInput = null;
if (null != str) {
if (null != charset) {
tmpInput = str.getBytes(charset);
} else {
tmpInput = str.getBytes();
}
} else {
return null;
}
MessageDigest alg = MessageDigest.getInstance("MD5"); // or "SHA-1"
alg.update(tmpInput);
return byte1hex(alg.digest());
}
/**
* 字节码转换成16进制字符串
*
* @param inputByte
* @return
*/
public static String byte1hex(byte[] inputByte) {
if (null == inputByte) {
return null;
}
String resultStr = "";
String tmpStr = "";
for (int n = 0; n < inputByte.length; n++) {
tmpStr = (Integer.toHexString(inputByte[n] & 0XFF));
if (tmpStr.length() == 1)
resultStr = resultStr + "0" + tmpStr;
else
resultStr = resultStr + tmpStr;
if (n < inputByte.length - 1)
resultStr = resultStr + ":";
}
return resultStr.toUpperCase();
}
public static String replace(String text, String repl, String with, int max) {
if (isEmpty(text) || isEmpty(repl) || with == null || max == 0) {
return text;
}
int start = 0;
int end = text.indexOf(repl, start);
if (end == -1) {
return text;
}
int replLength = repl.length();
int increase = with.length() - replLength;
increase = (increase < 0 ? 0 : increase);
increase *= (max < 0 ? 16 : (max > 64 ? 64 : max));
StringBuffer buf = new StringBuffer(text.length() + increase);
while (end != -1) {
buf.append(text.substring(start, end)).append(with);
start = end + replLength;
if (--max == 0) {
break;
}
end = text.indexOf(repl, start);
}
buf.append(text.substring(start));
return buf.toString();
}
public static boolean isEmpty(String str) {
return str == null || str.length() == 0;
}
}
//在 AndroidManifest.xml中配置
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>