<strong><span style="font-size:24px;">1.java的引用类型:</span></strong>
<p style="border-width: 0px; padding-top: 0px; padding-bottom: 0px; margin-top: 0px; margin-bottom: 8px; list-style: none; text-indent: 2em; color: rgb(51, 51, 51); font-family: 宋体; font-size: 14px; line-height: 28px; background-color: rgb(249, 249, 249);">1)强引用(StrongReference)
强引用是使用最普遍的引用。如果一个对象具有强引用,那垃圾回收器绝不会回收它。当内存空间不足,Java<a target=_blank href="http://www.2cto.com/os/xuniji/" target="_blank" class="keylink" style="color: rgb(51, 51, 51); text-decoration: none;">虚拟机</a>宁愿抛出OutOfMemoryError错误,使程序异常终止,也不会靠随意回收具有强引用的对象来解决内存不足的问题。
2)软引用(SoftReference)
如果一个对象只具有软引用,则内存空间足够,垃圾回收器就不会回收它;如果内存空间不足了,就会回收这些对象的内存。只要垃圾回收器没有回收它,该对象就可以被程序使用。软引用可用来实现内存敏感的高速缓存(下文给出示例)。
软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收器回收,Java虚拟机就会把这个软引用加入到与之关联的引用队列中。</p><p style="border-width: 0px; padding-top: 0px; padding-bottom: 0px; margin-top: 0px; margin-bottom: 8px; list-style: none; text-indent: 2em; color: rgb(51, 51, 51); font-family: 宋体; font-size: 14px; line-height: 28px; background-color: rgb(249, 249, 249);">3) 弱引用(WeakReference)
弱引用与软引用的区别在于:弱引用的对象拥有更短暂的生命周期。在垃圾回收器线程扫描它所管辖的内存区域的过程中,一旦发现了只具有弱引用的对象,不管当前内存空间足够与否,都会回收它的内存。不过,由于垃圾回收器是一个优先级很低的线程,因此不一定会很快发现那些只具有弱引用的对象。
弱引用可以和一个引用队列(ReferenceQueue)联合使用,如果弱引用所引用的对象被垃圾回收,Java虚拟机就会把这个弱引用加入到与之关联的引用队列中。</p><p style="border-width: 0px; padding-top: 0px; padding-bottom: 0px; margin-top: 0px; margin-bottom: 8px; list-style: none; text-indent: 2em; color: rgb(51, 51, 51); font-family: 宋体; font-size: 14px; line-height: 28px; background-color: rgb(249, 249, 249);"> 4)虚引用(PhantomReference)
“虚引用”顾名思义,就是形同虚设,与其他几种引用都不同,虚引用并不会决定对象的生命周期。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收器回收。
虚引用主要用来跟踪对象被垃圾回收器回收的活动。虚引用与软引用和弱引用的一个区别在于:虚引用必须和引用队列(ReferenceQueue)联合使用。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,把这个虚引用加入到与之 关联的引用队列中。</p>----
软引用:
结合加载歌手图片来说明:
1.先创建一个MAP集合,用来保存图片的缓存文件
<pre name="code" class="html"> //内存缓存 使用软引用
private Map<String, SoftReference<Bitmap>> softcache=new HashMap<String, SoftReference<Bitmap>>();
2.使用时 先在获取到图片的Bitmap数据位置进行数据的放入缓存操作。
<span style="white-space:pre"> </span>//将获取的bitmap存入内存缓存
softcache.put(task.imagePath, new SoftReference<Bitmap>(bitmap));
3.缓存原理就是:如果文件在缓存中有,就直接从缓存中获取数据,由于是软引用,当系统内存不足时,内存回收机制GC就可能会销毁掉部分缓存数据,没有时,才需要重新加载图片数据。所以在adapter的getview中 先判断后、然后就可以直接使用控件加载bitmap数据
//先去内存缓存查看是否有此图的缓存图片
SoftReference<Bitmap> ref= softcache.get(path); //获取缓存中的缓存对象
if(ref!=null){
//从缓存对象中取出缓存图片
Bitmap b= ref.get();
if(b!=null){//有图
holder.ivImage.setImageBitmap(b); //直接加载内存的缓存的图片
Log.d("tedu", "从内存缓存读取。。");
return convertView ;//有则直接返回
}
}
<strong><span style="font-size:18px;">2.文件引用</span></strong>
文件引用就是将开始读取的数据放入app对应的缓存文件夹内,当下次读取时,就可以直接加载显示 节省流量。
1.先创建两个方法,一个是用于保存数据到缓存,一个是用于通过缓存文件路径去取出数据用于显示
<pre name="code" class="html"> //用于保存文件
public static void saveMap(Bitmap bitmap,File file) throws FileNotFoundException{
if(!file.getParentFile().exists()){
//获取父目录文件夹是否存在,不存在就创建
file.getParentFile().mkdirs();
}
//创建文件输出流 保存文件
FileOutputStream fos=new FileOutputStream(file);
//将bitmap文件压缩并输出
bitmap.compress(CompressFormat.JPEG, 100, fos);
}
<span style="white-space:pre"> </span>//用于获取数据的方法
<pre name="code" class="html"> public static Bitmap getBitmapByFile(File file){
if(!file.exists()){
return null;
}
//根据文件去找到文件缓存中的图片、
Bitmap bitmap=BitmapFactory.decodeFile(file.getAbsolutePath());
return bitmap;
}
2.然后与软引用一样。在获取到数据的位置,调用保存方法,将数据放入缓存文件件夹内:
<pre name="code" class="html"><span style="white-space:pre"> </span>//将获取的图再存入文件缓存中
String path=task.imagePath;//获取当前任务中的文件路径
String filename=path.substring(path.lastIndexOf("/")+1);//不包含/
File file=new File(context.getCacheDir(), "images/"+filename);
//调用方法 保存文件
BitMapUtil.saveMap(bitmap, file);
3.同样的方法,在getview中判断后 就可以直接使用控件进行数据的显示:
<span style="white-space:pre"> </span>//从文件中读取图片
String filename=path.substring(path.lastIndexOf("/")+1);
File file=new File(context.getCacheDir(),"images/"+filename);
Bitmap map=BitMapUtil.getBitmapByFile(file);
if(map!=null){
holder.ivImage.setImageBitmap(map);
Log.d("tedu", "从文件缓存读取。。");
//从文件读时同时保存到内存缓存。加快读取速度
softcache.put(path, new SoftReference<Bitmap>(map));
return convertView;
}
上面这段代码中,加了一句当从文件获取数据缓存数据时,重新将数据放入内存的缓存集合中 ,这样可以加快图片的显示,从内存中获取是最快的!
原码:
package com.wuxs.three_musicplayer_v4.Adapter;
import java.io.File;
import java.io.InputStream;
import java.lang.ref.SoftReference;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.wuxs.three_musicplayer_v4.R;
import com.wuxs.three_musicplayer_v4.entity.Music;
import com.wuxs.three_musicplayer_v4.util.BitMapUtil;
import com.wuxs.three_musicplayer_v4.util.MusicHttpUtil;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
public class MusicsAdapter extends BaseAdapter {
private Context context;
private List<Music> musics;
private LayoutInflater inflater;
private ListView lvmusic;// 为了获取标记的imageview
//创建任务集合。
private List<LoadImageTask> tasks=new ArrayList<LoadImageTask>();
private Thread thread;
private boolean isLoop=true;
//内存缓存 使用软引用
private Map<String, SoftReference<Bitmap>> softcache=new HashMap<String, SoftReference<Bitmap>>();
private Handler handler=new Handler(new Handler.Callback() {
@Override
public boolean handleMessage(Message msg) {
switch (msg.what) {
case LOAD_IMAGE_SUCCESS: //加载ok
LoadImageTask task= (LoadImageTask) msg.obj;
Bitmap bitmap= task.bitmap; //数据ok
//取出
ImageView ivImage= (ImageView) lvmusic.findViewWithTag(task.imagePath);
if(ivImage!=null){
if(bitmap!=null){
ivImage.setImageBitmap(bitmap);
}
}
break;
}
return false;
}
});
private static final int LOAD_IMAGE_SUCCESS=1;
public MusicsAdapter(final Context context, List<Music> musics,ListView lvmusic) {
super();
this.context = context;
this.musics = musics;
this.inflater = LayoutInflater.from(context);
this.lvmusic=lvmusic;
thread=new Thread(){
@Override
public void run() {
//在工作线程处理加载任务
while(isLoop){//让他不断循环判断 类似handler的looper
if(!tasks.isEmpty()){//如果任务集合不为空
//获取bitmap数据
LoadImageTask task=tasks.remove(0); //每次移除第一个任务出来
// Bitmap bitmap=getBitMap(task.imagePath);//改为采用压缩格式图片获取
try {
Bitmap bitmap = BitMapUtil.getYasuoPhoto(task.imagePath,40,40);
//将bitmap数据封装进去
task.bitmap=bitmap;
//在这个位置获取了图片的bitmap信息 在此加上内存缓存
//将获取的bitmap存入内存缓存
softcache.put(task.imagePath, new SoftReference<Bitmap>(bitmap));
//将获取的图再存入文件缓存中
String path=task.imagePath;//获取当前任务中的文件路径
String filename=path.substring(path.lastIndexOf("/")+1);//不包含/
File file=new File(context.getCacheDir(), "images/"+filename);
//调用方法 保存文件
BitMapUtil.saveMap(bitmap, file);
} catch (Exception e) {
e.printStackTrace();
}
//发出消息
Message mes=Message.obtain();
mes.what=LOAD_IMAGE_SUCCESS;
mes.obj=task;
handler.sendMessage(mes);
}else{
//任务为空时 ,让线程休眠
synchronized (thread) {
try {
thread.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
};
thread.start();
}
//获取bitmap
protected Bitmap getBitMap(String imagePath) {
//调用方法
try {
String url=imagePath;
InputStream is= MusicHttpUtil.getXmlInputStream(url);
Bitmap bitmap=BitmapFactory.decodeStream(is);//通过输入流获取图片bitmap数据
return bitmap;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return musics.size();
}
@Override
public Object getItem(int position) {
// TODO Auto-generated method stub
return musics.get(position);
}
@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
Music music=musics.get(position);
viewHolder holder=null;
if(convertView==null){
convertView=inflater.inflate(R.layout.list_m, null);
holder=new viewHolder();
holder.ivImage=(ImageView) convertView.findViewById(R.id.ivphoto);
holder.tvAuthor=(TextView) convertView.findViewById(R.id.tv_author);
holder.tvTitle=(TextView) convertView.findViewById(R.id.tv_title);
convertView.setTag(holder);
}else {
holder=(viewHolder) convertView.getTag();
}
holder.tvAuthor.setText(music.getAuthor());
holder.tvTitle.setText(music.getTitle());
//标记每个imageview
String path=music.getPic_small();
holder.ivImage.setTag(path); //用small路径去标记imageview
//先去内存缓存查看是否有此图的缓存图片
SoftReference<Bitmap> ref= softcache.get(path); //获取缓存中的缓存对象
if(ref!=null){
//从缓存对象中取出缓存图片
Bitmap b= ref.get();
if(b!=null){//有图
holder.ivImage.setImageBitmap(b); //直接加载内存的缓存的图片
Log.d("tedu", "从内存缓存读取。。");
return convertView ;//有则直接返回
}
}
//从文件中读取图片
String filename=path.substring(path.lastIndexOf("/")+1);
File file=new File(context.getCacheDir(),"images/"+filename);
Bitmap map=BitMapUtil.getBitmapByFile(file);
if(map!=null){
holder.ivImage.setImageBitmap(map);
Log.d("tedu", "从文件缓存读取。。");
//从文件读时同时保存到内存缓存。加快读取速度
softcache.put(path, new SoftReference<Bitmap>(map));
return convertView;
}
//没有则继续发任务 子线程中获取图片
//在这里不能直接使用子线程来显示图片。应为那样会创建很多个线程、改为在构造方法时创建子线程。就会创建一个
//在这里要做的事就是发出一个图片显示任务,然后给到子线程,去处理。
LoadImageTask task=new LoadImageTask();
task.imagePath=music.getPic_small(); //将路径设置进去
//然后往集合里添加该task。 也就是发出了一个图片加载任务
tasks.add(task);
//唤醒休眠后的线程
synchronized (thread) {
thread.notify(); //唤醒线程
}
return convertView;
}
class viewHolder{
ImageView ivImage;
TextView tvTitle;
TextView tvAuthor;
}
//设置任务属性
private class LoadImageTask{
private String imagePath;
private Bitmap bitmap;
}
//停止线程方法
public void StopThread(){
isLoop=false; //停止子线程
//如果线程在休眠 就唤醒
synchronized (thread) {
thread.notify();
}
}
}