Merge pull request #3483 from sigmabeta/android-rx-db-access
[Android] Refactor DB read code to use RxJava
This commit is contained in:
commit
aa89516cf3
|
@ -89,6 +89,9 @@ dependencies {
|
|||
|
||||
// For loading huge screenshots from the disk.
|
||||
compile 'com.squareup.picasso:picasso:2.5.2'
|
||||
|
||||
// Allows FRP-style asynchronous operations in Android.
|
||||
compile 'io.reactivex:rxandroid:1.1.0'
|
||||
}
|
||||
|
||||
task setupCMake(type: Exec) {
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
|
||||
<application
|
||||
android:name=".DolphinApplication"
|
||||
android:label="@string/app_name"
|
||||
android:icon="@drawable/ic_launcher"
|
||||
android:allowBackup="true"
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
package org.dolphinemu.dolphinemu;
|
||||
|
||||
import android.app.Application;
|
||||
|
||||
import org.dolphinemu.dolphinemu.model.GameDatabase;
|
||||
|
||||
|
||||
public class DolphinApplication extends Application
|
||||
{
|
||||
public static GameDatabase databaseHelper;
|
||||
|
||||
@Override
|
||||
public void onCreate()
|
||||
{
|
||||
super.onCreate();
|
||||
|
||||
databaseHelper = new GameDatabase(this);
|
||||
}
|
||||
}
|
|
@ -1,9 +1,6 @@
|
|||
package org.dolphinemu.dolphinemu.activities;
|
||||
|
||||
import android.app.LoaderManager;
|
||||
import android.content.CursorLoader;
|
||||
import android.content.Intent;
|
||||
import android.content.Loader;
|
||||
import android.content.SharedPreferences;
|
||||
import android.database.Cursor;
|
||||
import android.os.Bundle;
|
||||
|
@ -34,20 +31,11 @@ import org.dolphinemu.dolphinemu.utils.StartupHandler;
|
|||
* The main Activity of the Lollipop style UI. Manages several PlatformGamesFragments, which
|
||||
* individually display a grid of available games for each Fragment, in a tabbed layout.
|
||||
*/
|
||||
public final class MainActivity extends AppCompatActivity implements LoaderManager.LoaderCallbacks<Cursor>
|
||||
public final class MainActivity extends AppCompatActivity
|
||||
{
|
||||
public static final int REQUEST_ADD_DIRECTORY = 1;
|
||||
public static final int REQUEST_EMULATE_GAME = 2;
|
||||
|
||||
/**
|
||||
* It is important to keep track of loader ID separately from platform ID (see Game.java)
|
||||
* because we could potentially have Loaders that load things other than Games.
|
||||
*/
|
||||
public static final int LOADER_ID_ALL = 100; // TODO
|
||||
public static final int LOADER_ID_GAMECUBE = 0;
|
||||
public static final int LOADER_ID_WII = 1;
|
||||
public static final int LOADER_ID_WIIWARE = 2;
|
||||
|
||||
private ViewPager mViewPager;
|
||||
private PlatformPagerAdapter mPlatformPagerAdapter;
|
||||
|
||||
|
@ -175,132 +163,6 @@ public final class MainActivity extends AppCompatActivity implements LoaderManag
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Callback that's invoked when the system has initialized the Loader and
|
||||
* is ready to start the query. This usually happens when initLoader() is
|
||||
* called. Here, we use it to make a DB query for games.
|
||||
*
|
||||
* @param id The ID value passed to the initLoader() call that triggered this.
|
||||
* @param args The args bundle supplied by the caller.
|
||||
* @return A new Loader instance that is ready to start loading.
|
||||
*/
|
||||
@Override
|
||||
public Loader<Cursor> onCreateLoader(int id, Bundle args)
|
||||
{
|
||||
Log.d("DolphinEmu", "Creating loader with id: " + id);
|
||||
|
||||
// Take action based on the ID of the Loader that's being created.
|
||||
switch (id)
|
||||
{
|
||||
case LOADER_ID_ALL:
|
||||
// TODO Play some sort of load-starting animation; maybe fade the list out.
|
||||
|
||||
return new CursorLoader(
|
||||
this, // Parent activity context
|
||||
GameProvider.URI_GAME, // URI of table to query
|
||||
null, // Return all columns
|
||||
null, // No selection clause
|
||||
null, // No selection arguments
|
||||
GameDatabase.KEY_GAME_TITLE + " asc" // Sort by game name, ascending order
|
||||
);
|
||||
|
||||
case LOADER_ID_GAMECUBE:
|
||||
case LOADER_ID_WII:
|
||||
case LOADER_ID_WIIWARE:
|
||||
// TODO Play some sort of load-starting animation; maybe fade the list out.
|
||||
|
||||
return new CursorLoader(
|
||||
this, // Parent activity context
|
||||
GameProvider.URI_GAME, // URI of table to query
|
||||
null, // Return all columns
|
||||
GameDatabase.KEY_GAME_PLATFORM + " = ?", // Select by platform
|
||||
new String[]{Integer.toString(id)}, // Platform id is Loader id
|
||||
GameDatabase.KEY_GAME_TITLE + " asc" // Sort by game name, ascending order
|
||||
);
|
||||
|
||||
default:
|
||||
Log.e("DolphinEmu", "Bad ID passed in.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback that's invoked when the Loader returned in onCreateLoader is finished
|
||||
* with its task. In this case, the game DB query is finished, so we should put the results
|
||||
* on screen.
|
||||
*
|
||||
* @param loader The loader that finished.
|
||||
* @param data The data the Loader loaded.
|
||||
*/
|
||||
@Override
|
||||
public void onLoadFinished(Loader<Cursor> loader, Cursor data)
|
||||
{
|
||||
int id = loader.getId();
|
||||
Log.d("DolphinEmu", "Loader finished with id: " + id);
|
||||
|
||||
PlatformGamesFragment fragment = null;
|
||||
switch (id)
|
||||
{
|
||||
case LOADER_ID_GAMECUBE:
|
||||
fragment = getPlatformFragment(Game.PLATFORM_GC);
|
||||
break;
|
||||
|
||||
case LOADER_ID_WII:
|
||||
fragment = getPlatformFragment(Game.PLATFORM_WII);
|
||||
break;
|
||||
|
||||
case LOADER_ID_WIIWARE:
|
||||
fragment = getPlatformFragment(Game.PLATFORM_WII_WARE);
|
||||
break;
|
||||
|
||||
// TODO case LOADER_ID_ALL:
|
||||
|
||||
default:
|
||||
Log.e("DolphinEmu", "Bad ID passed in.");
|
||||
break;
|
||||
}
|
||||
|
||||
if (fragment != null)
|
||||
{
|
||||
fragment.onLoadFinished(loader, data);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLoaderReset(Loader<Cursor> loader)
|
||||
{
|
||||
int id = loader.getId();
|
||||
Log.e("DolphinEmu", "Loader resetting with id: " + id);
|
||||
|
||||
PlatformGamesFragment fragment = null;
|
||||
switch (id)
|
||||
{
|
||||
case LOADER_ID_GAMECUBE:
|
||||
fragment = getPlatformFragment(Game.PLATFORM_GC);
|
||||
break;
|
||||
|
||||
case LOADER_ID_WII:
|
||||
fragment = getPlatformFragment(Game.PLATFORM_WII);
|
||||
break;
|
||||
|
||||
case LOADER_ID_WIIWARE:
|
||||
fragment = getPlatformFragment(Game.PLATFORM_WII_WARE);
|
||||
break;
|
||||
|
||||
// TODO case LOADER_ID_ALL:
|
||||
|
||||
default:
|
||||
Log.e("DolphinEmu", "Bad ID passed in.");
|
||||
break;
|
||||
}
|
||||
|
||||
if (fragment != null)
|
||||
{
|
||||
fragment.onLoaderReset();
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PlatformGamesFragment getPlatformFragment(int platform)
|
||||
{
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package org.dolphinemu.dolphinemu.fragments;
|
||||
|
||||
import android.app.Fragment;
|
||||
import android.app.LoaderManager;
|
||||
import android.content.Loader;
|
||||
import android.database.Cursor;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.Nullable;
|
||||
|
@ -15,8 +13,14 @@ import android.view.View;
|
|||
import android.view.ViewGroup;
|
||||
|
||||
import org.dolphinemu.dolphinemu.BuildConfig;
|
||||
import org.dolphinemu.dolphinemu.DolphinApplication;
|
||||
import org.dolphinemu.dolphinemu.R;
|
||||
import org.dolphinemu.dolphinemu.adapters.GameAdapter;
|
||||
import org.dolphinemu.dolphinemu.model.GameDatabase;
|
||||
|
||||
import rx.android.schedulers.AndroidSchedulers;
|
||||
import rx.functions.Action1;
|
||||
import rx.schedulers.Schedulers;
|
||||
|
||||
public class PlatformGamesFragment extends Fragment
|
||||
{
|
||||
|
@ -69,9 +73,7 @@ public class PlatformGamesFragment extends Fragment
|
|||
|
||||
recyclerView.addItemDecoration(new GameAdapter.SpacesItemDecoration(8));
|
||||
|
||||
// Create an adapter that will relate the dataset to the views on-screen. +1 because of LOADER_ID_ALL
|
||||
getLoaderManager().initLoader(mPlatform, null,
|
||||
(LoaderManager.LoaderCallbacks<Cursor>) getActivity());
|
||||
loadGames();
|
||||
|
||||
mAdapter = new GameAdapter();
|
||||
recyclerView.setAdapter(mAdapter);
|
||||
|
@ -87,32 +89,35 @@ public class PlatformGamesFragment extends Fragment
|
|||
public void refresh()
|
||||
{
|
||||
Log.d("DolphinEmu", "[PlatformGamesFragment] " + mPlatform + ": Refreshing...");
|
||||
// +1 because of LOADER_ID_ALL
|
||||
getLoaderManager().restartLoader(mPlatform, null, (LoaderManager.LoaderCallbacks<Cursor>) getActivity());
|
||||
loadGames();
|
||||
}
|
||||
|
||||
public void onLoadFinished(Loader<Cursor> loader, Cursor data)
|
||||
public void loadGames()
|
||||
{
|
||||
// TODO Play some sort of load-finished animation; maybe fade the list in.
|
||||
Log.d("DolphinEmu", "[PlatformGamesFragment] " + mPlatform + ": Loading games...");
|
||||
|
||||
Log.d("DolphinEmu", "[PlatformGamesFragment] " + mPlatform + ": Load finished, swapping cursor...");
|
||||
Log.d("DolphinEmu", "[PlatformGamesFragment] " + mPlatform + ": Cursor size: " + data.getCount());
|
||||
if (mAdapter != null)
|
||||
{
|
||||
mAdapter.swapCursor(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.e("DolphinEmu", "[PlatformGamesFragment] " + mPlatform + ": No adapter available.");
|
||||
}
|
||||
}
|
||||
GameDatabase databaseHelper = DolphinApplication.databaseHelper;
|
||||
|
||||
public void onLoaderReset()
|
||||
{
|
||||
Log.e("DolphinEmu", "[PlatformGamesFragment] " + mPlatform + ": Loader reset; clearing data from view.");
|
||||
if (mAdapter != null)
|
||||
{
|
||||
mAdapter.swapCursor(null);
|
||||
}
|
||||
databaseHelper.getGamesForPlatform(mPlatform)
|
||||
.subscribeOn(Schedulers.io())
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe(new Action1<Cursor>()
|
||||
{
|
||||
@Override
|
||||
public void call(Cursor data)
|
||||
{
|
||||
Log.d("DolphinEmu", "[PlatformGamesFragment] " + mPlatform + ": Load finished, swapping cursor...");
|
||||
|
||||
if (mAdapter != null)
|
||||
{
|
||||
mAdapter.swapCursor(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
Log.e("DolphinEmu", "[PlatformGamesFragment] " + mPlatform + ": No adapter available.");
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,6 +14,9 @@ import java.util.Arrays;
|
|||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import rx.Observable;
|
||||
import rx.Subscriber;
|
||||
|
||||
/**
|
||||
* A helper class that provides several utilities simplifying interaction with
|
||||
* the SQLite database.
|
||||
|
@ -252,4 +255,44 @@ public final class GameDatabase extends SQLiteOpenHelper
|
|||
folderCursor.close();
|
||||
database.close();
|
||||
}
|
||||
|
||||
public Observable<Cursor> getGamesForPlatform(final int platform)
|
||||
{
|
||||
return Observable.create(new Observable.OnSubscribe<Cursor>()
|
||||
{
|
||||
@Override
|
||||
public void call(Subscriber<? super Cursor> subscriber)
|
||||
{
|
||||
Log.i("DolphinEmu", "[GameDatabase] Reading games list...");
|
||||
|
||||
String whereClause = null;
|
||||
String[] whereArgs = null;
|
||||
|
||||
// If -1 passed in, return all games. Else, return games for one platform only.
|
||||
if (platform >= 0)
|
||||
{
|
||||
whereClause = KEY_GAME_PLATFORM + " = ?";
|
||||
whereArgs = new String[]{Integer.toString(platform)};
|
||||
}
|
||||
|
||||
SQLiteDatabase database = getReadableDatabase();
|
||||
|
||||
Cursor resultCursor = database.query(
|
||||
TABLE_NAME_GAMES,
|
||||
null,
|
||||
whereClause,
|
||||
whereArgs,
|
||||
null,
|
||||
null,
|
||||
KEY_GAME_TITLE + " ASC"
|
||||
);
|
||||
|
||||
// Pass the result cursor to the consumer.
|
||||
subscriber.onNext(resultCursor);
|
||||
|
||||
// Tell the consumer we're done; it will unsubscribe implicitly.
|
||||
subscriber.onCompleted();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue