前面两片文章中已经完成了Android MVP模式及dagger2的引入, 接下来我们将在前两天的代码的基础上引入Retrofit Rxjava Okhttp实现网络请求; 其中网络请求部分我讲以网络公共api为例子进行网络请求, 如果有开发这发现该地址无法返回数据时,可以联系我进行代码更新。微信号为: lg878398509; 添加时请备注!!!
1. 在Service包下分别建立api,client, converter包
- api, 包中存放的是网络请求的 api 请求方法信息
- client, 中封装了网络请求的框架; 包含Retrofit Okhttp的基础信息
- converter ,自定义数据返回解析转换工厂类[实现输出原始返回数据的json报文]
MainApi.java
public interface MainApi {
@GET("json/play/list.json?v=3.0.1&os=1&ver=4")
Observable getLiveListResult();
}
ApiEndpoint.java
public interface ApiEndpoint {
String getEndpoint();
}
BaseOkHttpClient.java 定义基础OkHttpClient对象信息, 供其他地方继承
public abstract class BaseOkHttpClient {
private static final long TIMEOUT_CONNECT = 30 * 1000;
public OkHttpClient get() {
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.connectTimeout(TIMEOUT_CONNECT, TimeUnit.MILLISECONDS)
.addInterceptor(new HttpLoggingInterceptor()
.setLevel(BuildConfig.DEBUG ? HttpLoggingInterceptor.Level.BODY : HttpLoggingInterceptor.Level.NONE));
builder = customize(builder);
return builder.build();
}
public abstract OkHttpClient.Builder customize(OkHttpClient.Builder builder);
}
BaseRetrofit.java 基础Retrofit信息类
public abstract class BaseRetrofit {
public Retrofit get() {
Retrofit.Builder builder = new Retrofit.Builder();
builder.baseUrl(getApiEndpoint().getEndpoint())
.client(getHttpClient())
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(ResponseConvertFactory.create());
return builder.build();
}
public abstract ApiEndpoint getApiEndpoint();
public abstract OkHttpClient getHttpClient();
}
CacheHttpClient.java 实现缓存功能的OkHttpClient;继承BaseOkHttp
public class CacheHttpClient extends BaseOkHttpClient {
private static final long CACHE_SIZE = 1024 * 1024 * 50;
@Inject
Application mContext;
@Inject
public CacheHttpClient() {
}
@Override
public OkHttpClient.Builder customize(OkHttpClient.Builder builder) {
// set cache dir
File cacheFile = new File(mContext.getCacheDir(), "appBase");
Cache cache = new Cache(cacheFile, CACHE_SIZE);
builder.cache(cache);
builder.addNetworkInterceptor(mCacheControlInterceptor);
return builder;
}
private final Interceptor mCacheControlInterceptor = new Interceptor() {
@Override
public Response intercept(Chain chain) throws IOException {
Request request = chain.request();
// Add FORCE_CACHE cache control for each request if network is not available.
if (!NetworkUtil.isNetworkAvailable(mContext)) {
request = request.newBuilder()
.cacheControl(CacheControl.FORCE_CACHE)
.build();
}
Response originalResponse = chain.proceed(request);
if (NetworkUtil.isNetworkAvailable(mContext)) {
String cacheControl = request.cacheControl().toString();
// Add cache control header for response same as request's while network is available.
return originalResponse.newBuilder()
.header("Cache-Control", cacheControl)
.build();
} else {
// Add cache control header for response to FORCE_CACHE while network is not available.
return originalResponse.newBuilder()
.header("Cache-Control", CacheControl.FORCE_CACHE.toString())
.build();
}
}
};
}
DemoHttpClient.java Demo项目使用的HttpClient; 继承CacheHttpClient; 如果不需要缓存功能则直接继承BaseHttpClient
public class DemoHttpClient extends CacheHttpClient {
@Inject
public Application application;
@Inject
public DemoHttpClient() {
}
@Override
public OkHttpClient.Builder customize(OkHttpClient.Builder builder) {
builder = super.customize(builder);
return builder;
}
}
DemoRetrofit.java Demo项目使用的Retrofit, 继承BaseRetrofit。
成员变量 “END_POINT” 为后台的BaseURL
public class DemoRetrofit extends BaseRetrofit {
private static final String END_POINT = "http://www.quanmin.tv/";
DemoHttpClient mHttpClient;
@Inject
public DemoRetrofit(DemoHttpClient mHttpClient) {
this.mHttpClient = mHttpClient;
}
@Override
public ApiEndpoint getApiEndpoint() {
return new ApiEndpoint() {
@Override
public String getEndpoint() {
return END_POINT;
}
};
}
@Override
public OkHttpClient getHttpClient() {
return mHttpClient.get();
}
}
自定义数据返回解析器 GsonResponseBodyConverter.java; 其中实现了原始json输出。
public class GsonResponseBodyConverter implements Converter {
private final Gson gson;
private final Type type;
GsonResponseBodyConverter(Gson gson, Type type) {
this.gson = gson;
this.type = type;
}
@Override
public T convert(ResponseBody value) throws IOException {
String response = value.string();
AppLog.i("<<<<<<<<<<<<<<<<<<<<<<<<<<<< Network response >>>>>>>>>>>>>>>>>>>>>>" + response);
return gson.fromJson(response, type);
}
}
ResponseConvertFactory.java
public class ResponseConvertFactory extends Converter.Factory{
/**
* Create an instance using a default {@link Gson} instance for conversion. Encoding to JSON and
* decoding from JSON (when no charset is specified by a header) will use UTF-8.
*/
public static ResponseConvertFactory create() {
return create(new Gson());
}
/**
* Create an instance using {@code gson} for conversion. Encoding to JSON and
* decoding from JSON (when no charset is specified by a header) will use UTF-8.
*/
public static ResponseConvertFactory create(Gson gson) {
return new ResponseConvertFactory(gson);
}
private final Gson gson;
private ResponseConvertFactory(Gson gson) {
if (gson == null) throw new NullPointerException("gson == null");
this.gson = gson;
}
@Override
public Converter responseBodyConverter(Type type, Annotation[] annotations,
Retrofit retrofit) {
return new GsonResponseBodyConverter<>(gson,type);
}
}
2 添加repository包, 其中加入网络请求业务逻辑代码
IMainService.java
public interface IMainService {
Observable getLiveListResult();
}
MainDataSource.java
public class MainDataSource implements IMainService {
@Inject
Application mContext;
MainApi maiApi;
@Inject
public MainDataSource(MainApi accountApi) {
this.maiApi = accountApi;
}
@Override
public Observable getLiveListResult() {
return maiApi.getLiveListResult();
}
}
ResponseObserver.java
public abstract class ResponseObserver extends Subscriber {
@Override
public void onCompleted() {
}
@Override
public void onNext(T t) {
onSuccess(t);
}
public abstract void onSuccess(T t);
}
ResponseResult.java 返回值实体类
public class ResponseResult {
private int total;
private int page;
private int size;
private String icon;
private String pageCount;
public int getTotal() {
return total;
}
public void setTotal(int total) {
this.total = total;
}
public int getPage() {
return page;
}
public void setPage(int page) {
this.page = page;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public String getIcon() {
return icon;
}
public void setIcon(String icon) {
this.icon = icon;
}
public String getPageCount() {
return pageCount;
}
public void setPageCount(String pageCount) {
this.pageCount = pageCount;
}
}
- 加入完网络请求的业务逻辑, 我们在那里调用进行网络请求呢! 没错,我们只需要在MainPresenter中加入网络请求代码即可。
最新MainPresenter.java代码如下:
public class MainPresenter extends RxMvpPresenter {
private final IMainService mainService;
@Inject
public MainPresenter(IMainService mainService) {
this.mainService = mainService;
}
@Inject
Application context;
public void getLiveListResult() {
mCompositeSubscription.add(mainService.getLiveListResult()
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.doOnSubscribe(new Action0() {
@Override
public void call() {
//加载中处理
}
})
.doOnTerminate(new Action0() {
@Override
public void call() {
//加载完成处理
}
})
.subscribe(new ResponseObserver() {
@Override
public void onSuccess(ResponseResult result) {
getMvpView().loginSuccess(result);
}
@Override
public void onError(Throwable e) {
e.printStackTrace();
getMvpView().loginException();
}
}));
}
}
- 分别修改MainActivity.java 和MainView.java类
MainActivity.java
public class MainActivity extends BaseAcitvity implements MainView, HasComponent {
@BindView(R.id.test)
TextView test;
@Inject
MainPresenter mainPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
getComponent().inject(this);
//重要
mainPresenter.attachView(this);
}
@OnClick(R.id.test)
public void onClick() {
mainPresenter.getLiveListResult();
}
@Override
public void loginSuccess(ResponseResult result) {
Toast.makeText(this, result.getIcon(), Toast.LENGTH_LONG).show();
}
@Override
public void loginFail() {
}
@Override
public void loginException() {
}
@Override
public MainComponent getComponent() {
return DaggerMainComponent.builder()
.applicationComponent(Application.get(this).getComponent())
.activityModule(new ActivityModule(this))
.mainModule(new MainModule())
.build();
}
@Override
protected void onDestroy() {
super.onDestroy();
mainPresenter.detachView();
}
}
MainView.java
public interface MainView extends MvpView{
void loginSuccess(ResponseResult result);
void loginFail();
void loginException();
}
- 运行代码,,,,发生了什么!!!没错就是报错了;;;
3 解决报错问题
- 该报错问题是由于MainService, MainApi没有交由Dagger2给提供给Presenter导致的。
分别修改ApplicationModule.java、ApplicationComponent.java、MainModule.java
ApplicationModule.java
@Module
public class ApplicationModule {
protected final Application mApplication;
public ApplicationModule(Application application) {
mApplication = application;
}
@Provides
public Application provideApplication() {
return mApplication;
}
@Provides
@ApplicationContext
public Context provideContext() {
return mApplication;
}
@Provides
@Singleton
public MainApi provideMainApi(DemoRetrofit retrofit) {
return retrofit.get().create(MainApi.class);
}
}
ApplicationComponent.java
@Singleton
@Component(modules = ApplicationModule.class)
public interface ApplicationComponent {
@ApplicationContext
Context context();
Application application();
MainApi accountAccountApi();
}
MainModule.java
@Module
public class MainModule {
@Provides
public IMainService provideMainService(MainDataSource dataSource) {
return dataSource;
}
}
4 再次运行代码
- 呵呵 成功了, 点击页面HelloWord 什么!!!没反应, 一顿狂点,还是没反应; 看一下后台, 报错了;原来是没有加入网络请求权限;;;网上copy一段网络请求权限代码防盗Manifests.xml文件中。再次运行。
点击 页面Hello World; 运行如下; Toast弹出的即为从网络上请求得到的图片icon地址。
项目下载地址