package com.netease.nim.demo.common.infra; import android.os.Handler; public abstract class Task { private static final String ENCLOSURE = "<>"; private static final int RETRY_COUNT = 1; /*package*/ static class Info { /** background */ boolean background; /** key */ String key; /** parameters */ Object[] params; Info(boolean background, String key, Object[] params) { this.background = background; this.key = key; this.params = params; } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("B"); sb.append(ENCLOSURE.charAt(0)); sb.append(background ? "T" : "F"); sb.append(ENCLOSURE.charAt(1)); sb.append(" "); sb.append("K"); sb.append(ENCLOSURE.charAt(0)); sb.append(key); sb.append(ENCLOSURE.charAt(1)); return sb.toString(); } } /*package*/ static class State { /** cancelled */ boolean cancelled; /** chances */ int chances; /** pending */ boolean pending; /** fault */ boolean fault; State() { } @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("C"); sb.append(ENCLOSURE.charAt(0)); sb.append(chances); sb.append(ENCLOSURE.charAt(1)); sb.append(" "); sb.append("P"); sb.append(ENCLOSURE.charAt(0)); sb.append(pending ? "T" : "F"); sb.append(ENCLOSURE.charAt(1)); return sb.toString(); } } /** handler for publish states */ /*package*/ Handler handler; /** task info */ /*package*/ Info info; /** task state */ /*package*/ State state; public void cancel() { state.cancelled = true; } public void setProperty(int prop, Object data) { // NOP } protected boolean background() { return info.background; } protected String key() { return info.key; } protected Object[] params() { return info.params; } protected boolean cancelled() { return state.cancelled; } protected int scheduled() { return state.chances; } protected void pending() { state.pending = true; } protected boolean giveup() { // give up boolean giveup = scheduled() > RETRY_COUNT; // mark pending if proceed if (!giveup) { pending(); } return giveup; } /*package*/ boolean schedule() { // update chances state.chances++; // reset pending state.pending = false; // execute Object[] results = null; try { results = execute(info.params); } catch (Throwable tr) { onException(tr); // fault state.fault = true; } // no fault and pending if (!state.fault && state.pending) { // not proceed return false; } // publish result publishResult(results); return true; } /** * execute * * @param params * @return results */ protected abstract Object[] execute(Object[] params); /** * on exception * @param tr throwable */ protected void onException(Throwable tr) { // save // AppCrashHandler.getInstance(null).saveException(tr, false); }; /** * on handle result * @param results */ protected void onHandleResult(Object[] results) {}; /** * on publish result * @param results */ protected void onPublishResult(Object[] results) {} /** * on publish progress * @param params */ protected void onPublishProgress(Object[] params) {} /** * publish result * @param results */ protected final void publishResult(Object[] results) { publish(true, results); } /** * publish progress * @param params */ protected final void publishProgress(Object[] params) { publish(false, params); } private final void publish(final boolean result, final Object[] params) { if (info.background && handler != null) { // shift to looper thread of handler to publish handler.post(new Runnable() { @Override public void run() { // publish on current thread onPublish(result, params); } }); } else { // publish on current thread onPublish(result, params); } } private final void onPublish(boolean result, Object[] params) { if (result) { onHandleResult(params); onPublishResult(params); } else { onPublishProgress(params); } } public final String dump(boolean statefull) { StringBuilder sb = new StringBuilder(); // info sb.append(info); // state if (statefull) { sb.append(" "); sb.append(state); } return sb.toString(); } @Override public String toString() { return dump(true); } }