package se.emilsjolander.sprinkles; import java.util.Arrays; import java.util.List; import android.annotation.TargetApi; import android.app.LoaderManager; import android.app.LoaderManager.LoaderCallbacks; import android.content.Loader; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.os.Build; import android.os.Bundle; /** * Object representing a Query that will return a single result. * * @param <T> * The type of model to return */ public final class OneQuery<T extends Model> { /** * Implement to get results delivered from a asynchronous query. * * @param <T> * The type of model that the result will represent. */ public interface ResultHandler<T extends Model> { /** * @param result * The result of the query. * * @return whether or not you want updated result when something changes in the underlying data. * */ boolean handleResult(T result); } Class<T> resultClass; String sqlQuery; OneQuery() { } /** * Execute the query synchronously * * @return the result of the query. */ public T get() { final SQLiteDatabase db = Sprinkles.getDatabase(); final Cursor c = db.rawQuery(sqlQuery, null); T result = null; if (c.moveToFirst()) { List<String> colNames = Arrays.asList(c.getColumnNames()); result = Utils.getResultFromCursor(resultClass, c, colNames); } c.close(); return result; } /** * Execute the query synchronously * * @return the result of the query. */ public boolean exists() { final SQLiteDatabase db = Sprinkles.getDatabase(); final Cursor c = db.rawQuery(sqlQuery, null); boolean result = c.getCount() > 0; c.close(); return result; } /** * Execute the query asynchronously * * @param lm * The loader manager to use for loading the data * * @param handler * The ResultHandler to notify of the query result and any updates to that result. * * @param respondsToUpdatedOf * A list of models excluding the queried model that should also trigger a update to the result if they change. */ @SuppressWarnings("unchecked") @TargetApi(Build.VERSION_CODES.HONEYCOMB) public void getAsync(LoaderManager lm, ResultHandler<T> handler, Class<? extends Model>... respondsToUpdatedOf) { if (Model.class.isAssignableFrom(resultClass)) { respondsToUpdatedOf = Utils.concatArrays(respondsToUpdatedOf, new Class[] { resultClass }); } final int loaderId = sqlQuery.hashCode(); lm.initLoader(loaderId, null, getLoaderCallbacks(sqlQuery, resultClass, handler, respondsToUpdatedOf)); } @TargetApi(Build.VERSION_CODES.HONEYCOMB) private LoaderCallbacks<Cursor> getLoaderCallbacks(final String sqlQuery, final Class<T> resultClass, final ResultHandler<T> handler, final Class<? extends Model>[] respondsToUpdatedOf) { return new LoaderCallbacks<Cursor>() { @Override public void onLoaderReset(Loader<Cursor> loader) { if (!loader.isAbandoned()) { handler.handleResult(null); } } @Override public void onLoadFinished(Loader<Cursor> loader, Cursor c) { T result = null; if (c.moveToFirst()) { List<String> colNames = Arrays.asList(c.getColumnNames()); result = Utils.getResultFromCursor(resultClass, c, colNames); } if (!handler.handleResult(result)) { loader.abandon(); } } @Override public Loader<Cursor> onCreateLoader(int id, Bundle args) { return new CursorLoader(Sprinkles.sInstance.mContext, sqlQuery, respondsToUpdatedOf); } }; } }