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;
}
}