簡述MVC架構模式以及在你(Android)項目中得應用,mvcandroid
標題是阿里電話面試的問題,一直以為自己很清楚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); }}
比較晚了,明天下班再繼續整理...