基於Retrofit2.0+RxJava+Dragger2實現不一樣的Android網路構架搭建
一起分享,一起進步。finddreams:http://blog.csdn.net/finddreams/article/details/50849385
眾所周知,手機APP的核心就在於呼叫後臺介面,展示相關資訊,方便我們在手機上就能和外界互動。所以APP中網路框架的搭建一直是我們開發者所關心的問題,在Android中關於如何搭建網路框架分為兩種:一種是不想重複造輪子使用第三方開源的網路框架;第二種就是喜歡造輪子的封裝自己的網路框架。
自己封裝實現網路框架這種行為固然不錯,但是這需要自身具備比較高的能力,而很多時候我們沒有那樣的能力把它封裝的足夠好。這時我們使用開源的網路框架也未嘗不是一件好事,github上面知名的網路框架已經經過了很多app的驗證,在一定意義上是非常符合我們在實際的專案開發所需要的。
Android開發中幾個知名的開源的網路框架有
我們很多開發者大都在小型公司,不瞭解大公司是怎麼做Android網路框架的,也想知道那些使用者量過千萬的APP到底用了些什麼技術,下面有兩張圖片,讓我們一起來了解一下Android版的美團和Uber到底用了些什麼技術。
美團 Uber
看完你會發現其實這些使用者量過億的APP也使用了很多的開源框架,而且這些開源框架中大多數其實都是我們平常在開發中所常用到的,並不陌生。可能大多數人對Retrofit,Rxjava這些還不太熟悉,那話不多說,今天我們就來講講怎麼用Retrofit2.0+RxJava+Dragger2來實現Android網路構架搭建,給大家提供一種思路,供大家參考參考。
Retrofit2.0
Square開發的型別安全的REST安卓客戶端請求庫,網路請求預設使用的是OkHttp,具體介紹請看相關教程。
RxJava +RxAndroid GitHub地址: https://github.com/ReactiveX/RxJava
RxJava是一種響應式程式設計框架,採用觀察者設計模式。最核心的是Observables(被觀察者,事件源)和Subscribers(觀察者)這兩個東西,RxAndroid是Rxjava在Android上的實現。
Dragger2
是一種依賴注入框架,可以大大節省我們的程式碼量,便於維護。
在這裡我就不費過多筆墨來介紹著三個東西了,今天的主題是提供一種如何搭建一個不一樣的網路框架的思路。如果讀者對這三個框架不是很瞭解的話,可以自行的Google腦補一下。
首先,就是開始把這些框架引入到咱們的專案中來作為依賴庫,在app/build.gradle檔案中新增
apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt'
android {
compileSdkVersion 23
buildToolsVersion "23.0.2"
defaultConfig {
applicationId "com.finddreams.retrofit"
minSdkVersion 15
targetSdkVersion 23
versionCode 1
versionName "1.0"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(include: ['*.jar'], dir: 'libs')
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.1.1'
//retrofit
compile 'com.squareup.retrofit2:retrofit:2.0.0-beta4'
//gson解析
compile 'com.squareup.retrofit2:converter-gson:2.0.0-beta4'
//rxjava
compile 'io.reactivex:rxandroid:1.1.0'
compile 'com.squareup.retrofit2:adapter-rxjava:2.0.0-beta4'
//dragger2
provided 'org.glassfish:javax.annotation:10.0-b28'
apt 'com.google.dagger:dagger-compiler:2.0.2'
compile 'com.google.dagger:dagger:2.0.2'
}
因為Dragger2是基於註解的,它會預先生成一些類檔案,所以需要在整個專案的/build.gradle檔案中加上apt工具:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:2.0.0-beta6'
classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
接著開始寫一個提供Retrofit的單例類:
/**
* Retrofit的實體類
*/
public class RestApiAdapter {
private static Retrofit retrofit = null;
public static Retrofit getInstance() {
if (retrofit == null) {
GsonConverterFactory gsonConverterFactory = GsonConverterFactory.create();
OkHttpClient okHttpClient = new OkHttpClient();
OkHttpClient.Builder builder = okHttpClient.newBuilder();
builder.retryOnConnectionFailure(true);
retrofit = new Retrofit.Builder().client(okHttpClient)
.baseUrl(ConstantApi.BaiduUrl)
.addConverterFactory(gsonConverterFactory)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.build();
}
return retrofit;
}
}
addCallAdapterFactory(RxJavaCallAdapterFactory.create()) 這個方法就是RxJava和Retrofit結合的關鍵。
接著我們為Retrofit 提供一個service介面,宣告api介面地址和所需要的引數,這裡我們使用百度API提供的天氣介面,實現根據城市名稱查詢天氣的功能,介面地址:http://apistore.baidu.com/apiworks/servicedetail/112.html 程式碼如下:
/**
* 天氣介面Api
*/
public interface WeatherApiService {
/**
* 查詢天氣
*/
@GET("apistore/weatherservice/cityname")
Observable<WeatherResultBean> queryWeather(@Header("apikey") String apikey, @Query("cityname") String cityname);
}
返回一個Observable被觀察者/事件源的意思是交給RxJava來處理。
然後我們寫一個BaseSubsribe觀察者來管理網路請求開始結束,成功與失敗:
/**
* 觀察者
*
* @author finddreams
* @address http://blog.csdn.net/finddreams
*/
public abstract class BaseSubsribe<T> extends Subscriber<T> {
private static final String TAG = "BaseSubsribe";
@Override
public void onStart() {
super.onStart();
Log.i(TAG, "onStart");
}
@Override
public void onNext(T t) {
Log.i(TAG, "response" + t.toString());
onSuccess(t);
}
@Override
public void onCompleted() {
Log.i(TAG, "onCompleted");
}
public abstract void onSuccess(T result);
@Override
public void onError(Throwable e) {
e.printStackTrace();
Log.i(TAG, "onError" + e.getMessage());
}
}
接著我們寫一個WeatherInteractor介面連線service類:
/**
* 獲取天氣資訊介面
*
* @author finddreams
* @address http://blog.csdn.net/finddreams
*/
public interface WeatherInteractor {
Subscription queryWeather(String apikey, String cityname, BaseSubsribe<WeatherResultBean> subsribe);
}
然後是這個介面的實現類:
/**
* 獲取天氣資訊實現類
*/
public class WeatherInteractorImpl implements WeatherInteractor {
private final WeatherApiService api;
@Inject
public WeatherInteractorImpl(WeatherApiService myApi) {
this.api = myApi;
}
@Override
public Subscription queryWeather(String apikey, String cityname, BaseSubsribe<WeatherResultBean> subsribe) {
Observable<WeatherResultBean> observable = api.queryWeather(apikey, cityname);
Subscription subscribe = observable.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(subsribe);
return subscribe;
}
}
接下來是如何使用Dragger2的時候,知道Dragger2的都知道有幾個概念,一個是Module:主要提供依賴物件比如context, rest api …; 一個是@inject:註解,用在需要依賴物件的地方;另一個是Componet:用來連線Module和@inject
首先定義一個Module類,提供需要注入依賴的物件:
/**
* Module類
* 提供需要注入的類
*
* @author finddreams
* @address http://blog.csdn.net/finddreams
*/
@Module
public class InteractorModule {
@Provides
public Retrofit provideRestAdapter() {
return RestApiAdapter.getInstance();
}
@Provides
public WeatherApiService provideHomeApi(Retrofit restAdapter) {
return restAdapter.create(WeatherApiService.class);
}
@Provides
public WeatherInteractor provideHomeInteractor(WeatherApiService myApi) {
return new WeatherInteractorImpl(myApi);
}
}
接著是寫一個Componet類:
/**
* 宣告AppComponent元件
*
* @author finddreams
* @address http://blog.csdn.net/finddreams
*/
@Singleton
@Component(
modules = {
InteractorModule.class,
}
)
public interface AppComponent {
void inject(App app);
WeatherInteractor getWeatherInteractor();
}
然後我們在Application中初始化這個AppComponent:
/**
* Application類
*
* @author finddreams
* @address http://blog.csdn.net/finddreams
*/
public class App extends Application {
private AppComponent component;
@Override
public void onCreate() {
super.onCreate();
setDraggerConfig();
}
public AppComponent component() {
return component;
}
public static App get(Context context) {
return (App) context.getApplicationContext();
}
/**
* 初始化Dragger,DaggerAppComponent是自動生成,需要Rebuild
*/
private void setDraggerConfig() {
component = DaggerAppComponent.builder().interactorModule(new InteractorModule())
.build();
component.inject(this);
}
}
這裡需要注意的是,由於Dagger2是預編譯生成一個類,所以我們需要Rebuild專案,才會生成DaggerAppComponent這個類。如果開發中出現
import com.finddreams.retrofit.api.config.DaggerAppComponent;
找不到這個類的錯誤
這時就需要重新的Rebuild專案
這是Rebuild專案之後生成的class檔案,如圖:
最後我們就可以在Activity中開始使用了:
/**
* 主頁
*
* @author finddreams
* @address http://blog.csdn.net/finddreams
*/
public class MainActivity extends AppCompatActivity {
private AppComponent component;
private WeatherInteractor weatherInteractor;
private EditText city;
private TextView queryresult;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
city = (EditText) findViewById(R.id.city);
queryresult = (TextView) findViewById(R.id.queryresult);
//獲取到AppComponent元件
component = App.get(this).component();
//通過AppComponent拿到WeatherInteractor
weatherInteractor = component.getWeatherInteractor();
findViewById(R.id.query).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
queryWeatherData();
}
});
}
public void queryWeatherData() {
String content = city.getText().toString();
//呼叫查詢天氣介面的方法
Subscription subscription = weatherInteractor.queryWeather(ConstantApi.baiduKey, content, new BaseSubsribe<WeatherResultBean>() {
@Override
public void onSuccess(WeatherResultBean result) {
WeatherResultBean.RetDataEntity retData = result.getRetData();
queryresult.setText(retData.getCity() + ":" + retData.getWeather() + ":" + retData.getDate());
}
@Override
public void onError(Throwable e) {
super.onError(e);
queryresult.setText("查詢失敗");
}
}
);
//取消請求
// subscription.unsubscribe();
}
}
我們看下專案執行的結果圖: