在醒目中对于进行数据缓存和图片缓存的对象是在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);