package io.github.xwz.base.api; import android.content.Context; import android.net.Uri; import android.os.AsyncTask; import android.os.Build; import android.os.StatFs; import android.util.Log; import com.squareup.okhttp.Cache; import com.squareup.okhttp.CacheControl; import com.squareup.okhttp.OkHttpClient; import com.squareup.okhttp.Request; import com.squareup.okhttp.Response; import com.squareup.okhttp.ResponseBody; import org.json.JSONException; import org.json.JSONObject; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeUnit; import io.github.xwz.base.trie.RadixTree; public abstract class HttpApiBase extends AsyncTask<String, Void, Void> { private static final String TAG = "HttpApiBase"; private static final int MIN_DISK_CACHE_SIZE = 8 * 1024 * 1024; // 8MB private static final int MAX_DISK_CACHE_SIZE = 64 * 1024 * 1024; // 64MB private static final float MAX_AVAILABLE_SPACE_USE_FRACTION = 0.5f; private static final float MAX_TOTAL_SPACE_USE_FRACTION = 0.1f; private final OkHttpClient client = new OkHttpClient(); private Context mContext = null; private boolean useCache = true; public HttpApiBase(Context context) { mContext = context; } protected CacheControl allowStaleCache(int seconds) { return new CacheControl.Builder().maxStale(seconds, TimeUnit.SECONDS).build(); } protected void setEnableCache(boolean enable) { useCache = enable; } private Cache createCache(Context context) { File cacheDir = createDefaultCacheDir(context, getCachePath()); long cacheSize = calculateDiskCacheSize(cacheDir); Log.i(TAG, "iview API disk cache:" + cacheDir + ", size:" + (cacheSize / 1024 / 1024) + "MB"); return new Cache(cacheDir, cacheSize); } abstract protected String getCachePath(); protected Context getContext() { return mContext; } protected JSONObject parseJSON(String content) { if (content != null) { try { return new JSONObject(content); } catch (JSONException e) { e.printStackTrace(); } } return null; } private void ensureCache() { if (useCache && client.getCache() == null) { Cache cache = createCache(getContext()); if (cache != null) { client.setCache(cache); } } } protected String fetchUrl(Uri url, int staleness) { ensureCache(); return extractBody(fetchFromNetwork(url, staleness)); } protected String fetchUrlSkipLocalCache(Uri url, int staleness) { return extractBody(fetchFromNetwork(url, staleness)); } private String extractBody(ResponseBody body) { if (body != null) { try { return body.string(); } catch (IOException e) { e.printStackTrace(); } } return null; } protected InputStream fetchStream(Uri url, int staleness) { ensureCache(); ResponseBody body = fetchFromNetwork(url, staleness); if (body != null) { try { return body.byteStream(); } catch (IOException e) { e.printStackTrace(); } } return null; } private ResponseBody fetchFromNetwork(Uri url, int staleness) { Request.Builder builder = new Request.Builder(); builder.url(url.toString()); if (staleness > 0) { builder.cacheControl(allowStaleCache(staleness)); } Request request = builder.build(); client.setConnectTimeout(10, TimeUnit.SECONDS); client.setReadTimeout(60, TimeUnit.SECONDS); Log.d(TAG, "Requesting URL:" + request.urlString()); try { Response response = client.newCall(request).execute(); if (response.cacheResponse() != null) { Log.d(TAG, "Cached response [" + response.code() + "]:" + request.urlString()); } else { Log.d(TAG, "Network response [" + response.code() + "]:" + request.urlString()); } if (response.isSuccessful()) { return response.body(); } } catch (IOException e) { e.printStackTrace(); } return null; } @SuppressWarnings({"unchecked", "TypeParameterExplicitlyExtendsObject"}) protected static <T extends Object> T get(JSONObject data, String key, T fallback) { T value = null; try { value = data != null && key != null ? (T) data.get(key) : null; } catch (JSONException e) { //Log.d(TAG, "No string value for: " + key); } return value != null ? value : fallback; } private static File createDefaultCacheDir(Context context, String path) { File cacheDir = context.getApplicationContext().getExternalCacheDir(); if (cacheDir == null) { cacheDir = context.getApplicationContext().getCacheDir(); } File cache = new File(cacheDir, path); if (!cache.exists()) { //noinspection ResultOfMethodCallIgnored cache.mkdirs(); } return cache; } private static long calculateDiskCacheSize(File dir) { long size = Math.min(calculateAvailableCacheSize(dir), MAX_DISK_CACHE_SIZE); return Math.max(size, MIN_DISK_CACHE_SIZE); } @SuppressWarnings("deprecation") private static long calculateAvailableCacheSize(File dir) { long size = 0; try { StatFs statFs = new StatFs(dir.getAbsolutePath()); int sdkInt = Build.VERSION.SDK_INT; long totalBytes; long availableBytes; if (sdkInt < Build.VERSION_CODES.JELLY_BEAN_MR2) { int blockSize = statFs.getBlockSize(); availableBytes = ((long) statFs.getAvailableBlocks()) * blockSize; totalBytes = ((long) statFs.getBlockCount()) * blockSize; } else { availableBytes = statFs.getAvailableBytes(); totalBytes = statFs.getTotalBytes(); } size = (long) Math.min(availableBytes * MAX_AVAILABLE_SPACE_USE_FRACTION, totalBytes * MAX_TOTAL_SPACE_USE_FRACTION); } catch (IllegalArgumentException ignored) { // ignored } return size; } }