final Retrofit loRetrofit = new Retrofit.Builder() .baseUrl("https://api.github.com") .addConverterFactory(JacksonConverterFactory.create()) // add the Jackson specific converter .build();
final GitHubService loService = loRetrofit.create(GitHubService.class); return loService;
final Configuration loConfiguration = new Configuration.Builder(poContext) .minConsumerCount(1) // always keep at least one consumer alive .maxConsumerCount(3) // up to 3 consumers at a time .loadFactor(3) // 3 jobs per consumer .consumerKeepAlive(120) // wait 2 minute .build();
final JobManager loJobManager = new JobManager(poContext, loConfiguration);
public abstract class AbstractQuery extends Job { private static final String TAG = AbstractQuery.class.getSimpleName(); private static final boolean DEBUG = true;
protected enum Priority { LOW(0), MEDIUM(500), HIGH(1000); private final int value;
Priority(final int piValue) { value = piValue; } }
protected AbstractQuery(final Priority poPriority, final boolean pbPersistent, final String psGroupId, final long plDelayMs) { super(new Params(poPriority.value).requireNetwork().setPersistent(pbPersistent).setGroupId(psGroupId).setDelayMs(plDelayMs)); } //endregion
//region Overridden methods @Override public void onAdded() { }
public class QueryGetRepos extends AbstractQuery { private static final String TAG = QueryGetRepos.class.getSimpleName(); private static final boolean DEBUG = true;
//region Fields public final String user; //endregion
//region Constructor matching super protected QueryGetRepos(@NonNull final String psUser) { super(Priority.MEDIUM); user = psUser; } //endregion
//region Overridden method @Override protected void execute() throws Exception { final GitHubService gitHubService = // specific code to get GitHubService instance
final Call<List<DTORepo>> loCall = gitHubService.listRepos(user); final Response<List<DTORepo>> loExecute = loCall.execute(); final List<DTORepo> loBody = loExecute.body();
// TODO deal with list of DTORepo }
@Override protected void postEventQueryFinished() { final EventQueryGetRepos loEvent = new EventQueryGetRepos(this, mSuccess, mErrorType, mThrowable); busManager.postEventOnMainThread(loEvent); }
@Override public void postEventQueryFinishedNoNetwork() { final EventQueryGetRepos loEvent = new EventQueryGetRepos(this, false, AbstractEventQueryDidFinish.ErrorType.NETWORK_UNREACHABLE, null); busManager.postEventOnMainThread(loEvent); } //endregion
//region Dedicated EventQueryDidFinish public static final class EventQueryGetRepos extends AbstractEventQueryDidFinish<QueryGetRepos> { public EventQueryGetRepos(final QueryGetRepos poQuery, final boolean pbSuccess, final ErrorType poErrorType, final Throwable poThrowable) { super(poQuery, pbSuccess, poErrorType, poThrowable); } } //endregion }
现在,通过QueryFactor这个简单的代理类来进行请求
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
public class QueryFactory { //region Build methods public QueryGetRepos buildQueryGetRepos(@NonNull final String psUser) { return new QueryGetRepos(psUser); } //endregion
//region Start methods public void startQuery(@NonNull final Context poContext, @NonNull final AbstractQuery poQuery) { final Intent loIntent = new ServiceQueryExecutorIntentBuilder(poQuery).build(poContext); poContext.startService(loIntent); }
public void startQueryGetRepos(@NonNull final Context poContext, @NonNull final String psUser) { final QueryGetRepos loQuery = buildQueryGetRepos(psUser); startQuery(poContext, loQuery); } //endregion }
public class ServiceQueryExecutor extends IntentService { private static final String TAG = ServiceQueryExecutor.class.getSimpleName();
//region Extra fields AbstractQuery query; //endregion
MerlinsBeard merlinsBeard; JobManager jobManager;
//region Constructor matching super /** * Creates an IntentService. Invoked by your subclass's constructor. */ public ServiceQueryExecutor() { super(TAG); } //endregion
//region Overridden methods @DebugLog @Override protected void onHandleIntent(final Intent poIntent) { // TODO get AbstractQuery from Intent // TODO get MerlinsBeard and JobManager instances
// If query requires network, and if network is unreachable, and if the query must not persist if (query.requiresNetwork() && !merlinsBeard.isConnected() && !query.isPersistent()) { // then, we post an event to notify the job could not be done because of network connectivity query.postEventQueryFinishedNoNetwork(); } else { // otherwise, we can add the job jobManager.addJobInBackground(query); } } //endregion }
public abstract class AbstractOrmLiteEntity { @DatabaseField(columnName = BaseColumns._ID, generatedId = true) protected long _id;
//region Getter public long getBaseId() { return _id; } //endregion }
现在创建一个POJO类
1 2 3 4 5 6 7 8 9 10 11 12 13 14
@DatabaseTable(tableName = "REPO", daoClass = DAORepo.class) public class RepoEntity extends AbstractOrmLiteEntity { @DatabaseField public Integer id;
@DatabaseField public String name;
@DatabaseField public String location;
@DatabaseField public String url; }
我们来看一下DAO。这个设计目的在于通过抽象的接口来访问具体的数据。
OrmLite提供了Dao接口以及其实现BaseDaoImpl。CURD所需的操作都具备。
然而,这些都是同步执行的。使用RxJava来异步执行这些操作。
因此我使用RxJava重写了所有的方法 我创建了如下接口
1
public interface IRxDao<T, ID> extends Dao<T, ID>
所有的方法名以”rx”为前缀。返回一个特定类型的Observable对象
1
public abstract class RxBaseDaoImpl<DataType extends AbstractOrmLiteEntity, IdType> extends BaseDaoImpl<DataType, IdType> implements IRxDao<DataType, IdType>
使用long作为ID类型
1 2
public interface IOrmLiteEntityDAO<DataType extends AbstractOrmLiteEntity> extends Dao<DataType, Long> { }
抽象类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
public abstract class AbstractBaseDAOImpl<DataType extends AbstractOrmLiteEntity> extends RxBaseDaoImpl<DataType, Long> implements IOrmLiteEntityDAO<DataType> { //region Constructors matching super protected AbstractBaseDAOImpl(final Class<DataType> poDataClass) throws SQLException { super(poDataClass); }
public AbstractBaseDAOImpl(final ConnectionSource poConnectionSource, final Class<DataType> poDataClass) throws SQLException { super(poConnectionSource, poDataClass); }
public AbstractBaseDAOImpl(final ConnectionSource poConnectionSource, final DatabaseTableConfig<DataType> poTableConfig) throws SQLException { super(poConnectionSource, poTableConfig); } //endregion }
DAORepo变成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
public class DAORepo extends AbstractBaseDAOImpl<RepoEntity> { //region Constructors matching super public DAORepo(final ConnectionSource poConnectionSource) throws SQLException { this(poConnectionSource, RepoEntity.class); }
public DAORepo(final ConnectionSource poConnectionSource, final Class<RepoEntity> poDataClass) throws SQLException { super(poConnectionSource, poDataClass); }
public DAORepo(final ConnectionSource poConnectionSource, final DatabaseTableConfig<RepoEntity> poTableConfig) throws SQLException { super(poConnectionSource, poTableConfig); } //endregion }
public class DatabaseHelperAndroidStarter extends OrmLiteSqliteOpenHelper { private static final String DATABASE_NAME = "android_starter.db"; private static final int DATABASE_VERSION = 1;
//region Constructor public DatabaseHelperAndroidStarter(@NonNull final Context poContext) { super(poContext, DATABASE_NAME, null, DATABASE_VERSION); } //endregion
//region Methods to override @Override @SneakyThrows(SQLException.class) public void onCreate(@NonNull final SQLiteDatabase poDatabase, @NonNull final ConnectionSource poConnectionSource) { TableUtils.createTable(poConnectionSource, RepoEntity.class); }
@Override @SneakyThrows(SQLException.class) public void onUpgrade(@NonNull final SQLiteDatabase poDatabase, @NonNull final ConnectionSource poConnectionSource, final int piOldVersion, final int piNewVersion) { TableUtils.dropTable(poConnectionSource, RepoEntity.class, true); onCreate(poDatabase, poConnectionSource); } //endregion }
ORMLite提供TableUtils,其可以根据映射的类文件创建或者删除表
现在,我们需要一个DatabaseHelperAndroidStarter来处理数据
1 2 3
public DatabaseHelperAndroidStarter getDatabaseHelperAndroidStarter(@NonNull final Context poContext) { return new DatabaseHelperAndroidStarter(poContext); }
我们能通过下面的方式获得一个DAORepo实例
1 2 3
public DAORepo getDAORepo(@NonNull final DatabaseHelperAndroidStarter poDatabaseHelperAndroidStarter) { return new DAORepo(poDatabaseHelperAndroidStarter.getConnectionSource()); }
@Mappable(with = DTORepo.class) @DatabaseTable(tableName = "REPO", daoClass = DAORepo.class) public class RepoEntity extends AbstractOrmLiteEntity implements Serializable { @Mapped @DatabaseField public Integer id;
@Mapped @DatabaseField public String name;
@Mapped @DatabaseField public String location;
@Mapped @DatabaseField public String url; }
现在我们能通过以下方式将DTO转换成实体
1 2
final Transformer loTransformerRepo = new Transformer.Builder().build(RepoEntity.class); final RepoEntity loRepo = loTransformerRepo.transform(loDTORepo, RepoEntity.class);
@AutoInjector(ApplicationAndroidStarter.class) // to automatically add inject method in component public final class PresenterRepoDetail extends MvpBasePresenter<ViewRepoDetail> {
//region Injected fields @Inject DAORepo daoRepo; // we need the DAO to load the repo from its ID //endregion
//region Fields private Subscription mSubscriptionGetRepo; // the RxJava subscription, to destroy it when needed //endregion
//region Constructor public PresenterRepoDetail() { // inject necessary fields via the component ApplicationAndroidStarter.sharedApplication().componentApplication().inject(this); } //endregion
//region Visible API public void loadRepo(final long plRepoId, final boolean pbPullToRefresh) { if (isViewAttached()) { getView().showLoading(pbPullToRefresh); } // get repo asynchronously via RxJava rxGetRepo(plRepoId); }
public void onDestroy() { // destroy the RxJava subscribtion if (mSubscriptionGetRepo != null) { mSubscriptionGetRepo.unsubscribe(); mSubscriptionGetRepo = null; } } //endregion