brief introduction
MVC is a design pattern, that is, a method and idea to solve problems, which was put forward in the 1980s, and has a long history. The significance of MVC is to guide developers to decouple data from presentation and improve the reusability of code, especially part of model code.
MVC mode means that software can be divided into three parts.
View: User interface.
Controller: Business logic
Model: Data preservation
View sends instructions to Controller
When Controller completes the business logic, it asks the Model to change state
Model sends new data to View and users get feedback
All communications are one-way.
The top layer is the "View" layer, which is directly oriented to the end user. It is the user's operating interface and the shell of the program.
The bottom layer is the core "Model", which is the data or information that the program needs to operate on.
The middle layer is the "Controller", which is responsible for selecting the data in the "Data Layer" according to the user's instructions input from the "View Layer", and then performing corresponding operations to produce the final results.
These three layers are closely linked, but they are independent of each other. The internal changes of each layer do not affect the other layers. Each layer provides an Interface for the upper layer to call. In this way, the software can be modularized, modifying the appearance or changing the data without modifying other layers, which greatly facilitates maintenance and upgrading.
Give an example
Take the calculator widget of Windows as an example to explain the MVC mode, although it is not necessarily written in this mode.
In this calculator program, the external buttons and the top display bar are "View Layer", "Data Layer" and "Control Layer" are the internal operation steps of adding, subtracting, multiplying and dividing. Each layer performs different functions, and the structure of the whole program is very clear.
If we expand our imagination, we will find that many programs are essentially in this mode: providing a set of triggers (buttons in this case) to the outside world, then performing some internal operations, and finally returning the results. Therefore, the application of MVC mode is very extensive.
Take the household microwave oven as an example, it can also be understood as a three-layer structure. In the simplest case, the microwave oven operates on two turntables, one to control temperature and the other to control time. The two turntables are "view" and the microwave generator inside them is "Model", where "data" needs to be understood as "core function". The control layer is used to convert the information input by the user through the turntable into the operation of the microwave generator.
If each layer is independent, replacing a trendy shell outside the microwave oven or replacing a more powerful microwave generator inside can be achieved without changing other layers. This is the advantage of MVC mode.
View: Customize View or ViewGroup to notify Controller of the user's request and update the interface according to the model.
Controller: Activity or Fragment, which receives user requests and updates the model;
Model: Data model, responsible for data processing related logic, encapsulating application status, responding to status queries, notifying View changes, corresponding to Android datebase, SharePreference, etc.
Advantages of MVC:
(1) Low coupling. Coupling is the degree of correlation between module codes. Using MVC framework, the View (View) layer and Model (Model) layer can be well separated, which achieves the purpose of decoupling, so the coupling is low and the interaction between module codes is reduced.
(2) Good scalability. Because of the low coupling, adding requirements, expanding code can reduce the code before modification and reduce the occurrence of bug s.
(3) The responsibilities of modules are clearly defined. Mainly divided into three layers M,V,C module, which is conducive to the maintenance of code.
Code Demo
Take the login interface as an example
Writing V
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" android:id="@+id/activity_main"
android:layout_width="match_parent" android:layout_height="match_parent"
tools:context="com.itheima.a001mvclogin.MainActivity">
<LinearLayout
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_centerInParent="true"
android:layout_height="wrap_content">
<EditText
android:layout_width="match_parent"
android:maxLines="1"
android:hint="Input account"
android:id="@+id/account_et"
android:layout_height="wrap_content" />
<EditText
android:layout_width="match_parent"
android:maxLines="1"
android:hint="Input password"
android:id="@+id/pwd_et"
android:layout_height="wrap_content" />
<Button
android:layout_width="match_parent"
android:onClick="login"
android:text="Sign in"
android:layout_height="wrap_content" />
<ProgressBar
android:layout_width="wrap_content"
android:id="@+id/pbar"
android:visibility="invisible"
android:layout_gravity="center_horizontal"
android:layout_height="wrap_content" />
</LinearLayout>
</RelativeLayout>
Writing M
http or database
public class User {
public String pwd;
public String account;
public User(String account, String pwd) {
this.account = account;
this.pwd = pwd;
}
}
Writing C
public class MainActivity extends AppCompatActivity {
private EditText accountEt;
private EditText pwdEt;
private ProgressBar pBar;
@Override
protected void onCreate(Bundle savedInstanceState{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Writing login
//1. Writing V in android is the layout inside the layout.
accountEt = (EditText) findViewById(R.id.account_et);
pwdEt = (EditText) findViewById(R.id.pwd_et);
pBar = (ProgressBar) findViewById(R.id.pbar);
//2. Write M to submit the account password obtained on the page to the server and return the verification results.
//3. Writing C Event Thread Judgment
}
public void login(View view) {
//3.1. Get page values
String inputAccount = accountEt.getText().toString();
String inputPwd = pwdEt.getText().toString();
//3.2. Logical judgment
if (!TextUtils.isEmpty(inputAccount) && !TextUtils.isEmpty(inputPwd)) {
//3.3. Prompt waiting
pBar.setVisibility(View.VISIBLE);
//3.4. Data submission
final User user = new User(inputAccount, inputPwd);
//Send out
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
//3.5. Get the result of the request
int code = new Random().nextInt(2);
//3.6. Close waiting
pBar.setVisibility(View.INVISIBLE);
if (code == 0)//The account password is correct
{
Toast.makeText(MainActivity.this, "Login successfully,Welcome" + user.account, Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(MainActivity.this, "Account Password Error", Toast.LENGTH_SHORT).show();
}
}
}, 3000);
} else {
Toast.makeText(this, "Account password cannot be empty", Toast.LENGTH_SHORT).show();
}
}
}
Code Demo2
Refer to other people's code Click to see
View implementation:
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);
}
/**
* Notify Controller of user requests
*/
@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{
/**
* The user clicks the button
*/
public void trackStatusRequest(@Nullable TrackRecordStatus newStatus);
}
}
Model implementation:
public class TrackRecordInfo {
private static final Gson gson = new Gson();
/**
* The track database id should be saved. The database operation is not implemented in this demo. Temporary trackId is always 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 notifies View refresh via message bus
EventBus.getDefault().post(new EventTrackRecordInfoChanged(info));
}
}
Controller implementation:
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; //Create a trajectory in the database and get the database 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);
}
}