package edu.vandy.presenter; import java.lang.ref.WeakReference; import java.util.List; import edu.vandy.MVP; import edu.vandy.common.GenericAsyncTask; import edu.vandy.common.GenericAsyncTaskOps; import edu.vandy.common.GenericModel; import edu.vandy.model.AcronymModel; import edu.vandy.model.aidl.AcronymExpansion; import edu.vandy.model.aidl.AcronymResults; import android.content.Context; import android.os.IBinder; import android.os.RemoteException; import android.util.Log; /** * This class plays the "Presenter" role in the Model-View-Presenter * (MVP) pattern by acting upon the Model and the View, i.e., it * retrieves data from the Model (e.g., AcronymModel) and formats it * for display in the View (e.g., DisplayExpansionActivity). It * expends the GenericModel superclass and implements * MVP.ProvidedPresenterOps and MVP.RequiredModelOps so it can be * created/managed by the GenericModel framework. It implements * GenericAsyncTaskOps so its doInBackground() method runs in a * background task. It implements AcronymResults so it can be the * target of asynchronous callback methods from the Model layer. */ public class AcronymPresenter extends GenericModel<MVP.RequiredPresenterOps, MVP.ProvidedModelOps, AcronymModel> implements GenericAsyncTaskOps<String, Void, List<AcronymExpansion>>, MVP.ProvidedPresenterOps, MVP.RequiredPresenterOps, AcronymResults { /** * A WeakReference used to access methods in the View layer. The * WeakReference enables garbage collection. */ private WeakReference<MVP.RequiredViewOps> mAcronymView; /** * The GenericAsyncTask used to synchronously expand an acronym in * a background thread via the Model layer. */ private GenericAsyncTask<String, Void, List<AcronymExpansion>, AcronymPresenter> mAsyncTask; /** * Keeps track of whether a call is already in progress and * ignores subsequent calls until the first call is done. */ private boolean mCallInProgress; /** * Store Acronym for error reporting purposes. */ private String mAcronym; /** * Default constructor that's needed by the GenericActivity * framework. */ public AcronymPresenter() { } /** * Hook method called when a new instance of AcronymPresenter is * created. One time initialization code goes here, e.g., storing * a WeakReference to the View layer and initializing the Model * layer. * * @param view * A reference to the View layer. */ @Override public void onCreate(MVP.RequiredViewOps view) { // Set the WeakReference. mAcronymView = new WeakReference<>(view); // Invoke the special onCreate() method in GenericModel, // passing in the AcronymModel class to instantiate/manage and // "this" to provide AcronymModel with this // MVP.RequiredModelOps instance. super.onCreate(AcronymModel.class, this); } /** * Hook method dispatched by the GenericActivity framework to * initialize the AcronymPresenter object after it's been created. * * @param view * The currently active MVP.RequiredViewOps. */ @Override public void onConfigurationChange(MVP.RequiredViewOps view) { Log.d(TAG, "onConfigurationChange() called"); // Reset the WeakReference. mAcronymView = new WeakReference<>(view); } /** * Hook method called to shutdown the Model layer. * * @param isChangingConfigurations * True if a runtime configuration triggered the onDestroy() call. */ @Override public void onDestroy(boolean isChangingConfigurations) { // Destroy the model. getModel().onDestroy(isChangingConfigurations); } /** * Initiate the synchronous acronym lookup when the user presses * the "Lookup Acronym Sync" button. It uses an AsyncTask to * avoid blocking the UI thread. * * @return false if a call is already in progress, else true. */ public boolean expandAcronymSync(String acronym) { if (mCallInProgress) return false; else { // Don't allow concurrent calls to get the weather. mCallInProgress = true; // Store this for error reporting purposes. mAcronym = acronym; // Execute the AsyncTask to expand the acronym without // blocking the caller. mAsyncTask = new GenericAsyncTask<>(this); mAsyncTask.execute(mAcronym); return true; } } /** * Retrieve the expanded acronym results via a synchronous two-way * method call, which runs in a background thread to avoid * blocking the UI thread. */ @Override public List<AcronymExpansion> doInBackground(String... acronyms) { // Get the acronym expansions synchronously. return getModel().getAcronymExpansions(acronyms[0]); } /** * Display the results in the UI Thread. */ @Override public void onPostExecute(List<AcronymExpansion> acronymExpansions) { displayResults(acronymExpansions, "no expansions for " + mAcronym + " found"); } /** * Initiate the synchronous acronym lookup when the user presses * the "Lookup Acronym Async" button. * * @return false if a call is already in progress, else true. */ public boolean expandAcronymAsync(String acronym) { if (mCallInProgress) return false; else { // Don't allow concurrent calls to get the weather. mCallInProgress = true; // Store this for error reporting purposes. mAcronym = acronym; // Get the acronym expansions asynchronously. The results // are returned via the sendResults() and sendError() hook // methods below. getModel().getAcronymExpansions(acronym, this); return true; } } /** * This hook method is called back by the Model layer and returns * AcronymExpansion results back to the View layer. */ @Override public void sendResults(final List<AcronymExpansion> acronymExpansions) throws RemoteException { displayResults(acronymExpansions, (String) null); } /** * This hook method is called back by the Model layer and returns * error results back to the View layer. */ @Override public void sendError(final String reason) throws RemoteException { displayResults(null, reason); } /** * Call back to the View layer to display the results. */ @Override public void displayResults(List<AcronymExpansion> results, String failureReason) { // Display the results. mAcronymView.get().displayResults(results, failureReason); // Call is no longer in progress. mCallInProgress = false; } /** * Return the Activity context. */ @Override public Context getActivityContext() { return mAcronymView.get().getActivityContext(); } /** * Return the Application context. */ @Override public Context getApplicationContext() { return mAcronymView.get().getApplicationContext(); } /** * A no-op needed to make the compiler happy since we implement * the AcronymResult interface. */ @Override public IBinder asBinder() { return null; } }