簡述MVC框架模式以及在你(Android)項目中的應用


  標題是阿里電話面試的問題,一直以為自己很清楚MVC模式,結果被問到時,居然沒法將MVC和Android中各個組件對應起來,所以,面試肯定掛了,不過面試也是學習的一種方式,可以知道大公司看中什么,以及自己還有哪些知識漏洞,例如這次面試就學到了很多東西。

  大家可以在看下面的內容之前,也想想能否把MVC及與Android各個組件的對應關系講清楚,看是否還有和我一樣對MVC一知半解的。

    如果寫的有問題的地方,歡迎討論。轉載請注明出處:http://www.cnblogs.com/John-Chen/p/4458823.html

 

  學習中讀了很多別人總結的文章,有幾篇不錯,推薦給大家:  

  前端之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的思想在實現,只是在設計和實現時,沒提升到框架模式,只是根據以前的經驗,以及一些基本的設計思想在做,所以被問到MVC模式時,也沒想到項目中有用到的地方。我覺得不管了不了解什么框架模式以及設計模式,最主要的是得想辦法做到解耦以及提升應用的穩定性。

 

  首先說下我現在認識的MVC與Android的各個組件的對應關系:

  View:自定義View或ViewGroup,負責將用戶的請求通知Controller,並根據model更新界面;

  Controller:Activity或者Fragment,接收用戶請求並更新model;

  Model:數據模型,負責數據處理相關的邏輯,封裝應用程序狀態,響應狀態查詢,通知View改變,對應Android中的datebase、SharePreference等。

 

  下面以我做的項目中的一個模塊來詳細介紹Android中的MVC框架模式:

  項目中有一個記錄軌跡的功能,記錄有幾種狀態:記錄、暫停、停止:

  

  接下來我把軌跡控制部分的邏輯提取出來,做了一個簡單地demo,

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

  

  View實現:

public class TrackCtrlView implements View.OnClickListener{
    private ImageView btnStartTrack, btnStopTrack, btnPauseTrack;
    private TrackCtrlViewListener listener;
    private TrackRecordInfo trackRecordInfo;

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); } /** * 將用戶請求通知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; } } 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); } }
   public void setTrackRecordInfo(@Nullable TrackRecordInfo trackRecordInfo) { this.trackRecordInfo = trackRecordInfo; refreshView(); } public interface TrackCtrlViewListener{ /** * 用戶點擊按鈕 */ public void trackStatusRequest(@Nullable TrackRecordStatus newStatus); } }

 

  Model實現:

public class TrackRecordInfo {
    private static final Gson gson = new Gson();

    /**
     * 應該是保存軌跡數據庫id,此demo中數據庫操作不實現,暫時trackId一直為0
     */
    public int trackId;

    public TrackRecordStatus status;

    public TrackRecordInfo(int trackId, TrackRecordStatus status) {
        this.trackId = trackId;
        this.status = status;
    }

    @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));
    }
}

 

  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);
    }

}

 

  最后總結下3者之間的關系:

  

    Android中,model通知view改變,可以通過消息總線實現。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM