RxJava+Retrofit+okhttp+mvp+butterknife实现的简易开源项目

首先介绍下该项目用到的技术点和亮点(大神请绕道,小弟菜鸡)

1. Rxjava+Retrofit+okhttp搭建的网络框架
2. mvp设计模式
3. butterknife注解方式查找控件,减少findViewById冗余代码
4. Glide图片加载框架
5. Recyclerview结合SwipeRefreshLayout实现列表和下拉刷新
6. 封装了ListView和GridView,RecycleView的通用数据适配器工具类

1. Rxjava+Retrofit+okhttp搭建的网络框架

代码我写的浅显易懂,就不一一解释了
主要是CacheHelper,OkHttpClientHelper,RetrofitHelper和HttpUtils这四个类,代码我们主要看RetrofitHelper和HttpUtils这两个

public class RetrofitHelper {

    private final OkHttpClient mClient;
    private Retrofit mRetrofit;

    private RetrofitHelper(){

        mClient = OkHttpClientHelper.getInstance().getOkHttpClient();
    }

    private static RetrofitHelper helper;

    //单例 保证对象唯一
    public static RetrofitHelper getInstance(){
        if(helper==null){
            synchronized (RetrofitHelper.class){
                if(helper==null){
                    helper = new RetrofitHelper();
                }
            }
        }
        return helper;
    }

    //获取Retrofit对象
    public Retrofit getRetrofit(String url){

        if(mRetrofit==null) {
            mRetrofit = new Retrofit.Builder()
                    .baseUrl(url + "/")
                    .addConverterFactory(GsonConverterFactory.create())  //添加Gson支持
                    .addCallAdapterFactory(RxJavaCallAdapterFactory.create())  //添加RxJava支持
                    .client(mClient)                                            //关联okhttp
                    .build();
        }
        return mRetrofit;
    }

    /**
      *获取服务对象   Rxjava+Retrofit建立在接口对象的基础上的
      *泛型避免强制转换
      */
    public static T getService(String url,Class classz){

        return RetrofitHelper.getInstance()
                .getRetrofit(url)
                .create(classz);
    }
}

网络请求工具类

public class HttpUtils {


    //Post方式请求网络
    public static void requestNetByPost(Observable observable, final OnResultListener resultListener){

        setSubscriber(observable, new Subscriber() {
            @Override
            public void onCompleted() {
                Log.e("onCompleted","读取完成");
            }

            @Override
            public void onError(Throwable error) {

                if(error!=null && resultListener!=null){
                    resultListener.onError(error,error.getMessage());
                }else if(resultListener!=null){
                    resultListener.onError(new Exception("网络不给力"),"");
                    Toast.makeText(MyApplication.getContext(),"网络不给力",Toast.LENGTH_LONG).show();
                    return;
                }

                String e  = error.getMessage();
                int code  =0;
                if(!TextUtils.isEmpty(e)){
                    try {
                        e = e.substring(e.length()-3,e.length());
                        code = Integer.valueOf(e);
                    }catch (Exception e1){
                        Toast.makeText(MyApplication.getContext(),"网络不给力",Toast.LENGTH_LONG).show();
                    }
                }
                Log.e("code==:",code+"");
                if(code>=300&&code<500){
                    Toast.makeText(MyApplication.getContext(),"您的请求迷路了,请稍后再试",Toast.LENGTH_LONG).show();
                }else if(code>=500){
                    Toast.makeText(MyApplication.getContext(),"服务器异常,请稍后再试",Toast.LENGTH_LONG).show();
                }else{
                    Toast.makeText(MyApplication.getContext(),"网络不给力",Toast.LENGTH_LONG).show();
                }
            }

            @Override
            public void onNext(T t) {

                if(resultListener!=null){
                    resultListener.onSuccess(t);
                }
            }
        });
    }

    //Get方式请求网络
    public static void requestNetByGet(Observable observable,final OnResultListener resultListener){

        requestNetByPost(observable,resultListener);
    }


    //订阅事件
    public static void setSubscriber(Observable observable, Subscriber subscriber){

        observable.subscribeOn(Schedulers.newThread())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(subscriber);
    }


    //网络请求接口回调
    public interface OnResultListener{

        void onSuccess(T t);
        void onError(Throwable error, String msg);
    }
}

2. mvp设计模式
因为这个项目没涉及数据库方面数据 所以modle我直接放到presenter层实现逻辑处理了,本项目设计三个列表,因为实现方式都差不多,所以我就只介绍其中一个
具体代码如下
bean对象:

public class MeiziInfo {

    public List results;

    public static class MeiziBean{

        public String objectId;
        public String url;
        public String type;
        public String desc;
        public String who;
        public boolean used;
        public boolean hasFadedIn=false;
        public int imageWidth;
        public int imageHeight;
    }
}

Presenter接口和实现类代码

妹子接口
public interface IMeiziPrestener{

    void getMeiziInfo(String url,int page);   
}

妹子接口实现类
public class MeiziPresenterImpl implements IMeiziPrestener{

    private IMeiziModel meiziModel; //没什么用 只是为了好看 哈哈
    private IMeiziFragment iMeiziFragment;   //View接口 后面实现
    public MeiziPresenterImpl(IMeiziFragment iMeiziFragment){
        meiziModel = new MeiziModelImpl();
        this.iMeiziFragment = iMeiziFragment;
    }

    //通过调用网络工具类 获取数据 View接口调用方法 在相应activity或者fragment中实现
    @Override
    public void getMeiziInfo(String url,int page) {

        Observable observable = RetrofitHelper.getService(url, IMeiziService.class).getMeizhiData(page);
        HttpUtils.requestNetByGet(observable, new HttpUtils.OnResultListener() {
            @Override
            public void onSuccess(MeiziInfo meiziInfo) {
                if(meiziInfo!=null)
                    iMeiziFragment.getMeiziDataList(meiziInfo.results);
            }

            @Override
            public void onError(Throwable error, String msg) {
                Log.e("妹子info error",msg);
            }
        });

    }
}

View接口代码

public interface IMeiziFragment {

    void getMeiziDataList(List meiziInfos);
}

3.Activity和 Fragment中实现

MainActivity实现,通过toolbar实现标题栏 实现三fragment切换
注解方式查找控件

public class MainActivity extends BaseActivity {


    @InjectView(R.id.toolbar)
    Toolbar toolbar;
    @InjectView(R.id.nav_view)
    NavigationView navView;
    @InjectView(R.id.drawer)
    DrawerLayout drawer;
    Fragment currentFragment;
    SimpleArrayMap mTitleArryMap = new SimpleArrayMap<>();
    private ZhihuFragment zhihuFragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ButterKnife.inject(this);  //注解初始化这个是必须的
        initData();


        setSupportActionBar(toolbar);
        toolbar.setOnMenuItemClickListener(onMenuItemClick);

        switchFragment(zhihuFragment = new ZhihuFragment());
        currentFragment = zhihuFragment;
        navView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
            @Override
            public boolean onNavigationItemSelected(MenuItem item) {
                switchFragment(getFragmentById(item.getItemId()));
                Log.e("条目内容===",item.toString());
                drawer.closeDrawer(GravityCompat.END);
                return true;
            }
        });

    }

    private void initData() {

    }

    private Fragment getFragmentById(int id) {
        Fragment fragment = null;
        switch (id) {
            case R.id.zhihuitem:
                fragment = new ZhihuFragment();
                break;
            case R.id.topnewsitem:
                fragment=new NewsFragment();
                break;
            case R.id.meiziitem:
                fragment=new MeiziFragment();
                break;

        }
        return fragment;
    }

    private void switchFragment(Fragment fragment) {

        if (currentFragment == null || !currentFragment.getClass().getName().equals(fragment.getClass().getName()))
            getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, fragment)
                    .commit();
        currentFragment = fragment;

    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    private Toolbar.OnMenuItemClickListener onMenuItemClick = new Toolbar.OnMenuItemClickListener() {
        @Override
        public boolean onMenuItemClick(MenuItem menuItem) {
            switch (menuItem.getItemId()) {
                case R.id.menu_open:
                    drawer.openDrawer(GravityCompat.END);
                    break;
            }
            return true;
        }};
}

妹子对应的Fragment实现,注解初始化我在BaseFragment中实现了,在Fragment中注意在onDestroyView方法中调用ButterKnife.reset(this);

public class MeiziFragment extends BaseFragment implements IMeiziFragment,SwipeRefreshLayout.OnRefreshListener {

    @InjectView(R.id.id_meizi_recycle)
    RecyclerView mMeiziRecycle;
    @InjectView(R.id.id_meizi_swipe)
    SwipeRefreshLayout mMeiziSwipe;
    private MeiziPresenterImpl meiziPrestener;
    private MeiziAdapter mMeiziAdapter;
    //妹子地址
    private String url = "http://gank.io";
    private int page = 1;
    private LinearLayoutManager linearLayoutManager;
    private RecyclerView.OnScrollListener mloadmoreListener;
    private boolean loading;
    private List meiziInfos;

    @Override
    public View initView() {
        mView = View.inflate(mActivity, R.layout.fragment_meizi, null);
        return mView;
    }

    @Override
    public void initData() {

        SwipeRefreshUtil.setSiwpeLayout(mMeiziSwipe,mActivity,this);
        meiziInfos = new ArrayList<>();
        meiziPrestener = new MeiziPresenterImpl(this);
        meiziPrestener.getMeiziInfo("",page);
        setRecycleView();
    }

    private void setRecycleView() {

        mMeiziRecycle.addItemDecoration(new GridItemDividerDecoration(getContext(), R.dimen.divider_height, R.color.divider_color));
        mMeiziRecycle.setItemAnimator(new DefaultItemAnimator());
        mMeiziRecycle.setLayoutManager(linearLayoutManager =new LinearLayoutManager(mActivity, LinearLayoutManager.VERTICAL, false));

    }

    @Override
    protected void initListener() {
        super.initListener();
        mloadmoreListener = new RecyclerView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                super.onScrollStateChanged(recyclerView, newState);
            }

            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
                super.onScrolled(recyclerView, dx, dy);
                if (dy > 0 && linearLayoutManager!=null) //向下滚动
                {
                    int visibleItemCount = linearLayoutManager.getChildCount();
                    int totalItemCount = linearLayoutManager.getItemCount();
                    int pastVisiblesItems = linearLayoutManager.findFirstVisibleItemPosition();

                    if (!loading && (visibleItemCount + pastVisiblesItems) >= totalItemCount) {
                        loading = true;
                        page+=1;
                        loadMoreData();
                    }
                }
            }
        };
    }

    private void loadMoreData() {
        Log.e("当前页数==",page+"");
        meiziPrestener.getMeiziInfo("",page);

    }


    @Override
    public void getMeiziDataList(List meiziInfos) {

        mMeiziSwipe.setRefreshing(false);
        if(meiziInfos==null || meiziInfos.size()<=0)
            return;
        loading = false;
        this.meiziInfos.addAll(meiziInfos);
        Log.e("妹子数据集合==",meiziInfos.size()+"");
        if(mMeiziAdapter==null) {
            mMeiziRecycle.setAdapter(mMeiziAdapter = new MeiziAdapter(mActivity, this.meiziInfos));
        }else{
            mMeiziAdapter.notifyDataSetChanged();
        }

        mMeiziRecycle.addOnScrollListener(mloadmoreListener);
    }

    @Override
    public void onRefresh() {

        new Handler().postDelayed(new Runnable() {
            @Override
            public void run() {
                meiziInfos.clear();
                page = 1;
                loading = false;
                meiziPrestener.getMeiziInfo("",page);
            }
        },1000);
    }
}

4. ListView和GridView,RecycleView的通用数据适配器工具类封装
ListView通用适配器在我的“你还在用第三方开源下拉刷新控件吗?试试google自带的下拉刷新控件SwipeRefreshLayout”这篇博客中有讲解

RecycleView通用适配器实现

public abstract class CommonRecyclerViewAdapter<T> extends RecyclerView.Adapter<CommonRecyclerViewHolder>{


    protected Context mContext;
    protected List mDatas;
    protected View mView;
    private CommonRecyclerViewHolder viewHolder;

    public CommonRecyclerViewAdapter(Context context, List datas){
        this.mContext = context;
        this.mDatas = datas;
    }


    @Override
    public CommonRecyclerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        mView = initView();
        viewHolder = new CommonRecyclerViewHolder(mContext,mView);
        return viewHolder;
    }

    @Override
    public int getItemCount() {
        return mDatas!=null && mDatas.size()>0 ? mDatas.size() : 0;
    }

    @Override
    public  void onBindViewHolder(CommonRecyclerViewHolder holder, int position){
        setData(holder,position);
    }


    public CommonRecyclerViewHolder getViewHolder() {
        return viewHolder;
    }

    public abstract View initView();  //加载布局

    public abstract void setData(CommonRecyclerViewHolder holder, int position);   //设置数据 处理逻辑

}

CommonRecyclerViewHolder 类实现

public class CommonRecyclerViewHolder extends RecyclerView.ViewHolder{

    private final SparseArray mViews;  //相当于Map集合 不过效率更高,key只能为Integer
    private View mConvertView;
    private int mPosition;
    private Context mContext;
    public CommonRecyclerViewHolder(Context context,View itemView) {
        super(itemView);
        this.mConvertView = itemView;
        this.mContext = context;
        this.mViews = new SparseArray<>();
    }

    /**
     * 通过控件的Id获取对应的控件,如果没有则加入views
     * @param viewId
     * @return
     */
    public extends View> T getView(int viewId){

        View view = mViews.get(viewId);
        if(view==null && mConvertView!=null){
            view = mConvertView.findViewById(viewId);
            mViews.put(viewId,view);
        }
        return (T) view;
    }

    /**
     * 为TextView设置字符串
     *
     * @param viewId
     * @param text
     * @return
     */
    public CommonRecyclerViewHolder setText(int viewId, String text)
    {
        TextView view = getView(viewId);
        view.setText(text);
        return this;
    }

    /**
     * 为ImageView设置图片
     */
    public CommonRecyclerViewHolder setImageResource(int viewId,int resId){

        ImageView imageView = getView(viewId);
        imageView.setImageResource(resId);
        return this;
    }

    /**
     * 为ImageView设置图片
     */
    public CommonRecyclerViewHolder setImageBitmap(int viewId,Bitmap bitmap){

        ImageView imageView = getView(viewId);
        imageView.setImageBitmap(bitmap);
        return this;
    }


    public void showImage(int viewId,String imageUrl){
        ImageView view = getView(viewId);
        ImageUtil.show(view,imageUrl);
    }

}

5. Glide实现的图片加载框架

public class ImageUtil {


    /**===========================加载图片方式,可换其他框架加载===========================================================================*/
    /**
     * 以正常模式加载网络图片
     */

    public static void show(ImageView mImageView, String imageUrl) {


        Glide.with(MyApplication.getContext()).load(imageUrl)
                .crossFade(0)
                .into(mImageView);  //crossFade是个淡入淡出效果
    }


    /**
     * 以拉伸模式加载网络图片
     */
    public static void show1(ImageView mImageView, String imageUrl) {
        Glide.with(MyApplication.getContext()).load(imageUrl)
                .fitCenter()
                .diskCacheStrategy(DiskCacheStrategy.ALL)
                .transform(new GlideRoundTransform(MyApplication.getContext(),8))
                .crossFade(0)
                .into(mImageView);  //crossFade是个淡入淡出效果
    }

    //加载正方形图片
    public static void showSquare(ImageView mImageView, String imageUrl) {


        Glide.with(MyApplication.getContext()).load(imageUrl)
                .diskCacheStrategy(DiskCacheStrategy.ALL)
                .centerCrop()
                .into(mImageView);
    }

    //加载正方形图片(商品)
    public static void showSquare2(ImageView mImageView, String imageUrl) {

        Glide.with(MyApplication.getContext()).load(imageUrl)
                .diskCacheStrategy(DiskCacheStrategy.ALL)
                .into(mImageView);
    }


    /**
     * 加载圆头像
     */
    public static void showCircle(final ImageView mImageView, String imageUrl) {

        Glide.with(MyApplication.getContext()).load(imageUrl)
                .diskCacheStrategy(DiskCacheStrategy.ALL)
                .fitCenter()
                .bitmapTransform(new CropCircleTransformation(MyApplication.getContext()))
                .crossFade(0)
                .into(mImageView);
    }



    public static void showRoundedImage(ImageView imageView, String imageUrl) {

        Glide.with(MyApplication.getContext())                                 //可以传getApplicationContext Activity Fragment
                .load(imageUrl)                                  //图片地址
                .diskCacheStrategy(DiskCacheStrategy.ALL)
                .transform(new GlideRoundTransform(MyApplication.getContext(),4))
                .centerCrop()
                .into(imageView);
    }


    public static void showGoodsImage(ImageView imageView, String imageUrl){

        Glide.with(MyApplication.getContext())                                 //可以传getApplicationContext Activity Fragment
                .load(imageUrl)                                  //图片地址
                .diskCacheStrategy(DiskCacheStrategy.ALL)
                .transform(new GlideRoundTransform(MyApplication.getContext(),4))
                .into(imageView);
    }


    public static void showRoundedImage2(ImageView imageView, String imageUrl,int radius) {


        Glide.with(MyApplication.getContext())                                 //可以传getApplicationContext Activity Fragment
                .load(imageUrl)                                  //图片地址
                .diskCacheStrategy(DiskCacheStrategy.ALL)
                .transform(new GlideRoundTransform(MyApplication.getContext(),radius))
                .into(imageView);
    }


    /**
     * 加载高斯模糊
     */
    public static void show2(ImageView mImageView, String imageUrl) {

        Glide.with(MyApplication.getContext())
                .load(imageUrl)
                .bitmapTransform(new BlurTransformation(MyApplication.getContext(), 25)).crossFade(0)
                .into(mImageView);
    }



    //=========================Glide加载GIF图片配置==============================================================//

    //加载本地GIF
    public static void showGIF(ImageView imageView,int img){
        Glide.with(MyApplication.getContext()).load(img).asGif()
                .diskCacheStrategy(DiskCacheStrategy.SOURCE)
                .into(imageView);
    }

    //加载网络GIF
    public static void showGIF(ImageView imageView,String img){
       Glide.with(MyApplication.getContext()).load(img).asGif().diskCacheStrategy(DiskCacheStrategy.SOURCE).into(imageView);
    }


}

6. 总结
我是读了网上的一个开源项目然后自己封装仿写的这个项目 不过我感觉比它写的好 至少代码可读性要强 哈哈(你个自恋狂)

7. 源代码下载
点击进入GitHub下载
如果觉得好,请随手star,如果不好,欢迎批评指点。Thanks you very much!
或者 下载需要2积分 sorry

8.效果展示
本来是想录制gif图片的,因为一些原因只能截图了
RxJava+Retrofit+okhttp+mvp+butterknife实现的简易开源项目_第1张图片

RxJava+Retrofit+okhttp+mvp+butterknife实现的简易开源项目_第2张图片

9. 联系方式
qq:1509815887
email:[email protected]

你可能感兴趣的:(开发类)