项目Demo已经上传至github

链接

本人android小白一枚,在学习android的过程中,我感受很深,在做了这么多练手的项目之后,我觉得android就像一块画板,画板是白纸,作为android的开发人员,要做的就是运用一切可能,去在画板上画出让人看的懂并且美观的画。说起来,我们却也属于艺术家这一行了。。。

在我看来,android是为了展示数据的,这里就要分两个步骤了,第一就是怎样去展示,这部分是相当于UI的工作,,第二就是数据的来源,数据从哪来,怎么来,来的是什么,有什么规律,这些都需要我们去考虑,一般来说,就现在的开发模式来说,数据都是存储在数据库中,后台的工作人员通过各种语言去实现对数据库的增删改查,然后将数据库中的数据进行加工处理,部署在服务器上,android端就需要通过访问服务器去获取并解析数据,这里就涉及到获取并解析数据了。不涉及到网络的应用现如今基本上是不复存在的了,一款App,没有强大的后台作为其支撑,纵然你将界面做的再花哨华丽,终究只能算是“花瓶”,“鸡肋”。

所以在开始开发一个项目之前,选取一款优秀的网络框架是非常有必要的。RxJava和Retrofit出现也很久了,之前是一直使用okHttp去封装一个请求类,这样虽然能够正确的请求到数据,但是,代码不仅复杂繁多,遇到多请求问题就会让逻辑不清晰,思维很容易进入混乱,说再多都无法表达多请求问题的恐怖,亲身经历才能够感受它的复杂。

RxJava的概念其实很模糊,我对它的理解就是一个给你方便处理异步问题的框架,到底有多方便,体会过才知道。。。

Retrofit就是对okhttp做了一层封装。把网络请求都交给给了Okhttp,我们只需要通过简单的配置就能使用retrofit来进行网络请求了,Retrofit 除了提供了传统的 Callback 形式的 API,还有 RxJava 版本的 Observable 形式 API,在我看来,retrofit有点像javaee里的springboot框架,通过xml文件配置好一切后,直接就可以在方法头前添加注释来执行网络请求,实在是不能再方便了。

使用方法:build.gradle文件中引入几个jar

compile 'io.reactivex.rxjava2:rxjava:2.0.7'compile 'io.reactivex.rxjava2:rxandroid:2.0.1'compile 'com.squareup.retrofit2:retrofit:2.1.0'compile 'com.squareup.retrofit2:adapter-rxjava2:2.2.0'compile 'com.squareup.retrofit2:converter-gson:2.1.0'compile 'com.squareup.okhttp3:okhttp:3.5.0'compile 'com.squareup.okhttp3:logging-interceptor:3.6.0'compile 'com.jakewharton:butterknife:7.0.1'compile 'com.trello.rxlifecycle2:rxlifecycle:2.1.0'compile 'com.trello.rxlifecycle2:rxlifecycle-components:2.1.0'

说再多,不如一个例子来的简单,我们现在定义好一个场景,来练练手。

假设现在有这么一组json数据

RxJava2+Retrofit2+okHttp的二次封装_第1张图片

results是一个json数据。它的请求url是http://gank.io/api/data/福利/10/1。因为本篇重点就是在讲运用网络框架去取数据,所以在这里,只要取到数据就可以了,至于怎样去展示,不是本篇重点,所以不做讨论。

1.首先观察json数据的规律,要自定义一个实体,负责将json数据解析成一个个实体类,方便去调用。

总体类:

public class BaseResult<T> {    private int code;    private String message;    private T results;    private boolean error;    public T getResults() {        return results;    }    public void setResults(T results) {        this.results = results;    }    public boolean isError() {        return error;    }    public void setError(boolean error) {        this.error = error;    }    public int getCode() {        return code;    }    public void setCode(int code) {        this.code = code;    }    public String getMessage() {        return message;    }    public void setMessage(String message) {        this.message = message;    }}
results中的数据类:Meizi

public class MeiZi {    /**     * _id : 59cd9b53421aa9727fdb25eb     * createdAt : 2017-09-29T09:01:07.894Z     * desc : 9-29     * publishedAt : 2017-09-29T11:21:16.116Z     * source : chrome     * type : 福利     * url : https://ws1.sinaimg.cn/large/610dc034ly1fk05lf9f4cj20u011h423.jpg     * used : true     * who : daimajia     */    private String _id;    private String createdAt;    private String desc;    private String publishedAt;    private String source;    private String type;    private String url;    private boolean used;    private String who;    public String get_id() {        return _id;    }    public void set_id(String _id) {        this._id = _id;    }    public String getCreatedAt() {        return createdAt;    }    public void setCreatedAt(String createdAt) {        this.createdAt = createdAt;    }    public String getDesc() {        return desc;    }    public void setDesc(String desc) {        this.desc = desc;    }    public String getPublishedAt() {        return publishedAt;    }    public void setPublishedAt(String publishedAt) {        this.publishedAt = publishedAt;    }    public String getSource() {        return source;    }    public void setSource(String source) {        this.source = source;    }    public String getType() {        return type;    }    public void setType(String type) {        this.type = type;    }    public String getUrl() {        return url;    }    public void setUrl(String url) {        this.url = url;    }    public boolean isUsed() {        return used;    }    public void setUsed(boolean used) {        this.used = used;    }    public String getWho() {        return who;    }    public void setWho(String who) {        this.who = who;    }}
2.数据的容器准备好之后,就开始去获取数据了,使用RxJava2与Retrofit2框架去进行网络请求,我觉得定义Retrofit访问的接口

这个是最好想的,所以先编写这个接口。

public interface ApiService {    /**     * 网络请求超时时间毫秒     */    int DEFAULT_TIMEOUT = 20000;    String HOST = "http://gank.io/";    String API_SERVER_URL = HOST + "api/data/";    @GET("福利/10/1")    Observable>> getMezi();    /**     * @param page     * @param number     * @return     */    @Headers("Cache-Control: public, max-age=100")//设置缓存 缓存时间为100s    @GET("everySay/selectAll.do")    Observable>> lookBack(@Query("page") int page, @Query("rows") int number);    @POST("upload/uploadFile.do")    Observable uploadFiles(@Part("filename") String description,                                          @Part("pic\"; filename=\"image1.png") RequestBody imgs1,                                          @Part("pic\"; filename=\"image2.png") RequestBody imgs2);    @POST("upload/uploadFile.do")    Observable uploadFiles(@Part("filename") String description, @PartMap() Map, RequestBody> maps);}
3.就是对自己的Retrofit去进行封装设置

(1)retrofit是基于okhttp的加强版,所以第一步去自定义一个okhttpclient,里面设置两个拦截器,一个是日志拦截器,用于对日志的筛选,还一个就是网络拦截器,用于对网络请求头的总体设置。

//日志拦截器HttpLoggingInterceptor interceptor=new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {    @Override    public void log(String message) {        try {            String text = URLDecoder.decode(message, "utf-8");            LogUtils.e(text);        } catch (UnsupportedEncodingException e) {            e.printStackTrace();            LogUtils.e(message);        }    }});
class HttpNetWorkInterceptor implements Interceptor {    @Override    public Response intercept(Chain chain) throws IOException {        Request request = chain.request();        if (!NetUtil.checkNetWork(BaseApplication.getmContext())) {            request = request.newBuilder()                    .cacheControl(CacheControl.FORCE_CACHE)                    .build();            LogUtils.d("no network");        }        Response originalResponse = chain.proceed(request);        if (NetUtil.checkNetWork(BaseApplication.getmContext())) {            //有网的时候读接口上的@Headers里的配置,可以在这里进行统一的设置            String cacheControl = request.cacheControl().toString();            return originalResponse.newBuilder()                    .header("Cache-Control", cacheControl)                    .removeHeader("Pragma")                    .build();        } else {            return originalResponse.newBuilder()                    .header("Cache-Control", "public, only-if-cached, max-stale=2419200")                    .removeHeader("Pragma")                    .build();        }    }}
(2)创建一个okhttpclient

//初始化一个OKhttpClientOkHttpClient okHttpClient=new OkHttpClient.Builder()        .addInterceptor(interceptor)        .readTimeout(8, TimeUnit.SECONDS)        .connectTimeout(8,TimeUnit.SECONDS)        .addNetworkInterceptor(new HttpNetWorkInterceptor())        .cache(cache)        .build();
(3)创建一个Retrofit

Gson gson=new GsonBuilder().setDateFormat("yyyy-MM-dd HH:mm:ss").serializeNulls().create();Retrofit retrofit=new Retrofit.Builder()        .client(okHttpClient)        .addConverterFactory(GsonConverterFactory.create(gson))        .addCallAdapterFactory(RxJava2CallAdapterFactory.create())        .baseUrl(ApiService.API_SERVER_URL)        .build();service=retrofit.create(ApiService.class);
(4)创建一个观察者基类,在其中进行对请求错误的封装和对进度条显示与消失的封装。

public abstract class DefaultObserver<T extends BaseResult> implements Observer<T> {    private Activity activity;    //  Activity 是否在执行onStop()时取消订阅    private boolean isAddInStop = false;    private CommonDialogUtils dialogUtils;    public DefaultObserver(Activity activity) {        this.activity = activity;        dialogUtils=new CommonDialogUtils();        dialogUtils.showProgress(activity);    }    public DefaultObserver(Activity activity, boolean isShowLoading) {        this.activity = activity;        dialogUtils=new CommonDialogUtils();        if (isShowLoading) {            dialogUtils.showProgress(activity,"Loading...");        }    }    @Override    public void onSubscribe(@NonNull Disposable d) {    }    @Override    public void onNext(@NonNull T t) {        dismissProgress();        if (!t.isError()) {            onSuccess(t);        } else {            onFail(t);        }    }    private void dismissProgress(){        if(dialogUtils!=null){            dialogUtils.dismissProgress();        }    }    @Override    public void onError(@NonNull Throwable e) {        LogUtils.e(e.getMessage());        dismissProgress();        if (e instanceof HttpException) {     //   HTTP错误            onException(ExceptionReason.BAD_NETWORK);        } else if (e instanceof ConnectException                || e instanceof UnknownHostException) {   //   连接错误            onException(CONNECT_ERROR);        } else if (e instanceof InterruptedIOException) {   //  连接超时            onException(CONNECT_TIMEOUT);        } else if (e instanceof JsonParseException                || e instanceof JSONException                || e instanceof ParseException) {   //  解析错误            onException(PARSE_ERROR);        } else {            onException(UNKNOWN_ERROR);        }    }    @Override    public void onComplete() {    }    /**     * 请求成功     *     * @param response 服务器返回的数据     */    abstract public void onSuccess(T response);    /**     * 服务器返回数据,但响应码不为200     *     * @param response 服务器返回的数据     */    public void onFail(T response) {        String message = response.getMessage();        if (TextUtils.isEmpty(message)) {            ToastUtils.show(R.string.response_return_error);        } else {            ToastUtils.show(message);        }    }    /**     * 请求异常     *     * @param reason     */    public void onException(ExceptionReason reason) {        switch (reason) {            case CONNECT_ERROR:                ToastUtils.show(R.string.connect_error, Toast.LENGTH_SHORT);                break;            case CONNECT_TIMEOUT:                ToastUtils.show(R.string.connect_timeout, Toast.LENGTH_SHORT);                break;            case BAD_NETWORK:                ToastUtils.show(R.string.bad_network, Toast.LENGTH_SHORT);                break;            case PARSE_ERROR:                ToastUtils.show(R.string.parse_error, Toast.LENGTH_SHORT);                break;            case UNKNOWN_ERROR:            default:                ToastUtils.show(R.string.unknown_error, Toast.LENGTH_SHORT);                break;        }    }    /**     * 请求网络失败原因     */    public enum ExceptionReason {        /**         * 解析数据失败         */        PARSE_ERROR,        /**         * 网络问题         */        BAD_NETWORK,        /**         * 连接错误         */        CONNECT_ERROR,        /**         * 连接超时         */        CONNECT_TIMEOUT,        /**         * 未知错误         */        UNKNOWN_ERROR,    }}
(5)对BaseActivity的封装,通过rxlifecycle对Rxjava的生命周期进行控制

public abstract class BaseActivity extends RxAppCompatActivity {    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(getLayoutId());        init(savedInstanceState);    }    protected void showToast(String msg) {        ToastUtils.show(msg);    }    protected abstract @LayoutRes int getLayoutId();    protected abstract void init(Bundle savedInstanceState);}
(6)对BaseFragment的封装

public abstract class BaseFragment extends RxFragment {    public View rootView;    public LayoutInflater inflater;    @Nullable    @Override    public final View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {        super.onCreateView(inflater, container, savedInstanceState);        this.inflater = inflater;        if (rootView == null) {            rootView = inflater.inflate(this.getLayoutId(), container, false);            init(savedInstanceState);        }        ViewGroup parent = (ViewGroup) rootView.getParent();        if (parent != null) {            parent.removeView(rootView);        }        return rootView;    }    protected abstract int getLayoutId();    protected abstract void init(Bundle savedInstanceState);    protected void showToast(String msg) {        ToastUtils.show(msg);    }    @Override    public void onResume() {        super.onResume();    }    @Override    public void onPause() {        super.onPause();    }    @Override    public void onDestroyView() {        super.onDestroyView();    }}
(7)请求数据的方法

public void getData() {    IdeaApi.getSingleHolder()            .getMezi()            .compose(this.>>bindToLifecycle())            .subscribeOn(Schedulers.io())            .observeOn(AndroidSchedulers.mainThread())            .subscribe(new DefaultObserver>>(this) {                @Override                public void onSuccess(BaseResult> response) {                    List results = response.getResults();                    showToast("请求成功,妹子个数为"+results.size());                }            });}

更多相关文章

  1. Android通讯录数据库介绍与基本操作(增删改查)
  2. Android数据传递相关内容概述
  3. android 数据库同步
  4. android异步发网络请求
  5. android 网络判断
  6. android 网络视频代码
  7. Android 获取网络图片
  8. android 监听联系人数据库

随机推荐

  1. Android如何设置两个view的Z order?
  2. 通过signapk.jar 为Android(安卓)应用程
  3. Android(安卓)Sensor分析
  4. Android(安卓)TextView 设置字与字之间的
  5. 借助HorizontalScrollView实现多列ListVi
  6. Android(安卓)系统名字、版本、API level
  7. Android(安卓)SwipeRefreshLayout Recycl
  8. 应用内存限制
  9. android生命周期总结
  10. Android(安卓)sqlite3插入速度优化方案