这次老师讲解了两张调用你缓存的方法 我以前是实现现在图片再从本地读取图片
这样需要
数据流 - bitmap - 图片 - bitmap
而老师的方式
数据流 -bitmap(已经显示在ui上) - 图片 显然 老师的方式更好
但是老师讲的内存缓存的方式 感觉一般,全写在activity感觉不是个好的方式
另外,似乎本地缓存+内存缓存是更好一点的解决方案
在爱家项目中遇到的图片由于缓存不能更新的问题现在想到了解决方案:
图片更新后图片的网址会更新,我可能要md5(URL) 命名图片 如果图片更新那url变了 那我就重新下载图片
两种缓存代码
package cn.itcast.douban;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.google.gdata.data.Link;
import com.google.gdata.data.douban.Attribute;
import com.google.gdata.data.douban.CollectionEntry;
import com.google.gdata.data.douban.CollectionFeed;
import com.google.gdata.data.douban.Subject;
import com.google.gdata.data.douban.SubjectEntry;
import com.google.gdata.data.douban.UserEntry;
import com.google.gdata.data.extensions.Rating;
import com.google.gdata.util.ServiceException;
import cn.itcast.douban.domain.Book;
import cn.itcast.douban.util.LoadImageAsynTask;
import cn.itcast.douban.util.LoadImageAsynTask.LoadImageAsynTaskCallback;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView.OnScrollListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.AbsListView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.RatingBar;
import android.widget.RelativeLayout;
import android.widget.TextView;
public class MyReadActivity extends BaseActivity implements OnItemClickListener {
private ListView subjectlist;
MyReadAdapter adapter;
// Map<String,Bitmap> iconCache;
Map<String, SoftReference<Bitmap>> iconCache;
int startindex; // 开始获取内容的id
int count;
int max = 20;
boolean isloading = false;
IntentFilter filter;
KillReceiver receiver ;
@Override
protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.subject);
super.onCreate(savedInstanceState);
startindex = 1;
count = 5;
// 初始化内存缓存
iconCache = new HashMap<String, SoftReference<Bitmap>>();
}
@Override
public void setupView() {
mRelativeLoading = (RelativeLayout) this.findViewById(R.id.loading);
subjectlist = (ListView) this.findViewById(R.id.subjectlist);
filter = new IntentFilter();
filter.addAction("kill_activity_action");
receiver = new KillReceiver();
this.registerReceiver(receiver, filter);
}
@Override
public void setListener() {
subjectlist.setOnItemClickListener(this);
subjectlist.setOnScrollListener(new OnScrollListener() {
public void onScrollStateChanged(AbsListView view, int scrollState) {
switch (scrollState) {
case OnScrollListener.SCROLL_STATE_IDLE:
// 如果当前滚动状态为静止状态
// 并且listview里面最后一个用户可见的条目 内容 等于listview数据适配器里面的最后一个条目
// 获取listview中最后一个用户可见条目的位置
int positon = view.getLastVisiblePosition();
System.out.println("最后一个可见条目的位置 " + positon);
int totalcount = adapter.getCount();
System.out.println("listview 条目的数目 " + totalcount);
if (positon == (totalcount - 1)) {// 代表当前界面拖动到了最下方
// 获取更多的数据
startindex = startindex + count;
if (startindex > max) {
showToast("数据已经加载到最大条目");
return;
}
if (isloading) {
return;
}
fillData();
}
break;
}
}
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
}
});
}
@Override
public void fillData() {
// 通过异步任务 获取数据 然后显示到界面上
new AsyncTask<Void, Void, List<Book>>() {
@Override
protected void onPreExecute() {
showLoading();
isloading = true;
super.onPreExecute();
}
@Override
protected void onPostExecute(List<Book> result) {
hideLoading();
super.onPostExecute(result);
if (result != null) {
if (adapter == null) {
adapter = new MyReadAdapter(result);
subjectlist.setAdapter(adapter);
} else {
// 把新获取到的数据 加到listview的数据适配器里面
// 通知界面更新内容
adapter.addMoreBook(result);
// 通知数据适配器更新数据
adapter.notifyDataSetChanged();
}
} else {
showToast("获取数据失败");
}
isloading = false;
}
@Override
protected List<Book> doInBackground(Void... params) {
try {
UserEntry ue = myService.getAuthorizedUser();
String uid = ue.getUid();
// 首先获取用户的 所有收集的信息
CollectionFeed feeds = myService.getUserCollections(uid,
"book", null, null, startindex, count);
List<Book> books = new ArrayList<Book>();
for (CollectionEntry ce : feeds.getEntries()) {
Subject se = ce.getSubjectEntry();
if (se != null) {
Book book = new Book();
String title = se.getTitle().getPlainText();
book.setName(title);
StringBuilder sb = new StringBuilder();
for (Attribute attr : se.getAttributes()) {
if ("author".equals(attr.getName())) {
sb.append(attr.getContent());
sb.append("/");
} else if ("publisher".equals(attr.getName())) {
sb.append(attr.getContent());
sb.append("/");
} else if ("pubdate".equals(attr.getName())) {
sb.append(attr.getContent());
sb.append("/");
} else if ("isbn10".equals(attr.getName())) {
sb.append(attr.getContent());
sb.append("/");
}
}
book.setDescription(sb.toString());
Rating rating = se.getRating();
if (rating != null) {
book.setRating(rating.getAverage());
}
for (Link link : se.getLinks()) {
if ("image".equals(link.getRel())) {
book.setBookurl(link.getHref());
}
}
books.add(book);
}
}
return books;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}.execute();
}
//点击某个条目对应的点击事件
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
Book book =(Book) subjectlist.getItemAtPosition(position);
String description = book.getDescription();
int end = description.indexOf("/");
String isbn = description.substring(0, end);
Intent intent = new Intent(this,BookDetailActivity.class);
intent.putExtra("isbn", isbn);
startActivity(intent);
}
private class MyReadAdapter extends BaseAdapter {
private List<Book> books;
public MyReadAdapter(List<Book> books) {
this.books = books;
}
public void addMoreBook(List<Book> books) {
for (Book book : books) {
this.books.add(book);
}
}
public int getCount() {
return books.size();
}
public Object getItem(int position) {
// TODO Auto-generated method stub
return books.get(position);
}
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
View view = View.inflate(MyReadActivity.this, R.layout.book_item,
null);
final ImageView iv_book = (ImageView) view
.findViewById(R.id.book_img);
RatingBar rb = (RatingBar) view.findViewById(R.id.ratingbar);
TextView tv_title = (TextView) view.findViewById(R.id.book_title);
TextView tv_description = (TextView) view
.findViewById(R.id.book_description);
Book book = books.get(position);
if (book.getRating() != 0) {
rb.setRating(book.getRating());
} else {
rb.setVisibility(View.INVISIBLE);
}
tv_description.setText(book.getDescription());
tv_title.setText(book.getName());
// 判断 图片是否在sd卡上存在
String iconpath = book.getBookurl();
final String iconname = iconpath.substring(
iconpath.lastIndexOf("/") + 1, iconpath.length());
/*
* File file = new File("/sdcard/" + iconname); if (file.exists()) {
* iv_book.setImageURI(Uri.fromFile(file));
* System.out.println("使用sd卡缓存"); } else {
*/
if (iconCache.containsKey(iconname)) {
SoftReference<Bitmap> softref = iconCache.get(iconname);
if (softref != null) {
Bitmap bitmap = softref.get();
if (bitmap != null) {
System.out.println("使用内存缓存 ");
iv_book.setImageBitmap(bitmap);
} else {
loadimage(iv_book, book, iconname);
}
}
} else {
loadimage(iv_book, book, iconname);
}
return view;
}
private void loadimage(final ImageView iv_book, Book book,
final String iconname) {
LoadImageAsynTask task = new LoadImageAsynTask(
new LoadImageAsynTaskCallback() {
public void beforeLoadImage() {
iv_book.setImageResource(R.drawable.book);
}
public void afterLoadImage(Bitmap bitmap) {
if (bitmap != null) {
System.out.println("下载服务器图片");
iv_book.setImageBitmap(bitmap);
/*
* // 把bitmap存放到sd卡上 try { File file = new
* File("/sdcard/" + iconname); FileOutputStream
* stream = new FileOutputStream( file);
* bitmap.compress(CompressFormat.JPEG, 100,
* stream); } catch (Exception e) {
* e.printStackTrace(); }
*/
// 把图片存放到内存缓存里面
iconCache.put(iconname,
new SoftReference<Bitmap>(bitmap));
} else {
iv_book.setImageResource(R.drawable.book);
}
}
});
task.execute(book.getBookurl());
}
}
private class KillReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
iconCache = null;
showToast("内存不足activity退出");
finish();
}
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
unregisterReceiver(receiver);
}
}
app中有个方法是关于oom错误的
@Override
public void onLowMemory() {
super.onLowMemory();
// 发送一些广播 关闭掉一些activity service
Intent intent = new Intent();
intent.setAction("kill_activity_action");
sendBroadcast(intent);
}
在listview中有一个
subjectlist.setEmptyView(emptyView)//Sets the view to show if the adapter is empty
这样如果listview没有内容就会显示一个默认view 很重要
在代码中老师还讲了一下下拉刷新 他实现的很简单就是判断到底部了 直接加载
但是很应用的整个设计却很协调,以后也可以参考这样设计
还要注意 如果数据已经没有了就不要加载了,这个需要在获取最后的数据后判断 大体上是加一个"锁"
在filldata()的时候也应该加一个锁来用户在加载数据的时候乱拖到造成listview的item错乱
// 如果当前滚动状态为静止状态
// 并且listview里面最后一个用户可见的条目 内容 等于listview数据适配器里面的最后一个条目
// 获取listview中最后一个用户可见条目的位置
int positon = view.getLastVisiblePosition();
System.out.println("最后一个可见条目的位置 " + positon);
int totalcount = adapter.getCount();
System.out.println("listview 条目的数目 " + totalcount);
if (positon == (totalcount - 1)) {// 代表当前界面拖动到了最下方
// 获取更多的数据
startindex = startindex + count;
if (startindex > max) {
showToast("数据已经加载到最大条目");
return;
}
if (isloading) {
return;
}
fillData();
}