概述
原來(lái)一直在用Android最原生的框架進(jìn)行開發(fā),最多也就使用了butterknife,減少了很多的findviewById。前段時(shí)間看google的IO大會(huì),偶爾聽到了新型的Android開發(fā)框架dagger2等等,然后對(duì)此框架產(chǎn)生了濃厚的興趣。
通過一段時(shí)間的深入學(xué)習(xí),把我的學(xué)習(xí)分享出來(lái),希望大家能夠喜歡。
mvp+dagger2+retrofit2+rxjava 一套開發(fā)模式自我感覺將是以后Android開發(fā)的趨勢(shì),盡早的用起來(lái)吧。
使用新型框架能給我們帶來(lái)什么好處?
- 解耦,降低模塊耦合度。
- 可以更方便的寫單元測(cè)試。
- 減少Activity編碼
- 提高團(tuán)隊(duì)協(xié)作的效率
- 提高編碼的效率
- 提高代碼的可讀性
示例:
本文示例功能:
- retrofit2+Rxjava進(jìn)行Http和Https網(wǎng)絡(luò)請(qǐng)求封裝
- MVP工程結(jié)構(gòu)
- Rxjava的使用示例
- dagger2的使用示例
說(shuō)明
閱讀此文首先你要對(duì)以下技術(shù)有一定的了解。對(duì)以上技術(shù)還不熟悉的朋友可以先去了解一下。
在我閱讀過無(wú)數(shù)相關(guān)技術(shù)文章之后,我給大家推薦這些技術(shù)學(xué)習(xí)的文章:
dagger2
理論:http://android.jobbole.com/82694/
實(shí)例(網(wǎng)絡(luò)上沒有找到合適的,我自己寫的一篇博文):http://m.itdecent.cn/p/269c3f70ec1e
官方:http://google.github.io/dagger/
mvp:
這個(gè)理論很簡(jiǎn)單,自己百度或者google吧
示例:https://github.com/googlesamples/android-architecture
retrofit2:
官方:http://square.github.io/retrofit/
rxjava:
偏理論:http://gank.io/post/560e15be2dca930e00da1083
偏實(shí)踐:http://blog.chinaunix.net/uid-20771867-id-5187376.html
對(duì)上面的技術(shù)有一定的了解后,我們開始一個(gè)示例:
架構(gòu)搭建
首先我們要一個(gè)示例的方式來(lái)詳細(xì)說(shuō)明整體項(xiàng)目的架構(gòu)與思想
示例功能;
- 登錄功能
- 檢查用戶名和密碼是否合法
- 登錄按鈕如果不合法則不可點(diǎn)擊,合法后登錄按鈕可以點(diǎn)擊
- 調(diào)用登錄接口進(jìn)行登錄
- 將用戶名和密碼保存本地
- 文章列表
- 從網(wǎng)絡(luò)獲取文章列表并展示
- 將文章列表保存到數(shù)據(jù)庫(kù)
- 點(diǎn)擊列表進(jìn)入文章詳情
- 網(wǎng)絡(luò)獲取圖片
- 單元測(cè)試
- 集成測(cè)試
- 單元測(cè)試
整體架構(gòu)圖

運(yùn)行webserver json
//安裝json-server
$ npm install -g json-server
//進(jìn)入工程目錄
$ cd AndroidArchitecture/
//運(yùn)行服務(wù)
json-server --watch login.json
運(yùn)行后可以通過此地址訪問接口
http://localhost:3000/users
http://localhost:3000/topics
關(guān)于工程
由于工程代碼較多,在這里就不一一將代碼貼出了,詳細(xì)的demo地址見我的github
https://github.com/wlj32011/AndroidArchitecture
下圖為demo目錄接口,查看demo源碼可以參考此結(jié)構(gòu)

關(guān)鍵代碼
-
網(wǎng)絡(luò)請(qǐng)求返回消息體統(tǒng)一錯(cuò)誤處理
消息體結(jié)構(gòu)
//登錄
{
"status_msg" : "登錄成功",
"status_code" : 200,
"data" : {
"username" : "admin",
"id" : 1,
"password" : "123456",
"gender" : "男"
}
}
模型結(jié)構(gòu)
public class BaseResponse<T> {
private int status_code;
private String status_msg;
private T data;
public int getStatus_code() {
return status_code;
}
public void setStatus_code(int status_code) {
this.status_code = status_code;
}
public String getStatus_msg() {
return status_msg;
}
public void setStatus_msg(String status_msg) {
this.status_msg = status_msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
使用Rxjava對(duì)象變換
public class BaseResponseFunc<T> implements Func1<BaseResponse<T>, Observable<T>> {
@Override
public Observable<T> call(BaseResponse<T> tBaseResponse) {
//遇到非200錯(cuò)誤統(tǒng)一處理,將BaseResponse轉(zhuǎn)換成您想要的對(duì)象
if (tBaseResponse.getStatus_code() != 200) {
return Observable.error(new Throwable(tBaseResponse.getStatus_msg()));
}else{
return Observable.just(tBaseResponse.getData());
}
}
}
自定義訂閱者
/**
* 錯(cuò)誤統(tǒng)一處理
*
* Created by wanglj on 16/7/4.
*/
public class ExceptionSubscriber<T> extends Subscriber<T> {
private SimpleCallback<T> simpleCallback;
private Application application;
public ExceptionSubscriber(SimpleCallback simpleCallback, Application application){
this.simpleCallback = simpleCallback;
this.application = application;
}
@Override
public void onStart() {
super.onStart();
if(simpleCallback != null)
simpleCallback.onStart();
}
@Override
public void onCompleted() {
if(simpleCallback != null)
simpleCallback.onComplete();
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
if (e instanceof SocketTimeoutException) {
Toast.makeText(application, "網(wǎng)絡(luò)中斷,請(qǐng)檢查您的網(wǎng)絡(luò)狀態(tài)", Toast.LENGTH_SHORT).show();
} else if (e instanceof ConnectException) {
Toast.makeText(application, "網(wǎng)絡(luò)中斷,請(qǐng)檢查您的網(wǎng)絡(luò)狀態(tài)", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(application, "error:" + e.getMessage(), Toast.LENGTH_SHORT).show();
}
if(simpleCallback != null)
simpleCallback.onComplete();
}
@Override
public void onNext(T t) {
if(simpleCallback != null)
simpleCallback.onNext(t);
}
}
簡(jiǎn)單的回調(diào)模型
public interface SimpleCallback<T> {
void onStart();
void onNext(T t);
void onComplete();
}
presenter層調(diào)用
public void login(String username,String password){
apiManager.login(username, password, new SimpleCallback<User>() {
@Override
public void onStart() {
loginView.showLoading();
}
@Override
public void onNext(User user) {
loginView.showUser(user);
}
@Override
public void onComplete() {
loginView.hideLoading();
}
});
}
- 對(duì)外提供ApiManager以及retrofit的封裝
@Module
public class ApiModule {
@Provides
@Singleton
public OkHttpClient provideOkHttpClient() {
final OkHttpClient.Builder builder = new OkHttpClient.Builder();
//添加logo日志打印網(wǎng)絡(luò)請(qǐng)求的攔截器
if (BuildConfig.DEBUG) {
HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
logging.setLevel(HttpLoggingInterceptor.Level.BODY);
builder.addInterceptor(logging);
}
builder.connectTimeout(60 * 1000, TimeUnit.MILLISECONDS)
.readTimeout(60 * 1000, TimeUnit.MILLISECONDS);
return builder.build();
}
@Provides
@Singleton
public Retrofit provideRestAdapter(OkHttpClient okHttpClient) {
Retrofit.Builder builder = new Retrofit.Builder();
builder.client(okHttpClient)
.baseUrl(ApiService.SERVER_URL)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create());
return builder.build();
}
@Provides
@Singleton
public ApiService provideApiService(Retrofit restAdapter) {
return restAdapter.create(ApiService.class);
}
@Provides
@Singleton
public ApiManager provideApiManager(Application application,ApiService githubApiService) {
return new ApiManager(githubApiService,application);
}
}
- 所有的全局共用對(duì)象都可以在AppModule里對(duì)外提供,比如PreferencesManager DatabaseManager等等
更高級(jí)的用法--dagger2 劃分更細(xì)的scope
目前demo示例是將功能模塊直接依賴于整個(gè)APP,其實(shí)我們可以劃分更細(xì)的作用域。使一個(gè)對(duì)象的生命周期存在于多個(gè)功能模塊中。
比如:項(xiàng)目中登錄成功后,獲取文章列表需要用戶信息,獲取文章詳情以及文章下的評(píng)論列表,又需要當(dāng)前文章和用戶的信息。那么我們就可以這樣設(shè)計(jì)我們的工程架構(gòu)如圖:

后記
由于寫的比較倉(cāng)促,架構(gòu)圖中的紅色字體部分還未實(shí)現(xiàn),更細(xì)的scope還沒有在demo中體現(xiàn)出來(lái),如果您對(duì)此感興趣,請(qǐng)關(guān)注,后續(xù)會(huì)陸續(xù)更新。
由于表達(dá)能力有限,可能有些地方解釋的不是很清楚,歡迎在下方評(píng)論,一起討論一起進(jìn)步~