在醒目中对于进行数据缓存和图片缓存的对象是在public class JamendoApplication extends Application这个Application里面进行创建和获取的。
对于Application先看一下API中的解释
Base class for those who need to maintain global application state. You can provide your own implementation by specifying its name in your AndroidManifest.xml's <application> tag, which will cause that class to be instantiated for you when the process for your application/package is created.
There is normally no need to subclass Application. In most situation, static singletons can provide the same functionality in a more modular way. If your singleton needs a global context (for example to register broadcast receivers), the function to retrieve it can be given a Context
which internally uses Context.getApplicationContext()
when first constructing the singleton.
public class JamendoApplication extends Application {
/**
* Singleton pattern
*/
private static JamendoApplication instance;
/**
* Image cache, one for all activities and orientations
*/
private ImageCache mImageCache;
/**
* Web request cache, one for all activities and orientations
*/
private RequestCache mRequestCache;
@Override
public void onCreate() {
super.onCreate();
mImageCache = new ImageCache();
mRequestCache = new RequestCache();
Caller.setRequestCache(mRequestCache);
instance = this;
mDownloadManager = new DownloadManagerImpl(this);
}
/**
* Access to global image cache across Activity instances
*
* @return
*/
public ImageCache getImageCache() {
return mImageCache;
}
}
对于数据的缓存是通过一个类RequestCache来处理的
public class RequestCache {
// TODO cache lifeTime
private static int CACHE_LIMIT = 10;
@SuppressWarnings("unchecked")
private LinkedList history;
private Hashtable<String, String> cache;
@SuppressWarnings("unchecked")
public RequestCache(){
history = new LinkedList();
cache = new Hashtable<String, String>();
}
@SuppressWarnings("unchecked")
public void put(String url, String data){
history.add(url);
// too much in the cache, we need to clear something
if(history.size() > CACHE_LIMIT){
String old_url = (String) history.poll();
cache.remove(old_url);
}
cache.put(url, data);
}
public String get(String url){
return cache.get(url);
}
}
将已经下载的最近10个数据放到一个HashTable<String,String>里面,如果HashTable里面有那么直接取出来,如果没有则加入,如果HashTable里面的数据超过了10个那个就把最晚的那个删除。
在HomeActivity里面有一个NewsTask的AsyncTask用以加载最近一个星期内最受欢迎的专辑
@Override
public Album[] doInBackground(Void... params) {
JamendoGet2Api server = new JamendoGet2ApiImpl();
Album[] albums = null;
try {
albums = server.getPopularAlbumsWeek();
} catch (JSONException e) {
e.printStackTrace();
} catch (WSError e){
publishProgress(e);
}
return albums;
}
会调用JamendoGet2ApiImpl里面想用的方法
private String doGet(String query) throws WSError{
return Caller.doGet(GET_API + query);
}
@Override
public Album[] getPopularAlbumsWeek() throws JSONException, WSError {
String jsonString = doGet("id+name+url+image+rating+artist_name/album/json/?n=20&order=ratingweek_desc");
if (jsonString == null)
return null;
try {
JSONArray jsonArrayAlbums = new JSONArray(jsonString);
return AlbumFunctions.getAlbums(jsonArrayAlbums);
} catch (NullPointerException e) {
e.printStackTrace();
throw new JSONException(e.getLocalizedMessage());
}
}
这里面会调用Caller里面的doGet()方法
public static String doGet(String url) throws WSError{
String data = null;
if(requestCache != null){
data = requestCache.get(url);
if(data != null){
Log.d(JamendoApplication.TAG, "Caller.doGet [cached] "+url);
return data;
}
}
URI encodedUri = null;
HttpGet httpGet = null;
try {
encodedUri = new URI(url);
httpGet = new HttpGet(encodedUri);
} catch (URISyntaxException e1) {
// at least try to remove spaces
String encodedUrl = url.replace(' ', '+');
httpGet = new HttpGet(encodedUrl);
e1.printStackTrace();
}
// initialize HTTP GET request objects
HttpClient httpClient = new DefaultHttpClient();
HttpResponse httpResponse;
try {
// execute request
try {
httpResponse = httpClient.execute(httpGet);
} catch (UnknownHostException e) {
throw new WSError("Unable to access " + e.getLocalizedMessage());
} catch (SocketException e){
throw new WSError(e.getLocalizedMessage());
}
// request data
HttpEntity httpEntity = httpResponse.getEntity();
if(httpEntity != null){
InputStream inputStream = httpEntity.getContent();
data = convertStreamToString(inputStream);
// cache the result
if(requestCache != null){
requestCache.put(url, data);
}
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Log.d(JamendoApplication.TAG, "Caller.doGet "+url);
return data;
}
String data = null;
if(requestCache != null){
data = requestCache.get(url);
if(data != null){
Log.d(JamendoApplication.TAG, "Caller.doGet [cached] "+url);
return data;
}
}
可以看出如果存放缓存的requestCache不是null,而且根据要取的url作为key从HashTable里面取出的的数据不是null,那么久可以直接取出缓存的数据,否则就要从网络获取,从网络获取后将其加入到缓存中
if(requestCache != null){
requestCache.put(url, data);
}
public class ImageCache extends WeakHashMap<String, Bitmap> {
private static final long serialVersionUID = 1L;
public boolean isCached(String url){
return containsKey(url) && get(url) != null;
}
}
在PlayerActivity里面显示图片的空间不是直接用的ImageView而是RemoteImageView这个继承了ImageView的空间来处理的,在设置图片的时候是mCoverImageView.setImageUrl(playlistEntry.getAlbum().getImage().replaceAll("1.100.jpg", mBetterRes));是将在服务器上的地址传过来的
public void setImageUrl(String url){
if(mListView == null && mCurrentlyGrabbedUrl != null && mCurrentlyGrabbedUrl.equals(url)){
// do nothing image is grabbed & loaded, we are golden
return;
}
if(mUrl != null && mUrl.equals(url)){
mFailure++;
if(mFailure > MAX_FAILURES){
Log.e(JamendoApplication.TAG, "Failed to download "+url+", falling back to default image");
loadDefaultImage();
return;
}
} else {
mUrl = url;
mFailure = 0;
}
ImageCache imageCache = JamendoApplication.getInstance().getImageCache();
if(imageCache.isCached(url)){
this.setImageBitmap(imageCache.get(url));
}
else {
try{
new DownloadTask().execute(url);
} catch (RejectedExecutionException e) {
// do nothing, just don't crash
}
}
}
如果ImageCache里面有则直接从缓存里面取出,如果没有启动一个异步任务进行加载。如果在启动的异步任务里面加载完了图片则将他加入到缓存中
JamendoApplication.getInstance().getImageCache().put(mTaskUrl, bmp);