从零开始搭建MVC项目

前言

这篇文章主要记录如何搭建一个MVP架构,同时结合Retrofit,RxJava,Okhttp等主流框架实现网络请求,方便后面的复习以及快速开发。

项目分包

这里写图片描述

base:放一些基类,Activity,Adapter,Present等
common:存放常量,Application
model:模型层,存放实体类以及网络请求相关
presenter:P层,接收View层的命令,调用M层获取数据,通知View层更新
util:存放一些工具类
view:View层,包括Activity,Fragment,adapter,自定义View等

用到的框架依赖

//RxJava
    compile 'io.reactivex:rxjava:1.1.6'
    compile 'com.trello:rxlifecycle:0.6.1'
    compile 'com.trello:rxlifecycle-components:0.6.1'
    //Picasso
    compile 'com.squareup.picasso:picasso:2.5.2'
    //Retrofit库
    compile 'com.squareup.retrofit2:retrofit:2.0.2'
    compile 'com.squareup.retrofit2:converter-gson:2.0.2'
    compile 'com.squareup.retrofit2:adapter-rxjava:2.0.2'
    //切换Android主线程
    compile 'io.reactivex:rxandroid:1.0.1'
    // Okhttp库
    compile 'com.squareup.okhttp3:okhttp:3.1.2'
    //dagger2(暂时没用到)
    compile 'com.google.dagger:dagger:2.4'
    apt 'com.google.dagger:dagger-compiler:2.4'
    //java注解(暂时没用到)
    compile 'org.glassfish:javax.annotation:10.0-b28'
    //日志
    compile 'com.orhanobut:logger:1.15'
    //okhttp通用参数拦截器(暂时没用到)
    compile 'com.github.jkyeo:okhttp-basicparamsinterceptor:v0.9'

View层实现

首先我们定义一个MvpView

/**
 * 所有View的基类
 */

public interface MvpView {
}

我们自己定义的View需要实现这个接口

public interface IMovieView extends MvpView {
    void showLoading();
    void hideLoading();
    void showError(Throwable e);
    void setMovieInfo(MovieInfo movieInfo);
}

Presenter层

/**
 *  P层接口基类,需要关联View
 */
interface MvpPresenter<V extends MvpView>  {
    //关联View
    void attachView(V view);
    //解除关联
    void  detachView();
}
/**
 *  实现Presenter层的具体逻辑
 */

public class BasePresenter<V extends MvpView> implements MvpPresenter<V>{
    private V mMvpView;
    //管理RxJava的订阅
    protected CompositeSubscription mCompositeSubscription;
    //关联View
    @Override
    public void attachView(V view) {
        mMvpView = view;
        mCompositeSubscription = new CompositeSubscription();
    }

    @Override
    public void detachView() {
        mMvpView = null;
        mCompositeSubscription.clear();
        mCompositeSubscription = null;
    }

    protected V getMvpView() {
        return mMvpView;
    }
}

Activity中的处理

public abstract class BaseActivity extends AppCompatActivity{

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

    @Override
    protected void onDestroy() {
        super.onDestroy();
        detachView();
    }
    //需要子类初始化Presenter
    public abstract void initPresenter();
    //解除View以及RxJava,防止内存泄漏
    public abstract void detachView();
}
/**
 *Adapter的基类
 */

public abstract class BasicAdapter<T> extends BaseAdapter {
    private Context mContext;
    private List<T> mDatas;
    private int mItemLayoutId;
    public BasicAdapter(Context context,List<T> data,int itemLayoutId){
        mContext = context;
        mDatas = data;
        mItemLayoutId = itemLayoutId;
    }
    @Override
    public int getCount() {
        return mDatas.size();
    }

    @Override
    public T getItem(int position) {
        return mDatas.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        BasicViewHolder viewHolder = getViewHolder(position,convertView,parent);
        convert(viewHolder,getItem(position));
        return viewHolder.getConvertView();
    }
    //交给子类去处理具体的逻辑和显示
    protected abstract void convert(BasicViewHolder viewHolder, T item);

    private BasicViewHolder getViewHolder(int position,View convertView,ViewGroup parent){
        return BasicViewHolder.get(mContext,convertView,parent,mItemLayoutId,position);
    }
}

/**
 *  公共的ViewHolder
 */

public class BasicViewHolder {
    private View mConvertView;
    private int mPosition;
    private SparseArray<View> mViews;
    private Context mContext;

    private BasicViewHolder(Context context, ViewGroup parent, int layoutId, int position) {
        //填充布局
        mConvertView = LayoutInflater.from(context).inflate(layoutId, parent, false);
        mContext = context;
        mPosition = position;
        mViews = new SparseArray<>();
        mConvertView.setTag(this);
    }

    static BasicViewHolder get(Context context, View converView, ViewGroup parent, int layoutId, int position) {
        if (converView == null) {
            return new BasicViewHolder(context, parent, layoutId, position);
        } else {
            return (BasicViewHolder) converView.getTag();
        }
    }

    View getConvertView() {
        return mConvertView;
    }

    private <T extends View> T getView(int viewId){
        View view = mViews.get(viewId);
        if (view == null) {
            view = mConvertView.findViewById(viewId);
            mViews.put(viewId,view);
        }
        return (T) view;
    }
    public BasicViewHolder setText(int viewId,String text) {
        TextView textView = getView(viewId);
        textView.setText(text);
        return this;
    }

    public BasicViewHolder setImageResource(int viewId,int resId) {
        ImageView imageView = getView(viewId);
        imageView.setImageResource(resId);
        return this;
    }

    public BasicViewHolder setImageBitmap(int viewId, Bitmap bitmap){
        ImageView imageView = getView(viewId);
        imageView.setImageBitmap(bitmap);
        return this;
    }

    public BasicViewHolder setImageUri(int viewId, String uri) {
        ImageView imageView = getView(viewId);
        Picasso.with(mContext).load(uri).into(imageView);
        return this;
    }

    public int getPosition() {
        return mPosition;
    }
}
**
 *全局Application
 */

public class MovieApplication  extends Application {
    private static MovieApplication mInstance;
    @Override
    public void onCreate() {
        super.onCreate();
        //初始化Log类
        LogUtil.initLog(this);
        mInstance = this;
    }
    //方便在其他地方获取Application的实例
    public static MovieApplication getApplication() {
        return mInstance;
    }
}

/*
* Application中方法的执行顺序:
* 构造方法
* attachBaseContext
* onCreate
* */

上面就是项目的一些代码实例,完整的代码可以下载Demo查看
点此下载Demo源码

然后贴出最后的实现效果
这里写图片描述

接下来说一下项目中遇到的一些问题

打印Log
测试环境我们需要打印Log,方便测试,正式环境需要停止打log,如何判断当前的环境,下面说一种简单的方法。

/**
 * Log工具类
 */

public class LogUtil {
    private static boolean mIsDebug;
    public static void initLog(Context context){
    //Log初始化
        Logger.init("MvpDemo")
        .methodCount(0);
        mIsDebug = context.getApplicationInfo() != null &&
                (context.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) == ApplicationInfo.FLAG_DEBUGGABLE;
    }

    public static void v(String msg,Object... obj){
        if (mIsDebug) {
            Logger.v(msg,obj);
        }
    }
    public static void w(String msg,Object... obj){
        if (mIsDebug) {
            Logger.w(msg,obj);
        }
    }
    public static void e(String msg,Object... obj){
        if (mIsDebug) {
            Logger.e(msg,obj);
        }
    }
    public static void d(String msg,Object... obj){
        if (mIsDebug) {
            Logger.d(msg,obj);
        }
    }
}

我们判断的原理是根据ApplicationInfo中的一个标记位,具体可参考
#Android源码#ApplicationInfo中flags的设计

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值