package com.tv.ui.metro.loader; import android.content.Context; import android.database.Cursor; import android.os.AsyncTask; import android.support.v4.content.Loader; import android.text.TextUtils; import android.util.Log; import android.util.Pair; import com.android.volley.*; import com.android.volley.toolbox.HttpHeaderParser; import com.google.gson.Gson; import com.google.gson.JsonSyntaxException; import com.tv.ui.metro.idata.iDataORM; import org.json.JSONObject; import java.io.*; import java.util.ArrayList; import java.util.Map; /** * Created by tv metro on 8/28/14. */ public class BaseLoader<T> extends Loader<T> { private static final String TAG = "BaseLoader"; protected T mResult; protected volatile boolean mIsLoading; protected boolean mNeedFile; protected boolean mNeedDatabase; protected boolean mNeedServer; protected boolean mNeedDeliverResult; private boolean mHasDeliverdResult; private ArrayList<AsyncTask<Void, Void, T>> mTaskList; private int mNextExecuteTask; private ProgressNotifiable mProgressNotifiable; private volatile boolean mDatabaseSave;//更新时间是否保存过了 protected volatile int mCurrPageGameCount = -1;//如果此值小于要请求的个数表示没有下页了 protected long mStampTime = -1;//时间戳 protected final static int FIRST_PAGE_NUM = 1; protected int mPage = FIRST_PAGE_NUM;//分页从1开始 protected boolean mNeedNextPage; public BaseLoader(Context context) { super(context); init(); } public void nextPage() { if (mNeedNextPage) { mPage++; } // 只要翻页了,就不需要从数据库取数据,只从服务器取数据 setNeedDatabase(false); } private void init(){ mIsLoading = false; mNeedFile = false; mNeedDatabase = true; mNeedServer = true; mNeedDeliverResult = true; mHasDeliverdResult = false; mTaskList = new ArrayList<AsyncTask<Void, Void, T>>(); mNextExecuteTask = 0; mPage = FIRST_PAGE_NUM; mNeedNextPage = false; } public void setNeedFile(boolean needFile) { this.mNeedFile = needFile; } public void setNeedDatabase(boolean needDatabase) { this.mNeedDatabase = needDatabase; } public void setNeedServer(boolean needServer) { this.mNeedServer = needServer; } /** * 保存更新时间 * @param key * @param updateTime */ protected void saveUpdateTime(String key, long updateTime){ if(!mDatabaseSave && updateTime != -1){ mDatabaseSave = true; iDataORM.getInstance(getContext()).addSetting(key, String.valueOf(updateTime)); } } //获取上次更新的时间 protected long getLastTime(String key){ return iDataORM.getInstance(getContext()).getLongValue(key, -1); } //设置该值后,后续任务执行完均会根据设定值处理数据 public void setNeedDeliverResult(boolean needDeliverResult) { this.mNeedDeliverResult = needDeliverResult;//BUG } public boolean hasMoreData(){ if(-1 == mCurrPageGameCount ){ return false; }else{ return true; } } public boolean isLoading() { return mIsLoading; } public void setProgressNotifiable(ProgressNotifiable progressNotifiable) { this.mProgressNotifiable = progressNotifiable; // 注册监听器时直接告知当前状态 if (progressNotifiable != null) { progressNotifiable.init(dataExists(), mIsLoading); } } @Override protected void onStartLoading() { if (mResult != null) { //这里浅克隆结果避免由于结果完全一致,不会刷新界面 deliverResult((T)mResult); } if (!mIsLoading && (mResult == null || takeContentChanged())) { forceLoad(); } } @Override protected void onForceLoad() { mTaskList.clear(); mNextExecuteTask = 0; initTaskList(mTaskList); executeNextTask(); } //子类可以继承该方法自定义任务列表,此时默认列表不起作用(一个数据库任务和一个网络任务) protected void initTaskList(ArrayList<AsyncTask<Void, Void, T>> tasks) { if (mNeedDatabase) { DatabaseLoader task = getDatabaseLoader(); if (task != null) { tasks.add(task); } } if(mNeedFile){ FileLoader task = getFileLoader(); if(task != null){ tasks.add(task); } } if (mNeedServer) { UpdateLoader task = getUpdateLoader(); if (task != null) { tasks.add(task); } } } //调用该方法将会执行下一个任务 protected void executeNextTask() { if (hasNextTask()) { AsyncTask<Void, Void, T> task = null; while (task == null && hasNextTask()) { task = mTaskList.get(mNextExecuteTask); mNextExecuteTask ++; } if (task != null) { task.execute(); } } } protected boolean hasNextTask() { return mNextExecuteTask < mTaskList.size(); } protected FileLoader getFileLoader() { return null; } protected DatabaseLoader getDatabaseLoader() { return null; } protected UpdateLoader getUpdateLoader() { return null; } protected boolean dataExists() { // 数据存在并且已经发送给界面过 return mResult != null && mHasDeliverdResult; } //子类的任务都需要继承该类以获得任务管理和进度通知特性 protected abstract class BaseTaskLoader extends AsyncTask<Void, Void, T> { @Override protected void onPreExecute() { mIsLoading = true; if (mProgressNotifiable != null) { mProgressNotifiable.startLoading(dataExists()); } } @Override protected void onPostExecute(T result) { mIsLoading = false; if (isResultValid(result)) { mResult = result; if (mNeedDeliverResult) { BaseLoader.this.deliverResult(result); mHasDeliverdResult = true; } } if (mProgressNotifiable != null) { mProgressNotifiable.stopLoading(dataExists(), hasNextTask()); } BaseLoader.this.executeNextTask(); } //检查结果是否有效,如果有效,则会更新数据,并告知界面 protected boolean isResultValid(T result) { return result != null; } } //从数据库将数据载入缓存 protected abstract class DatabaseLoader extends BaseTaskLoader { @Override protected T doInBackground(Void... params) { Cursor cursor = loadFromDB(); T newResult = parseResult(cursor); if(cursor != null){ cursor.close(); cursor = null; } T result = onDataLoaded(mResult, newResult); return result; } //从数据库中读取数据 protected abstract Cursor loadFromDB(); //从cursor中获取数据,如果没有数据则返回null protected abstract T parseResult(Cursor cursor); //子类可以对获取的数据进行处理,如果该方法返回null,则数据和界面不会更新 protected T onDataLoaded(T oldResult, T newResult) { return newResult; } } //从文件将数据载入缓存 protected abstract class FileLoader extends BaseTaskLoader { @Override protected T doInBackground(Void... params) { String data = loadFromLocalFile(); if(!TextUtils.isEmpty(data)){ T newResult = parseResult(data); T result = onDataLoaded(mResult, newResult); return result; }else{ return null; } } //从文件流中读取数据 protected String loadFromLocalFile() { InputStream fis = null; String data = null; try { File f = new File(localDataFileName()); if(f.exists() && f.length() > 0){ fis = new FileInputStream(f); byte[] buffer = new byte[(int)f.length()]; fis.read(buffer); data = new String(buffer); } } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if(fis != null){ try { fis.close(); } catch (IOException e) { e.printStackTrace(); } fis = null; } } return data; } protected abstract String localDataFileName(); // 从String中获取数据,如果没有数据则返回null protected abstract T parseResult(String data); //子类可以对获取的数据进行处理,如果该方法返回null,则数据和界面不会更新 protected T onDataLoaded(T oldResult, T newResult) { return newResult; } } public class GsonRequest<T> extends Request<T> { private final Gson gson = new Gson(); private final Class<T> clazz; private final Map<String, String> headers; private final Response.Listener<T> listener; private String cacheFile; public void setCacheNeed(String _cacheFile){ cacheFile = _cacheFile; } /** * Make a GET request and return a parsed object from JSON. * * @param url * URL of the request to make * @param clazz * Relevant class object, for Gson's reflection * @param headers * Map of request headers */ public GsonRequest(String url, Class<T> clazz, Map<String, String> headers, Response.Listener<T> listener, Response.ErrorListener errorListener) { super(Method.GET, url, errorListener); this.clazz = clazz; this.headers = headers; this.listener = listener; } @Override public Map<String, String> getHeaders() throws AuthFailureError { return headers != null ? headers : super.getHeaders(); } @Override protected void deliverResponse(T response) { listener.onResponse(response); } @Override protected Response<T> parseNetworkResponse(NetworkResponse response) { try { String json = new String(response.data, HttpHeaderParser.parseCharset(response.headers)); Log.d(TAG, "response json:" + json); long timeStart = System.currentTimeMillis(); T fromJson = gson.fromJson(json, clazz); long timeEnd = System.currentTimeMillis(); Log.d(TAG, "fromJson take time in ms: " + (timeEnd - timeStart)); Response<T> res = Response.success(fromJson, HttpHeaderParser.parseCacheHeaders(response)); if(cacheFile != null && cacheFile.length() > 0){ //save to files updateToFile(cacheFile, json); } return res; } catch (UnsupportedEncodingException e) { return Response.error(new ParseError(e)); } catch (JsonSyntaxException e) { return Response.error(new ParseError(e)); } } } public static void updateToFile(String fileName, String response){ if(null == response || TextUtils.isEmpty(fileName)){ return; } File f = new File(fileName); if(f.exists()){ f.delete(); } FileOutputStream fos = null; try { fos = new FileOutputStream(f); fos.write(response.getBytes()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally{ if(fos != null){ try { fos.close(); fos = null; } catch (IOException e) { e.printStackTrace(); } } } } public static StringBuilder readCacheFromFile(String filePath){ StringBuilder sb = new StringBuilder(); File f = new File(filePath); if(f.exists() == false){ return sb; } FileInputStream fin = null; try { fin = new FileInputStream(new File(filePath)); byte []buffer = new byte[4096*2]; int len = -1; while((len = fin.read(buffer, 0, 4096*2)) > 0){ sb.append(buffer); } buffer = null; } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally{ if(fin != null){ try { fin.close(); fin = null; } catch (IOException e) { e.printStackTrace(); } } } return sb; } //从服务器将数据载入缓存和数据库 protected abstract class UpdateLoader extends BaseTaskLoader { @Override protected T doInBackground(Void... params) { loadData(); return null; } protected abstract void loadData(); // 从Json中获取数据,如果没有数据则返回null/ protected abstract T parseResult(JSONObject json); //子类可以对获取的数据进行处理,如果该方法返回null,则数据和界面不会更新/ protected T onDataLoaded(T oldResult, T newResult) { return newResult; } } }