最新Retrofit + RxJava + MVP

栏目: Java · 发布时间: 7年前

内容简介:最新Retrofit + RxJava + MVP

此处搭建的框架是目前最新版本,项目今天刚搭建好,( ^__^ ) 嘻嘻……。

先撸上包:

compile ‘com.jakewharton:butterknife:8.6.0’

compile ‘com.jakewharton:butterknife-compiler:8.6.0’

compile ‘io.reactivex.rxjava2:rxjava:2.1.0’

compile ‘io.reactivex.rxjava2:rxandroid:2.0.1’

compile ‘com.squareup.retrofit2:converter-gson:2.3.0’

compile ‘com.squareup.retrofit2:retrofit:2.3.0’

compile ‘com.google.code.gson:gson:2.8.0’

compile ‘com.squareup.retrofit2:adapter-rxjava2:2.3.0’

本人还是挺嫌弃Gson的,一定会有人说,嫌弃还用,我勒个去,我想支持下国产用fastjson,丫的,retrofit2.X没给出支持包,不想使用其它第三方包,只能等有空的时候自己摸索一个出来了,更高效的LoganSquare也不支持,无语了,那就考虑下jackson,发现jackson的包1M多,算了,jackson洗洗睡吧,无奈之下选择了gson,肯定会有人想,为啥主流的json解析工具gson这么受嫌弃,gson在解析的效率上对比其它几个第三方,还是明显偏低的。

废话不多说,直接撸代码,因为写了很多详细的注释,未来还会写几篇帖子专门分析,此处就不多做介绍。

先看下目录结构图

最新Retrofit + RxJava + MVP

最新Retrofit + RxJava + MVP

除了删除test文件和删了baseUrl里的地址外,其它全部上传到我的github了,最后会附上地址。

BaseActivity:

/**
 * Created by Zero on 2017/5/25.
 */
public abstract class BaseActivity<Pre extends BasePresenter> extends AppCompatActivity implements OnClickListener {

    private static final String DIALOG_LOADING = "DialogLoading";
    private boolean mVisible;
    private LoadingDialogFragment waitDialog = null;

    protected Pre presenter;
    protected final Handler mHandler = new MyHandler(this);
    private BroadcastReceiver receiver;
    private IntentFilter filter;

    private class MyHandler extends Handler {
        private final WeakReference<BaseActivity> mActivity;

        /**
         * 因为内部类会隐式强引用当前类,采用弱引用,避免长生命周期导致内存泄漏
         *
         * @param activity
         */
        private MyHandler(BaseActivity activity) {
            mActivity = new WeakReference<>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            if (mActivity.get() != null) {
                requestOver(msg);
            }
        }
    }

    @Override
    protected final void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            getWindow().setNavigationBarColor(Color.BLACK);
        }

        if (initLayout() != 0) {
            /**
             * 设置布局,其实很多view注解框架都可以对layout抓取到,但还是习惯这样写,^_^
             */
            setContentView(initLayout());
            ButterKnife.bind(this);
        }

        try {
            if (getPsClass() != null) {
                if (getPsClass().newInstance() instanceof BasePresenter) {
                    /**
                     * presenter实例化,new和newInstance()不清晰,自己百度
                     */
                    presenter = (Pre) getPsClass().newInstance();
                    /**
                     * 把一些必要的数据和presenter传过去
                     */
                    presenter.initBaseData(this, mHandler, getIView(), getIntent());
                } else {
                    throw new RuntimeException("必须继承BasePresenter");
                }
            }
        } catch (InstantiationException e) {
            /**
             * 不能newInstance()导致的错误
             */
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            /**
             * 权限不足,主要是构造方法使用了private
             */
            e.printStackTrace();
        }

        initData();
        initViewAndListen();
    }

    /**
     * 传入需要过滤的action不定参数
     *
     * @param filterActions
     */
    protected void registerReceiver(@NonNull String... filterActions) {
        filter = filter == null ? new IntentFilter() : filter;
        for (String action : filterActions) {
            filter.addAction(action);
        }
        registerReceiver(filter);
    }

    /**
     * 传入filter,注册广播
     *
     * @param filter
     */
    protected void registerReceiver(@NonNull IntentFilter filter) {
        // TODO Auto-generated method stub
        receiver = new BroadcastReceiver() {

            @Override
            public void onReceive(Context context, Intent intent) {
                executeReceiver(context, intent);
            }
        };
        LocalBroadcastManager.getInstance(this).registerReceiver(
                receiver, filter);
    }

    /**
     * 接收到广播
     *
     * @param context
     * @param intent
     */
    protected void executeReceiver(Context context, Intent intent) {

    }

    /**
     * setontentview()
     *
     * @return
     */
    abstract protected int initLayout();

    /**
     * 使用比如ButterKnife可以不使用
     */
    abstract protected void initViewAndListen();

    /**
     * 初始化简单数据,比如传过来的title
     */
    abstract protected void initData();

    /**
     * 不用多个类实现OnClickListener
     *
     * @param v
     */
    abstract protected void onclick(View v);

    /**
     * @return presenter, 此处不能使用返回Pre类型,newInstance()方法是class下的,Pre不能使用newInstance()实例化
     */
    abstract protected Class getPsClass();

    /**
     * 接口回调
     *
     * @return
     */
    abstract protected BaseInterface getIView();

    /**
     * 把发送到view层的message传递到presenter层处理,因为采用了rxjava和retrofit,
     * 很多view不在使用handler发送数据,所以没写成抽象方法
     *
     * @param msg
     */
    protected void requestOver(Message msg) {
        if (presenter != null) {
            presenter.handMsg(msg);
        }
    }

    protected void to(Intent intent) {
        startActivity(intent);
    }

    protected void to(Class<?> T) {
        Intent intent = new Intent(this, T);
        to(intent);
    }

    protected void to(Class<?> T, Bundle bundle) {
        Intent intent = new Intent(this, T);
        intent.putExtras(bundle);
        to(intent);
    }

    @Override
    public void onBackPressed() {
        if (waitDialog != null) {
            hideProcessDialog();
        } else {
            super.onBackPressed();
        }
    }

    public LoadingDialogFragment showProcessDialog() {
        return showProcessDialog(R.string.loading);
    }

    public LoadingDialogFragment showProcessDialog(int resId) {
        return showProcessDialog(getString(resId));
    }

    private LoadingDialogFragment showProcessDialog(String msg) {
        if (mVisible) {
            FragmentManager fm = getSupportFragmentManager();
            if (waitDialog == null) {
                waitDialog = LoadingDialogFragment.newInstance(msg);
            }

            if (!waitDialog.isAdded()) {
                waitDialog.show(fm, DIALOG_LOADING);
            }

            return waitDialog;
        }
        return null;
    }

    public void hideProcessDialog() {
        if (mVisible && waitDialog != null) {
            try {
                waitDialog.dismiss();
                waitDialog = null;
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }
    }

    @Override
    public void setVisible(boolean visible) {
        mVisible = visible;
    }

    @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            View v = getCurrentFocus();
            if (isShouldHideKeyboard(v, ev)) {
                hideKeyboard(v.getWindowToken());
                v.clearFocus();
            }
        }
        return super.dispatchTouchEvent(ev);
    }

    /**
     * 根据EditText所在坐标和用户点击的坐标相对比,来判断是否隐藏键盘,因为当用户点击EditText时则不能隐藏
     *
     * @param v
     * @param event
     * @return
     */
    private boolean isShouldHideKeyboard(View v, MotionEvent event) {
        if (v != null && (v instanceof EditText)) {
            int[] l = {0, 0};
            v.getLocationInWindow(l);
            int left = l[0],
                    top = l[1],
                    bottom = top + v.getHeight(),
                    right = left + v.getWidth();
            if (event.getX() > left && event.getX() < right
                    && event.getY() > top && event.getY() < bottom) {
                // 点击EditText的事件,忽略它。
                return false;
            } else {
                return true;
            }
        }
        return false;
    }

    /**
     * 获取InputMethodManager,隐藏软键盘
     *
     * @param token
     */
    private void hideKeyboard(IBinder token) {
        if (token != null) {
            InputMethodManager im = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
            im.hideSoftInputFromWindow(token, InputMethodManager.HIDE_NOT_ALWAYS);
        }
    }

    @Override
    public void onClick(View v) {
        // TODO Auto-generated method stub
        onclick(v);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        /**
         * 移除mHandler,避免因为移除mHandler超activity生命周期工作造成内存泄漏
         */
        mHandler.removeCallbacksAndMessages(null);
        if (receiver != null) {
            LocalBroadcastManager.getInstance(this).unregisterReceiver(receiver);
        }
    }
}

这是我从上一个私活项目演化而来,当然,上个项目也是我从无到有,目前此类还少了一个对toolbar的封装。

BaseObserver类

/**
 * Observer的封装
 * Created by Zero on 2017/5/28.
 */

public class BaseObserver<T> implements Observer<ResponseBody> {

    private IResponse iResponse;
    private Gson mGson;
    private final Type finalNeedType;
    private static final int UNLOGIN_EXCEPTION = 33333;
    private static final int REQUEST_EXCEPTION = 1003;

    public BaseObserver(IResponse<T> iResponse) {
        this.iResponse = iResponse;
        mGson = new Gson();

        final Type[] types = iResponse.getClass().getGenericInterfaces();

        if (MethodHandler(types) == null || MethodHandler(types).size() == 0) {

        }
        finalNeedType = MethodHandler(types).get(0);
    }

    /**
     * 通过反射,拿到所需要的类型
     * @param types
     * @return
     */
    private List<Type> MethodHandler(Type[] types) {
        List<Type> needTypes = new ArrayList<>();

        for (Type paramType : types) {
            if (paramType instanceof ParameterizedType) {
                Type[] parenTypes = ((ParameterizedType) paramType).getActualTypeArguments();
                for (Type childType : parenTypes) {
                    needTypes.add(childType);
                    if (childType instanceof ParameterizedType) {
                        Type[] childTypes = ((ParameterizedType) childType).getActualTypeArguments();
                        for (Type type : childTypes) {
                            needTypes.add(type);
                        }
                    }
                }
            }
        }
        return needTypes;
    }

    @Override
    public void onSubscribe(Disposable d) {

    }

    @Override
    public void onNext(ResponseBody responseBody) {

        try {
            /**
             * responseBody.string()当前打断点,获取不到值,具体原因还未去查找,此处先用result接收
             */
            String result = responseBody.string();
            BaseResponse httpResponse = mGson.fromJson(result,finalNeedType);
            if (httpResponse.isSuccess()) {
                iResponse.onSuccess(httpResponse);
            } else {
                if (httpResponse.getCode() == UNLOGIN_EXCEPTION) {
                    iResponse.onError(new UnLoginException(httpResponse.getCode(), httpResponse.getMessage()));
                } else if (httpResponse.getCode() == REQUEST_EXCEPTION) {
                    iResponse.onError(new RequestExpiredException(httpResponse.getCode(), httpResponse.getMessage()));
                } else {
                    iResponse.onError(new APIException(httpResponse.getCode(), httpResponse.getMessage()));
                }
            }
        } catch (IOException e) {
            iResponse.onError(e);
        }
    }

    @Override
    public void onError(Throwable e) {
        iResponse.onError(e);
    }

    @Override
    public void onComplete() {

    }
}

RetrofitFactory类

/**
 * 此类主要是对retrofit进行配置
 * Created by Zero on 2017/5/26.
 */

public class RetrofitFactory {

    private RetrofitFactory() {
        new RuntimeException("反射个毛线,好玩吗?");
    }

    private static OkHttpClient httpClient = MyOkHttpClient.getInstance();

    private static ApiService retrofitService;

    private static String baseUrl = "";

    private static Retrofit retrofit;

    /**
     * 默认为ApiService
     *
     * @return
     */
    public static ApiService getInstance() {
        if (retrofitService == null) {
            synchronized (RetrofitFactory.class) {
                if (retrofitService == null) {
                    retrofitService = getInstanceRetrofit().create(ApiService.class);
                }
            }
        }
        return retrofitService;
    }

    /**
     * baseUrl
     */
    private static void getBaseUrl() {
        baseUrl = HttpConfig.getServer();
    }

    private static Retrofit getInstanceRetrofit() {
        if (retrofit == null) {
            synchronized (RetrofitFactory.class) {
                if (retrofit == null) {
                    if (TextUtils.isEmpty(baseUrl)) {
                        getBaseUrl();
                    }

                    retrofit = new Retrofit.Builder()
                            .baseUrl(baseUrl)
                            .addConverterFactory(GsonConverterFactory.create())
                            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                            .client(httpClient)
                            .build();
                }
            }
        }
        return retrofit;
    }

    /**
     * 用于创建自定义的apiService
     *
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T createRetrofitService(final Class<T> clazz) {
        return getInstanceRetrofit().create(clazz);
    }
}

RequestUtil类

/**
 * 请求的封装入口
 * Created by Zero on 2017/5/25.
 */

public class RequestUtil {
    /**
     * get方式处理
     *
     * @param url
     * @param map
     * @param iResponse
     * @param <T>
     */
    public static <T> Observable<ResponseBody> getDispose(String url, Map map, final IResponse<T> iResponse) {
        Observable<ResponseBody> observable = RetrofitFactory.getInstance().executeGet(url, map);
        return getObservable(observable, iResponse, null);
    }

    private static <T> Observable<ResponseBody> getDispose(String url, Map map, final IResponse<T> iResponse, Map cacheMap) {
        Observable<ResponseBody> observable = RetrofitFactory.getInstance().executeGet(url, map);
        return getObservable(observable, iResponse, cacheMap);
    }

    /**
     * 自定义ApiService
     *
     * @param clazz
     * @param <T>
     * @return
     */
    public static <T> T getCutomService(Class<T> clazz) {
        return RetrofitFactory.createRetrofitService(clazz);
    }

    /********************************post********************************/

    public static <T> void postDispose(String url, Map map, final IResponse<T> iResponse) {

        Observable<ResponseBody> observable = RetrofitFactory.getInstance().executePost(url, map);
        observable.observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(Schedulers.io())
                .subscribe(new BaseObserver<>(iResponse));
    }

    private static <T> Observable<ResponseBody> postDispose(String url, Map map, final IResponse<T> iResponse, Map cacheMap) {
        Observable<ResponseBody> observable = RetrofitFactory.getInstance().executePost(url, map);
        return getObservable(observable, iResponse, cacheMap);
    }

    /**
     * 获取Observable对象,
     * 此处名称的get为获取的意思,不是数据请求方式
     * @param observable
     * @param iResponse
     * @param cacheMap
     * @param <T>
     * @return
     */
    private static <T> Observable<ResponseBody> getObservable(Observable<ResponseBody> observable, IResponse<T> iResponse, Map cacheMap) {
        if (cacheMap != null && cacheMap.size() > 0) {
            CacheManager.addData(cacheMap.get("cacheKey").toString(), observable, (int) cacheMap.get("period"));
        }
        observable.observeOn(AndroidSchedulers.mainThread())
                .subscribeOn(Schedulers.io())
                .subscribe(new BaseObserver<>(iResponse));
        return observable;
    }


    /**************************************cache**************************************/

    private static <T> void cacheData(String url, Map map, final IResponse<T> iResponse, int period,boolean isGet){
        String cacheKey = url + getCacheKey(map);
        CacheObject data = CacheManager.getData(cacheKey);
        if (data == null) {
            Map cacheMap = new HashMap();
            cacheMap.put("cacheKey", cacheKey);
            cacheMap.put("period", period);
            if (isGet) {
                getDispose(url, map, iResponse, cacheMap);
            }else{
                postDispose(url, map, iResponse, cacheMap);
            }
        } else {
            getObservable((Observable<ResponseBody>) data.getObject(), iResponse, null);
        }
    }

    /**
     * get方式请求,需要做本地cache
     */
    public static <T> void getDisposeWithCache(String url, Map map, final IResponse<T> iResponse, int period) {
        cacheData(url,map,iResponse,period,true);
    }

    /**
     * post方式请求,需要做本地cache
     */
    public static <T> void postDisposeWithCache(String url, Map map, final IResponse<T> iResponse, int period) {
        cacheData(url,map,iResponse,period,false);
    }

    private static String getCacheKey(Map param) {
        if (param == null) {
            return "";
        }
        StringBuffer sb = new StringBuffer("");
        TreeMap treeMapParams = new TreeMap(param);
        for (Object key : treeMapParams.keySet()) {
            /**
             * 过滤掉token,根据自己需要
             */
            if (!key.toString().equals("token")) {
                sb.append(key).append("=").append(Uri.encode(treeMapParams.get(key).toString()));
            }
        }
        return sb.toString();
    }
}

RequestUtil、BaseObserver、RetrofitFactory三者相辅相成,通过RetrofitFactory进行retrofit的一系列配置,通过RequestUtil进行get/post数据请求,最后通过BaseObserver把RequestUtil数据请求中获取到的Observer进一步处理。

CacheManager类

/**
 * 数据请求中对cache进行管理
 * Created by Zero on 2017/5/30.
 */

public class CacheManager {

    private static Map<String, CacheObject> cacheMap = new HashMap<>();

    /**
     * 添加到cache
     * @param key
     * @param data
     * @param period
     */
    public static void addData(String key, Object data, int period) {
        CacheObject cacheObject = getData(key);
        if (cacheObject != null) {
            cacheObject.setPeriod(period);
        } else {
            cacheObject = new CacheObject(data, period);
        }
        cacheMap.put(key, cacheObject);
    }

    /**
     * 获取cache
     * @param key
     * @return
     */
    public static CacheObject getData(String key) {
        CacheObject cacheObject = cacheMap.get(key);
        if (cacheObject != null) {
            if (cacheObject.isValid()) {
                return cacheObject;
            } else {
                removeInvalidData(key);
            }
        }
        return null;
    }

    /**
     * 移除过期的key
     * @param key
     */
    public static void removeInvalidData(String key){
        if(cacheMap.containsKey(key)){
            cacheMap.remove(key);
        }
    }
}

CacheObject类

/**
 * Created by Zero on 2017/5/30.
 */

public class CacheObject {

    private long timestamp;
    private int period = -1;
    private Object data;

    /**
     * @param data
     * @param period -1 表示永不过期,大于0表示过期的时间,单位分钟
     */
    public CacheObject(Object data, int period) {
        timestamp = System.currentTimeMillis();
        this.data = data;
        this.period = period;
    }

    public Object getObject() {
        return data;
    }

    public boolean isValid() {
        if (period == -1 || System.currentTimeMillis() < (timestamp + period * 60000)) {
            return true;
        }
        return false;
    }

    public void setPeriod(int period) {
        this.period = period;
    }

    public int getPeriod() {
        return period;
    }
}

CacheObject和CacheManager两个类,分别是对cache进行配置和管理,在数据请求中,比如获取省区县三级目录,这些都不需要多次请求的,可以加载到cache中,当以后再想使用的时候,直接从cache中获取,减轻服务器压力。

LogInterceptor类

/**
 * 打印网络请求时传输的字段还有返回的json数据
 * Created by Zero on 2017/5/27.
 */

public class LogInterceptor implements Interceptor {
    private final static String TAG = LogInterceptor.class.getSimpleName();

    @Override
    public okhttp3.Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        long t1 = System.nanoTime();
        okhttp3.Response response = chain.proceed(chain.request());
        long t2 = System.nanoTime();

        StringBuffer sb = new StringBuffer();
        sb.append(request.method()).append("\n");
        String url[] = request.url().toString().split("\\?");
        sb.append(url[0]).append("\n");
        if (url.length == 2) {
            String params[] = url[1].split("&");
            for (String param : params) {
                sb.append(Uri.decode(param)).append("\n");
            }
        }

        if(request.body() instanceof FormBody){
            FormBody postParams = ((FormBody) request.body());
            if (postParams != null) {
                sb.append("post:").append("\n");
                int size = postParams.size();
                for (int i = 0; i < size; i++) {
                    sb.append(postParams.encodedName(i) + "=" + java.net.URLDecoder.decode(postParams.encodedValue(i), "utf-8")).append("\n");
                }
            }
        }

        okhttp3.MediaType mediaType = response.body().contentType();
        String content = response.body().string();
        Log.v(TAG, String.format(Locale.getDefault(), "%s cost %.1fms%n%s", sb.toString(), (t2 - t1) / 1e6d, format(content)));
        //格式化打印json
        //       Log.v(TAG, String.format(Locale.getDefault(), "%s cost %.1fms%n%s", sb.toString(), (t2 - t1) / 1e6d, format(content)));
//        Log.v(TAG, String.format(Locale.getDefault(), "%s cost %.1fms%n%s", sb.toString(), (t2 - t1) / 1e6d, content));
        return response.newBuilder()
                .body(okhttp3.ResponseBody.create(mediaType, content))
                .build();
    }

    public static String format(String jsonStr) {

        int level = 0;
        StringBuffer jsonForMatStr = new StringBuffer();
        for (int i = 0; i < jsonStr.length(); i++) {
            char c = jsonStr.charAt(i);
            if (level > 0 && '\n' == jsonForMatStr.charAt(jsonForMatStr.length() - 1)) {
                jsonForMatStr.append(getLevelStr(level));
            }
            switch (c) {
                case '{':
                case '[':
                    jsonForMatStr.append(c + "\n");
                    level++;
                    break;
                case ',':
                    jsonForMatStr.append(c + "\n");
                    break;
                case '}':
                case ']':
                    jsonForMatStr.append("\n");
                    level--;
                    jsonForMatStr.append(getLevelStr(level));
                    jsonForMatStr.append(c);
                    break;
                default:
                    jsonForMatStr.append(c);
                    break;
            }
        }
        return jsonForMatStr.toString();
    }

    private static String getLevelStr(int level) {
        StringBuffer levelStr = new StringBuffer();
        for (int levelI = 0; levelI < level; levelI++) {
            levelStr.append("\t");
        }
        return levelStr.toString();
    }
}

最新Retrofit + RxJava + MVP

一图胜千言,不做更多赘述。

由于项目今天刚搭建好,肯定也存在很多问题,日后会有不断完善,今天就不多做叙述了,如有什么疑问,可以留言,也可以加QQ群,如有什么错误,也请多多指正,共勉共进。

github链接戳此CSDN下载链接戳此。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

逻辑的引擎

逻辑的引擎

[美] 马丁·戴维斯 / 张卜天 / 湖南科学技术出版社 / 2005-5 / 20.00元

本书介绍了现代计算机背后的那些基本概念和发展这些概念的人,描写了莱布尼茨、布尔、费雷格、康托尔、希尔伯特、哥德尔、图灵等天才的生活和工作,讲述了数学家们如何在成果付诸应用之前很久就已经提出了其背后的思想。博达著作权代理有限公司授权出版据美国W.W.Norton公司2000年版本译出。2007年第二版亦使用同一ISBN。一起来看看 《逻辑的引擎》 这本书的介绍吧!

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

随机密码生成器
随机密码生成器

多种字符组合密码

HEX HSV 转换工具
HEX HSV 转换工具

HEX HSV 互换工具