你的位置:首页 > 操作系统

[操作系统]简述MVC框架模式以及在你(Android)项目中得应用


  标题是阿里电话面试的问题,一直以为自己很清楚MVC模式,结果被问到时,这M、V、C这几者之间的关系都搞不清楚了,最主要是,没法将MVC和Android中各个组件对应起来,所以,面试肯定挂了,不过面试也是学习的一种方式,可以知道大公司看中什么,以及自己还有哪些知识漏洞,例如这次面试就学到了很多东西。

  大家也可以在看下面的内容之前,也想想能否把MVC及与Android各个组件的对应关系讲清楚,看是否还有和我一样对MVC一知半解的。

    如果写的有问题的地方,欢迎讨论。转载请注明出处:http://www.cnblogs.com/John-Chen/p/4458823.html

 

  学习MVC模式中读了很多别人总结的文章,有几篇不错,推荐给大家:  

  前端之Android入门(3):MVC模式:
  http://isux.tencent.com/learn-android-from-zero-session3.html
  http://isux.tencent.com/learn-android-from-zero-session4.html
  http://isux.tencent.com/learn-android-from-zero-session5-html.html

  The Activity Revisited:
  http://www.therealjoshua.com/2012/07/android-architecture-part-10-the-activity-revisited/

  谈谈UI架构设计的演化:
  http://www.cnblogs.com/winter-cn/p/4285171.html

  MVC,MVP 和 MVVM 的图示:
  http://www.ruanyifeng.com/blog/2015/02/mvcmvp_mvvm.html

  关于另一种框架模式MVP的实践:

  http://www.imooc.com/wenda/detail/216700

 

  搞清楚MVC以及与Android各个组件的对应关系之后,再看自己项目中的某些实现,其实很多地方已经是遵循MVC的思想在实现,只是在设计和实现时,没想到框架模式,只是根据以前的经验,以及一些基本的设计思想在做,所以被问到MVC模式时,也没想到项目中有用到的地方。我觉得不管你自己了不了解什么框架模式以及设计模式,最主要的是得想办法做到解耦以及提升应用的稳定性。

  下面以项目中得一个实现来介绍Android中的MVC框架模式:

  项目中有一个记录轨迹的功能,记录有几种状态:记录、暂停、停止:

  

  接下来我把轨迹控制部分的逻辑提取出来,简单介绍下这部分的MVC设计思想。

  demo源码地址:https://github.com/John-Chen/BlogSamples/tree/master/MVCDemo  

  

  View实现:

public class TrackCtrlView implements View.OnClickListener{  // ------------------------ Constants ------------------------  // ------------------------- Fields --------------------------  private ImageView btnStartTrack, btnStopTrack, btnPauseTrack;  private TrackCtrlViewListener listener;  private TrackRecordInfo trackRecordInfo;  // ----------------------- Constructors ----------------------  public TrackCtrlView(Activity activity, TrackCtrlViewListener listener){    this.listener = listener;    btnStartTrack = (ImageView) activity.findViewById(R.id.btnStartTrack);    btnStopTrack = (ImageView) activity.findViewById(R.id.btnStopTrack);    btnPauseTrack = (ImageView) activity.findViewById(R.id.btnPauseTrack);    btnStartTrack.setOnClickListener(this);    btnStopTrack.setOnClickListener(this);    btnPauseTrack.setOnClickListener(this);    btnPauseTrack.setOnClickListener(this);  }  // -------- Methods for/from SuperClass/Interfaces -----------  /**   * 将用户请求通知Controller   */  @Override  public void onClick(View v) {    switch(v.getId()){      case R.id.btnStartTrack:        if(listener != null){          listener.trackStatusRequest(TrackRecordStatus.Recording);        }        break;      case R.id.btnStopTrack:        if(listener != null){          listener.trackStatusRequest(TrackRecordStatus.Stoped);        }        break;      case R.id.btnPauseTrack:        if(listener != null){          if(trackRecordInfo.status == TrackRecordStatus.Paused){            listener.trackStatusRequest(TrackRecordStatus.Recording);          }else{            listener.trackStatusRequest(TrackRecordStatus.Paused);          }        }        break;      default:        break;    }  }  // --------------------- Methods public ----------------------  // --------------------- Methods private ---------------------  private void refreshView(){    TrackRecordStatus trackStatus = trackRecordInfo == null ?        TrackRecordStatus.Stoped : trackRecordInfo.status;    if (trackStatus == TrackRecordStatus.Recording) {      btnStartTrack.setVisibility(View.GONE);      btnPauseTrack.setVisibility(View.VISIBLE);      btnStopTrack.setVisibility(View.VISIBLE);      btnPauseTrack.setImageResource(R.drawable.btn_track_ctrl_pause);    } else if (trackStatus == TrackRecordStatus.Paused) {      btnStartTrack.setVisibility(View.GONE);      btnPauseTrack.setVisibility(View.VISIBLE);      btnStopTrack.setVisibility(View.VISIBLE);      btnPauseTrack.setImageResource(R.drawable.btn_track_ctrl_resume);    } else {      // TrackRecordStatus.Stoped      btnStartTrack.setVisibility(View.VISIBLE);      btnPauseTrack.setVisibility(View.GONE);      btnStopTrack.setVisibility(View.GONE);    }  }  // --------------------- Getter & Setter -----------------  public void setTrackRecordInfo(@Nullable TrackRecordInfo trackRecordInfo) {    this.trackRecordInfo = trackRecordInfo;    refreshView();  }  // --------------- Inner and Anonymous Classes ---------------  public interface TrackCtrlViewListener{    /**     * 用户点击按钮     */    public void trackStatusRequest(@Nullable TrackRecordStatus newStatus);  }  // --------------------- logical fragments -----------------}

 

  Model实现:

public class TrackRecordInfo {  // ------------------------ Constants ------------------------  // ------------------------- Fields --------------------------  private static final Gson gson = new Gson();  /**   * 应该是保存轨迹数据库id,此demo中数据库操作不实现,暂时trackId一直为0   */  public int trackId;  public TrackRecordStatus status;  // ----------------------- Constructors ----------------------  public TrackRecordInfo(int trackId, TrackRecordStatus status) {    this.trackId = trackId;    this.status = status;  }  // -------- Methods for/from SuperClass/Interfaces -----------  // --------------------- Methods public ----------------------  @NonNull  public static TrackRecordInfo loadTrackRecordInfo(@NonNull Context context){    String pref = SpUtil.getString(context, SpUtil.KEY_TRACK_RECORD_INFO, "");    if(!TextUtils.isEmpty(pref)){      return gson.fromJson(pref, TrackRecordInfo.class);    }    return null;  }  public static void changeTrackRecordInfo(@NonNull Context context, @Nullable TrackRecordInfo info){    SpUtil.saveString(context,        SpUtil.KEY_TRACK_RECORD_INFO,        info == null ? "" : gson.toJson(info));    //model通过消息总线,通知View刷新    EventBus.getDefault().post(new EventTrackRecordInfoChanged(info));  }  // --------------------- Methods private ---------------------  // --------------------- Getter & Setter -----------------  // --------------- Inner and Anonymous Classes ---------------  // --------------------- logical fragments -----------------}

 

  Controller实现:

public class MainActivity extends ActionBarActivity implements TrackCtrlView.TrackCtrlViewListener{  private TrackCtrlView trackCtrlView;  private TrackRecordInfo trackRecordInfo;  @Override  protected void onCreate(Bundle savedInstanceState) {    super.onCreate(savedInstanceState);    setContentView(R.layout.activity_main);    trackCtrlView = new TrackCtrlView(this, this);    EventBus.getDefault().register(this);    trackRecordInfo = TrackRecordInfo.loadTrackRecordInfo(this);    trackCtrlView.setTrackRecordInfo(trackRecordInfo);  }  @Override  protected void onDestroy() {    super.onDestroy();    EventBus.getDefault().unregister(this);  }  @Override  public void trackStatusRequest(@Nullable TrackRecordStatus newStatus) {    if(newStatus == TrackRecordStatus.Recording){      int trackId = 0; //在数据库创建一条轨迹,并获取到数据库id      trackRecordInfo = new TrackRecordInfo(trackId, TrackRecordStatus.Recording);    }else if (newStatus == TrackRecordStatus.Paused) {      if(trackRecordInfo != null){        trackRecordInfo.status = newStatus;      }    } else {      trackRecordInfo = null;    }    TrackRecordInfo.changeTrackRecordInfo(this, trackRecordInfo);  }  public void onEventMainThread(EventTrackRecordInfoChanged event){    trackRecordInfo = event.info;    trackCtrlView.setTrackRecordInfo(trackRecordInfo);  }}

 

比较晚了,明天下班再继续整理...