package com.nominanuda.hyperapi.async;
import android.app.LoaderManager;
import android.content.AsyncTaskLoader;
import android.content.Context;
import android.content.Loader;
import android.os.Bundle;
import android.util.Pair;
import com.nominanuda.web.http.Http500Exception;
import com.nominanuda.web.http.HttpAppException;
import com.nominanuda.zen.common.Util;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* Created by azum on 13/05/17.
*/
public class AsyncLoaderInvocationHandler<API, T> implements InvocationHandler {
private static class AsyncCallLoader<API, RESULT> extends AsyncTaskLoader<Pair<RESULT, Exception>> {
private final API mApi;
private final Method mMethod;
private final Object[] mMethodArgs;
private AsyncCallLoader(Context ctx, API api, Method method, Object[] methodArgs) {
super(ctx);
mApi = api;
mMethod = method;
mMethodArgs = methodArgs;
// new ForceLoadContentObserver(); TODO?
}
@Override
protected void onStartLoading() {
forceLoad();
}
@Override
protected void onStopLoading() {
cancelLoad();
}
@Override
protected void onForceLoad() {
super.onForceLoad();
}
@Override
protected void onReset() {
onStopLoading();
}
@Override
public Pair<RESULT, Exception> loadInBackground() {
try {
RESULT data = (RESULT) mMethod.invoke(mApi, mMethodArgs);
return new Pair<RESULT, Exception>(data, null);
} catch (InvocationTargetException e) {
e.printStackTrace();
Throwable cause = e.getCause();
return new Pair<RESULT, Exception>(null, (cause != null && cause instanceof HttpAppException)
? (HttpAppException) cause
: new Http500Exception(e)
);
} catch (Exception e) {
e.printStackTrace();
return new Pair<RESULT, Exception>(null, e);
}
}
@Override
public void deliverResult(Pair<RESULT, Exception> result) {
if (isStarted()) {
super.deliverResult(result);
}
}
}
private final Context mCtx;
private final LoaderManager mLoaderManager;
private final API mApi;
private final Util.Consumer<T> mResultFnc;
private final Util.Consumer<Exception> mErrorFnc;
AsyncLoaderInvocationHandler(Context ctx, LoaderManager loaderManager, API api,
Util.Consumer<T> resultFnc, Util.Consumer<Exception> errorFnc) {
mCtx = ctx;
mLoaderManager = loaderManager;
mApi = api;
mResultFnc = resultFnc;
mErrorFnc = errorFnc;
}
@Override
public Object invoke(Object proxy, Method method, Object[] methodArgs) throws Throwable {
final int loaderId = (int) (Math.random() * 10000); // TODO uniqueness
mLoaderManager.initLoader(loaderId, null, new LoaderManager.LoaderCallbacks<Pair<T, Exception>>() {
@Override
public Loader<Pair<T, Exception>> onCreateLoader(int id, Bundle args) {
return new AsyncCallLoader<API, T>(mCtx, mApi, method, methodArgs);
}
@Override
public void onLoadFinished(Loader<Pair<T, Exception>> loader, Pair<T, Exception> result) {
if (result.second != null) {
mErrorFnc.accept(result.second);
} else {
mResultFnc.accept(result.first);
}
mLoaderManager.destroyLoader(loaderId);
}
@Override
public void onLoaderReset(Loader<Pair<T, Exception>> loader) {
}
});
return null; // just for signature check
}
}