android MVP dagger2 Retrofit Rxjava okhttp 框架整合(3)--完美实现

前面两片文章中已经完成了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<ResponseResult> 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<T> implements Converter<ResponseBody, T> {
    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<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations,
                                                            Retrofit retrofit) {
        return new GsonResponseBodyConverter<>(gson,type);
    }

}

2 添加repository包, 其中加入网络请求业务逻辑代码

IMainService.java

public interface IMainService {
    Observable<ResponseResult> getLiveListResult();
}

MainDataSource.java

public class MainDataSource implements IMainService {
    
    
        @Inject
        Application mContext;
    
        MainApi maiApi;
    
        @Inject
        public MainDataSource(MainApi accountApi) {
            this.maiApi = accountApi;
        }
    
        @Override
        public Observable<ResponseResult> getLiveListResult() {
    
            return maiApi.getLiveListResult();
        }
    
    }

ResponseObserver.java

public abstract class ResponseObserver<T> extends Subscriber<T> {
    @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<MainView> {

    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<ResponseResult>() {
                    @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<MainComponent> {

    @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地址。

ress.png

项目下载地址

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容