SkillAgentSearch skills...

EasyAppMoudle

简单的实现App的module层,不要在意我名字单词打错了......

Install / Use

/learn @ziabo/EasyAppMoudle
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

EasyAppMoudle

注:此处的文档可能更新的不会太频繁,里面有可能会有一些错误的地方,烦请结合简书上面我的博客配合着看

前言: 本人也是一个小菜鸟,写这篇文章意在抛砖引玉,希望有的大神可以来看看我哪里有不足之处,帮我答疑解难!假如有刚接触的小伙伴,也可以一起进步......

首先,看本博客之前你需要掌握以下技能:

1.你是一个Android开发工程师,且迫切希望改变自己项目里面的moudle层 2.你对java的解耦思想有一定了解,基础相对较扎实 3.你要对Android的okHttp3有一定的了解,比如拦截器等... 4.对Retrofit有一定的了解,最起码自己写过Demo测试过 5.对java1.8的RetroLamada知道是什么 6.对RxJava有一定的了解,以及1.x升级到2.x做了什么改动 7.对google的Gson熟练掌握 8.对以上我所说的你确定你都达到了,当然没达到也没关系,后面我会一点一点的讲

首先先贴上一个maven仓库的地址,方便你查询当前maven仓库里面各种库的最新版本. 然后是RxJava 的github地址俗话说得好,任何不懂的问题都可以通过查询源码来解决,人家的注释给你写的很明白,英文水平决定了你的高度. 然后是Retrofit的github地址,个人一直比较喜欢Retrofit这个网络加载框架,Retrofit的英文翻译是改进,更新, 花样翻新...我觉得他们起名字的时候更倾向的是第三种翻译吧,哈哈... 还有okHttp的github地址,okHttp在HttpClient安卓弃用了以后(当然也不能讲弃用,是没法用),是Android开发中的一个利器,简洁方便,但是就是使用原生的话有点费劲,搭配Retrofit以后可以说是如虎添翼.

好了啰啰嗦嗦的说了这么多废话,下面进入正题!

首先是我的项目结构图

项目结构

写这个大致分为以下几步,先列出来后面会一步一步的讲:

  • 1 依赖倒入
  • 2 封装BaseActivity和App(其实这一步每个人有每个人的想法,我只是建议这样写,不足之处望指出)
  • 3 net包下两个拦截器以及自定义Observer
  • 4 bean包下HttpResult类(针对自己的接口编写)
  • 5 api包下面的四个类

大致分为上面的几个步骤,不要着急,容我倒杯茶慢慢道来...

1. 依赖导入

    //okhttp
    compile 'com.squareup.okhttp3:okhttp:3.7.0'
    compile 'com.squareup.okio:okio:1.12.0'
    compile 'com.squareup.okhttp3:logging-interceptor:3.7.0'
    //gson
    compile 'com.google.code.gson:gson:2.8.0'
    //retrofit2
    compile 'com.squareup.retrofit2:retrofit:2.2.0'
    compile 'com.squareup.retrofit2:converter-gson:2.2.0'
    compile 'com.squareup.retrofit2:converter-scalars:2.2.0'
    compile 'com.squareup.retrofit2:adapter-rxjava2:2.2.0'
    //rxJava
    compile'io.reactivex.rxjava2:rxjava:2.0.1'
    compile'io.reactivex.rxjava2:rxandroid:2.0.1'

下面我依次介绍一下上面几个依赖的具体用处

okhttp注释下面的三个

前两个不用多说,用过okhttp的自然都知道,需要注意的一点是第一个版本不能低于3.4.1,具体原因我也不是很清楚,有知道原因的烦请告诉我一声.第三个顾名思义,是okhttp自己提供的log拦截器,方便我们在控制台输出okhttp信息

Retrofit2注释下面的四个

第一个是不必多说,第二个作用是让Retrofit支持gson,添加这个以后可以直接结果出来就生成我们想要的JavaBean.第三个, <strong>A Converter which supports converting strings and both primitives and their boxed types to text/plain bodies.</strong>源码里面是这么介绍的,意思自己理解,我就不关公门前耍大刀了,毕竟自己是四级425分的渣渣...最后一个是Retrofit适配RxJava2必须要添加的

RxJava注释下面的两个

第一个是RxJava 第二个是RxJava适配Android的

注:gson注释下面的就不用我废话了吧

2. 封装BaseActivity和App

因为我在项目里面多次用到Application的Context,以及我的工具类里面需要用到Context的地方也都是用的Application的,所以简单写了一下就是下面这个样子的

public class App extends Application{

    public static Application INSTANCE;
    @Override
    public void onCreate() {
        super.onCreate();
        INSTANCE = this;
        T.register(this);
        NetUtils.register(this);
    }
}

下面贴上我的T这个类,这个类主要是做一些Toast的工作

/**
 * Toast统一管理类
 */
public class T {
    public static Context mContext;
    private static Toast toast;


    private T() {
        /* cannot be instantiated */
        throw new UnsupportedOperationException("cannot be instantiated");
    }


    public static void register(Context context) {
        mContext = context;
    }

    /**
     * 短时间显示Toast
     */
    public static void showShort(CharSequence message) {
        if (mContext==null){
            throw new RuntimeException("unRegister Context in Application");
        }
        if (toast != null) {
            toast.cancel();
        }
        toast = Toast.makeText(mContext, message, Toast.LENGTH_LONG);
        toast.setText(message);
        toast.show();
    }

    public static void showShort(int resId) {
        if (mContext==null){
            throw new RuntimeException("unRegister Context in Application");
        }
        if (toast != null) {
            toast.cancel();
        }
        toast = Toast.makeText(mContext, mContext.getString(resId), Toast.LENGTH_LONG);
        toast.setText(mContext.getString(resId));
        toast.show();
    }

}

友情提示:自定义App以后不要忘了在Manifest.xml的application节点下面加入android:name=".App"这一句!

接下来是我自己的BaseActivity

/**
 * Created by ziabo on 2017/5/9.
 * Activity的Base类
 */

public abstract class BaseActivity extends AppCompatActivity{

    private CompositeDisposable mCompositeDisposable;
    private ApiService mApiService;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (mApiService == null){
            mApiService = ApiService.getApiService();
        }
        setContentView(initContentView());
        initUIAndListener();
        initData();
    }

    /**
     * 设置layout
     */
    protected abstract int initContentView();

    /**
     * 初始化UI和Listener
     */
    protected abstract void initUIAndListener();

    /**
     * 初始化数据
     */
    protected abstract void initData();

    /**
     * 管理所有建立的链接,在onDestroy中清空 mCompositeDisposable
     */
    protected void addDisposable(Disposable disposable){
        if (mCompositeDisposable==null){
            mCompositeDisposable = new CompositeDisposable();
        }
        mCompositeDisposable.add(disposable);
    }

    @Override
    protected void onDestroy() {
        if (mCompositeDisposable != null){
            mCompositeDisposable.clear();
        }
        super.onDestroy();
    }
}

里面有些看不懂的地方不要着急,可以先就看我那三个protected abstract的方法就好,这三个是强制要子类实现的,我们的Activity写出来的时候就是下面这个样子,比较简洁明了..

public class TestActivity extends BaseActivity{
    @Override
    public int initContentView() {
        return 0;//此处放上你的Layout的id
    }

    @Override
    protected void initUIAndListener() {

    }

    @Override
    protected void initData() {

    }
}

注: 一定要注意方法的先后执行顺序!

3. net包下两个拦截器以及自定义Observer

说到拦截器,这个就不得不提一下okHttp的强大之处,此处的两个拦截器一个拦截器是发送请求的时候的调用的,另一个是结果以jsonString返回回来的时候调用的,他们分别的用处我会在下面细讲!先上代码

RequestInterceptor
/**
 * 类名称:请求前拦截器,这个拦截器会在okhttp请求之前拦截并做处理
 */
public class RequestInterceptor implements Interceptor {

    @Override
    public Response intercept(Chain chain) throws IOException {
        Request original = chain.request();
        //请求定制:添加请求头
        Request.Builder requestBuilder = original
                .newBuilder()
                .addHeader("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
        //设置cookie
//        String cookie= App.getCookie();
//        if (StringUtil.checkStr(cookie)) {             //cookie判空检查
//            requestBuilder.addHeader("Cookie", cookie);
//        }

        //如果是post的情况下,请求体定制:统一添加参数,此处演示的是get请求,因此不做处理
        if (original.body() instanceof FormBody) {
            FormBody.Builder newFormBody = new FormBody.Builder();
            FormBody oidFormBody = (FormBody) original.body();
            for (int i = 0; i < oidFormBody.size(); i++) {
                newFormBody.addEncoded(oidFormBody.encodedName(i), oidFormBody.encodedValue(i));
            }
        //当post请求的情况下在此处追加统一参数
//            String client = Constants.CONFIG_CLIENT;
//
//            newFormBody.add("client", client);

            requestBuilder.method(original.method(), newFormBody.build());
        }
        return chain.proceed(requestBuilder.build());
    }
}

里面的注释写的个人觉得挺全的,有什么问题可以具体详细再问!

ResponseInterceptor
/**
 * 结果拦截器,这个类的执行时间是返回结果返回的时候,返回一个json的String,对里面一些特殊字符做处理
 * 主要用来处理一些后台上会出现的bug,比如下面声明的这三种情况下统一替换为:null
 */
public class ResponseInterceptor implements Interceptor {
    private String emptyString = ":\"\"";
    private String emptyObject = ":{}";
    private String emptyArray = ":[]";
    private String newChars = ":null";

    @Override
    public Response intercept(Chain chain) throws IOException {

        Request request = chain.request();
        Response response = chain.proceed(request);
        ResponseBody responseBody = response.body();
        if (responseBody != null) {
            String json = responseBody.string();
            MediaType contentType = responseBody.contentType();
            if (!json.contains(emptyString)) {
                ResponseBody body = ResponseBody.create(contentType, json);
                return response.newBuilder().body(body).build();
            } else {
                String replace = json.replace(emptyString, newChars);
                String replace1 = replace.replace(emptyObject, newChars);
                String replace2 = replace1.replace(emptyArray, newChars);
                ResponseBody body = ResponseBody.create(contentType, replace2);
                return response.newBuilder().body(body).build();
            }
        }
        return response;
    }
}

这个注释好像也挺全的,哈哈... HttpObserver我放到讲api包的时候再讲!!!!

bean包下HttpResult类

一般来讲,我们的接口请求下来的结构大致都是这样的

{
    "code":"noError",
    "data":{
        "banner":Array[3]
    },
    "msg":"",
    "result":true
}

接下来看一下我针对这个接口做的HttpResult类

/**
 * Created by ziabo on 2017/5/9.
 * T就是传递过来的data的类型
 */

public class HttpResult<T> {

    public String code;
    public String msg;
    public boolean result;
    public T data;
}

这个是要手写的,下面这个是GsonFormat自动生成的,toString方法是我自己加进去的,方便打印.所有的变量我都声明为public的方便存取.

/**
 * Created by ziabo on 2017/5/9.
 * 这个是实体类,里面只有我们关注的数据,其他的都统一处理
 */

public class DataBean {

    /**
     * nextPage : 1
     * count : 6
     * pageSize : 20
     * prevPage : 1
     * currentPage : 1
     * pageNum : 1
     * healthInfo : [{"img":"http://test2.mb.zkrj.com/wlstatic/image/2017-03-30/0394155040297634.png","formatCreateDate":"03-30","formatUpdateDate":"04-01","index":1,"updateTime":"2017-04-01 16:01:44","title":"茶的物极必反","accountId":"4028817d549332dd015494a0edd80000","subTitle":"知识","createTime":"2017-03-30 16:19:34","publish":true,"adminAccountId":"4028817d549332dd015494a0edd80000","orders":1,"id":"8a9a35085b180e49015b1e4c604800ad","account":"zkrj"},{"img":"http://test2.mb.zkrj.com/wlstatic/image/2017-03-30/1143420851997416.jpeg","formatCreateDate":"03-30","formatUpdateDate":"04-01","index":2,"updateTime":"2017-04-01 15:59:24","title":"少食多餐在说什么
View on GitHub
GitHub Stars25
CategoryDevelopment
Updated1y ago
Forks5

Languages

Java

Security Score

60/100

Audited on Mar 7, 2025

No findings