在MVP大行其道的当下,很多的产品都在使用MVP作为主流的框架实现方式。一方面MVP实现的完全的解耦,另一方面MVP也可以在一些情况下共用接口。不过这里我给大家提供一种MVC的框架。这种框架的好处是,我们可以更加简洁的完成代码解耦,简单易行。在项目比较简单的时候我们可以使用这种方法。当然,这种方法在大型项目中表现也是一流的。
首先我先分析一下我们的类结构。
第一个自然是布局文件,这个这里就不再多提了。
第二个就是Activity或者Fragment了。这里我们提供了基类的写法。之前我在
Android框架入门,基类的写法(一)-------- BaseActivity
系类文章中已经提到过相关的写法,这里就是对这个基类的一种重新封装。
先上BaseActivity写法
/**
* Activity基类
* Created by WaterWood on 2018/5/9.
*/
public abstract class BaseActivity<T extends MvcBaseModel> extends AppCompatActivity {
protected T mModel;
//日志打印标志
protected String TAG;
protected Bundle savedInstanceState;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//在界面未初始化之前调用的初始化窗口
initWindows();
if (initArgs(getIntent().getExtras())) {
this.savedInstanceState = savedInstanceState;
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(getContentLayoutId());
TAG = getComponentName().getShortClassName();
initWidget();
mModel = getModelImp();
initData();
} else {
finish();
}
}
protected abstract T getModelImp();
/**
* 初始化窗口
*/
protected void initWindows() {
}
/**
* 初始化相关参数
*
* @param bundle 参数bundle
* @return 如果参数正确返回true, 错误返回false
*/
protected boolean initArgs(Bundle bundle) {
return true;
}
/**
* 得到当前界面的资源文件Id
*
* @return 资源文件Id
*/
protected abstract int getContentLayoutId();
/**
* 初始化控件
*/
protected void initWidget() {
}
/**
* 初始化数据
*/
protected void initData() {
}
@Override
public boolean onSupportNavigateUp() {
//点击当前界面导航返回时,finish当前界面
finish();
return super.onSupportNavigateUp();
}
@Override
public void onBackPressed() {
//得到当前Activity下的所有Fragment
List<Fragment> fragments = getSupportFragmentManager().getFragments();
//判断集合是否为空
if (fragments != null && fragments.size() > 0) {
for (Fragment fragment : fragments) {
//判断是否为我们能够处理的Fragment类型
if (fragment instanceof BaseFragment) {
//是否拦截了返回按钮
if (((BaseFragment) fragment).onBackPressed()) {
//如果有,直接return
return;
}
}
}
}
super.onBackPressed();
finish();
}
}
接着是BaseFragment
/**
* Fragment基类
* Created by WaterWood on 2018/5/9.
*/
public abstract class BaseFragment<T extends MvcBaseModel> extends Fragment {
protected T mModel;
protected View mRoot;
protected Activity activity;
//日志打印标志
protected String TAG;
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
//初始化参数
initArgs(getArguments());
this.activity = activity;
TAG = activity.getComponentName().getShortClassName();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (mRoot == null) {
int layId = getContentLayoutId();
//初始化当前的根布局,但是不在创建时就添加到container里面
View root = inflater.inflate(layId, container, false);
initWidget(root);
mModel = getModelImp();
mRoot = root;
} else {
if (mRoot.getParent() != null) {
//把当前root从其父控件中移除
((ViewGroup) mRoot.getParent()).removeView(mRoot);
}
}
return mRoot;
}
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
//当View创建完成后初始化数据
initData();
}
/**
* 得到当前界面的资源文件Id
*
* @return 资源文件Id
*/
protected abstract int getContentLayoutId();
/**
* 初始化控件
*/
protected void initWidget(View root) {
}
/**
* 初始化数据
*/
protected void initData() {
}
/**
* 初始化相关参数
*
* @param bundle 参数bundle
* @return 如果参数正确返回true, 错误返回false
*/
protected void initArgs(Bundle bundle) {
}
/**
* 返回键触发时调用
*
* @return 返回true代表我已处理返回逻辑,Activity不用自己finish。
* 返回false代表我没有处理逻辑,Activity自己走自己的逻辑
*/
public boolean onBackPressed() {
return false;
}
protected abstract T getModelImp();
}
其中的变化大家可以和之前的做一些比较,当然,直接拿来用也是可以的。
第三个,自然是我们的接口
public interface MvcBaseCallBack {
}
这个没什么基本上,不过之后如果有统一接口我们可以写在这里。
第四个是Model的基类
public class MvcBaseModel<T extends MvcBaseCallBack> {
protected T callback;
protected Context context;
public MvcBaseModel(Context context,T callback) {
this.context = context;
this.callback = callback;
}
}
Model基类构造函数要求传入上下文和Callback实现类。大家要注意传入的内容。
四个主要部分已经说明白了。终于是不报错了。不过大家可能还是不太明白怎么用。这里我给大家举个例子
public class DemoActivity extends BaseActivity<DemoModel> implements DemoCallback{
@Override
protected DemoModel getModelImp() {
return new DemoModel(this,this);
}
@Override
protected int getContentLayoutId() {
return R.layout.activity_main;
}
@Override
protected void initWidget() {
//初始化控件的操作
}
@Override
protected void initData() {
//网络请求等操作,要使用mModel必须在这里用
mModel.requestWeb();
}
@Override
public void success() {
}
}
public interface DemoCallback extends MvcBaseCallBack{
public void success();
}
public class DemoModel extends MvcBaseModel<DemoCallback>{
public DemoModel(Context context, DemoCallback callback) {
super(context, callback);
}
public void requestWeb(){
callback.success();
}
}
DemoCallback 中写的接口我不做过多说明,一般我们就是成功和失败。当然,如果页面请求了多个接口,可能这里就需要多对儿接口方法。每个成功和失败为一对儿。
DemoModel 中每个方法中会请求一个网络接口,接口返回成功用callback调用成功的接口方法,接口返回失败用callback调用失败的接口方法。对应的在Activity或Fragment中要实现接口的方法。
我们可以通过接口方法的参数将返回的结果从Model中传入Activity中。
这篇文章可能有些基础的同学比较容易看懂。不过你有任何问题都可以给我留言。我将给大家一一解答。