package com.tv.ui.metro.loader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.lang.reflect.Type; import java.net.PortUnreachableException; import java.util.Map; import android.content.Context; import android.support.v4.content.Loader; import android.text.TextUtils; import android.util.Log; import com.android.volley.AuthFailureError; import com.android.volley.NetworkResponse; import com.android.volley.ParseError; import com.android.volley.Request; import com.android.volley.Request.Method; import com.android.volley.Response; import com.android.volley.VolleyError; import com.android.volley.toolbox.HttpHeaderParser; import com.google.gson.Gson; import com.google.gson.JsonSyntaxException; import com.google.gson.reflect.TypeToken; import com.tv.ui.metro.model.DisplayItem; /** * Created by tv metro on 9/1/14. */ public abstract class BaseGsonLoader<T> extends Loader<T> { private final String TAG = "BaseGsonLoader"; protected int page = 1; protected final int page_size = 50; protected T mResult; protected volatile boolean mIsLoading; private ProgressNotifiable mProgressNotifiable; private boolean mHasDeliveredResult; protected String cacheFileName = ""; public abstract void setCacheFileName(); private static boolean mEnableCache = true; public static void enableCache(boolean _enable){ mEnableCache = _enable; } protected String calledURL = ""; public abstract void setLoaderURL(DisplayItem obj); public BaseGsonLoader(Context context) { super(context); init(null); } protected DisplayItem mItem; private void init(DisplayItem item){ mIsLoading = false; mHasDeliveredResult = false; mItem = item; setCacheFileName(); setLoaderURL(item); } public BaseGsonLoader(Context context, DisplayItem item) { super(context); init(item); } public int getCurrentPage(){ return page; } public void setProgressNotifiable(ProgressNotifiable progressNotifiable) { this.mProgressNotifiable = progressNotifiable; if (progressNotifiable != null) { progressNotifiable.init(dataExists(), mIsLoading); } } protected boolean dataExists() { // data exist and delivered to UI return mResult != null && mHasDeliveredResult; } @Override protected void onStartLoading() { if(mResult != null){ deliverResult(mResult); } if (!mIsLoading && (mResult == null || takeContentChanged())) { forceLoad(); } } @Override protected void onForceLoad() { //load from server mIsLoading = true; if (mProgressNotifiable != null) { mProgressNotifiable.startLoading(dataExists()); } loadDataByGson(); } protected Response.Listener<T> listener = new Response.Listener<T>() { @Override public void onResponse(T response) { mResult = response; deliverResult(response); mHasDeliveredResult = true; mIsLoading = false; if (mProgressNotifiable != null) { mProgressNotifiable.stopLoading(dataExists(), false); } } }; protected Response.ErrorListener errorListener = new Response.ErrorListener() { @Override public void onErrorResponse(VolleyError error) { Log.d(TAG, "onErrorResponse error:" + error.toString()); //means load from next page if(page > 1){ page--; } mIsLoading = false; if (mProgressNotifiable != null) { mProgressNotifiable.stopLoading(dataExists(), false); } deliverResult(null); } }; protected abstract void loadDataByGson(); public class GsonRequest<T> extends Request<T> { private final Gson gson = new Gson(); private final Type type; private final Map<String, String> headers; private final Response.Listener<T> listener; private String cacheFile; public void setCacheNeed(String _cacheFile){ cacheFile = _cacheFile; } public GsonRequest(String url, Type type, Map<String, String> headers, Response.Listener<T> listener, Response.ErrorListener errorListener) { super(Method.GET, url, errorListener); this.type = type; 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, type); long timeEnd = System.currentTimeMillis(); Log.d(TAG, "fromJson take time in ms: " + (timeEnd - timeStart)); Response<T> res = Response.success(fromJson, HttpHeaderParser.parseCacheHeaders(response)); if(mEnableCache && 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; } }