简体   繁体   English

如何在我的样本中正确应用MVP模式

[英]How correctly apply MVP pattern in my sample

I decide to learn about MVP pattern and after look through some articles i want to try it with my current project. 我决定学习MVP模式,并在浏览了一些文章之后想在当前项目中尝试使用它。

I have choosen one activity and begin to think how i can decouple it according MVP rules. 我选择了一项活动,并开始考虑如何根据MVP规则将其解耦。 And eventually I don't know how to do it. 最终我不知道该怎么做。 It seems like a not complicated activity but I don't know 这似乎并不复杂,但我不知道

Could please someone adviced me with what I have to start? 可以请别人给我一些建议吗?

Which methods have to be in presenter, witch view have to be left in this current activity and whitch methods have to be in interface? 演示者必须使用哪种方法,当前活动中必须保留女巫视图,并且必须在界面中使用抽动方法?

Just advised me who i supposed to begin. 只是告诉我我应该开始谁。

This is my class 这是我的课

public final class ActivityUserDataScreen extends AppCompatActivity implements InterfaceActivityUserDataScreen{

private static String gender;
private static int inputHeight;
private static int inputWeight;
private TextInputLayout tilUserName;
private int backPressedQ = 0;
private String avatarName;

private static final String MEN = "men";
private static final String WOMEN = "men";

private Context context;
private PresenterActivityUserDataScreen presenter;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    Fabric.with(this, new Crashlytics());
    setContentView(R.layout.activity_user_data_screen);
    setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
    setSupportActionBar((Toolbar) findViewById(R.id.tool_bar));

    context = getApplicationContext();
    initNumberPicker();
    initVar();
    presenter = new PresenterActivityUserDataScreen(this);
}

private void initNumberPicker() {
    NumberPicker pickerHeight = (NumberPicker) findViewById(R.id.pickerHeight);
    UtilClass.setDividerColor(pickerHeight, UtilClass.getMyColor(context, R.color.ntz_color_yellow));
    pickerHeight.setOnValueChangedListener(changeListener);
    pickerHeight.setMaxValue(220);
    pickerHeight.setMinValue(130);
    pickerHeight.setValue(States.HEIGHT_DEFAULT);

    NumberPicker pickerWeight = (NumberPicker) findViewById(R.id.pickerWeight);
    UtilClass.setDividerColor(pickerWeight, UtilClass.getMyColor(context, R.color.ntz_color_yellow));
    pickerWeight.setOnValueChangedListener(changeListener);
    pickerWeight.setMaxValue(120);
    pickerWeight.setMinValue(35);
    pickerWeight.setValue(States.WEIGHT_DEFAULT);
}

private void initVar() {
    tilUserName = (TextInputLayout) findViewById(R.id.tilUserName);

    SwitchButton switchButton = (SwitchButton) findViewById(R.id.sb_custom);
    switchButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            if (isChecked){
                gender = WOMEN;
            }else {
                gender = MEN;
            }
        }
    });

    EditText etAvatarName = (EditText) findViewById(R.id.etAvatarName);
    etAvatarName.setText(getResources().getString(R.string.avatar));
}

private NumberPicker.OnValueChangeListener changeListener = new NumberPicker.OnValueChangeListener() {
    @Override
    public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
        switch (picker.getId()) {
            case R.id.pickerHeight:
                inputHeight = newVal;
                break;
            case R.id.pickerWeight:
                inputWeight = newVal;
                break;
        }
    }
};

@Override
public final void onBackPressed() {
    UtilClass.processClick(context);

    if (backPressedQ == 1) {
        backPressedQ = 0;
        super.onBackPressed();
        overridePendingTransition(R.anim.open_main, R.anim.close_next);

    } else {
        backPressedQ++;
        Toast.makeText(this, "Press again to exit", Toast.LENGTH_SHORT).show();
    }

    //Обнуление счётчика через 5 секунд
    final Handler handler = new Handler();
    handler.postDelayed(new Runnable() {
        @Override
        public void run() {
            backPressedQ = 0;
        }
    }, 5000);
}

public final void goNext(View view) {
    UtilClass.processClick(context);
    EditText editText = tilUserName.getEditText();
    Editable editable = null;
    if (editText != null) {
        editable = editText.getText();
    }
    if (editable != null) {
        avatarName = editable.toString();
    }
    if (!isValidAvatarName()) return;

    saveUserData();
    MetadataSaver saver = new MetadataSaver(context);
    saver.saveFirstUserInfo();
    saver.saveDeviceInfo();
    PreferencesHelper.savePref(context, States.STILL_NOT_FINISH, true);
    UtilClass.goToNextActivity(ActivityUserDataScreen.this, ActivityVideo.class);
}

private void saveUserData(){
    saveAvatarGender();
    saveAvatarHeight();
    saveAvatarWeight();
    saveAvatarName();
}

private void saveAvatarGender(){
    if (gender == null){
        gender = MEN;
    }
    PreferencesHelper.savePref(context, States.AVATAR_GENDER, gender);
}

private boolean isValidAvatarName() {
    if (UtilClass.isTextEmpty(avatarName)) {
        tilUserName.setErrorEnabled(true);
        tilUserName.setError(getResources().getString(R.string.fill_your_avatar_name));
        return false;
    }

    if (avatarName.contains(" ")) {
        avatarName = avatarName.replace(" ", "");
    }

    if (!UtilClass.isLatinAlphabet(avatarName)) {
        tilUserName.setErrorEnabled(true);
        tilUserName.setError(getResources().getString(R.string.avatar_name_in_english));
        return false;
    }

    if (!UtilClass.isNameFree(context, avatarName)) {
        tilUserName.setErrorEnabled(true);
        tilUserName.setError(getResources().getString(R.string.avatar_name_already_in_use));
        return false;
    }

    return true;
}

private void saveAvatarHeight() {
    int result;
    if (inputHeight == 0) {
        result = States.HEIGHT_DEFAULT;
    } else {
        result = inputHeight;
    }

    PreferencesHelper.savePref(context, States.AVATAR_HEIGHT, result);
}

private void saveAvatarWeight() {
    int result;
    if (inputWeight == 0) {
        result = States.WEIGHT_DEFAULT;
    } else {
        result = inputWeight;
    }
    PreferencesHelper.savePref(context, States.AVATAR_WEIGHT, result);
}

private void saveAvatarName() {
    PreferencesHelper.savePref(context, States.AVATAR_NAME, avatarName);
}

public final void switchManWoman(View view) {
    UtilClass.processClick(context);
}
}

Thanks in advance! 提前致谢!

The things to take into account are: 要考虑的事情是:

  • The view needs to be as dumb as possible. 视图需要尽可能的愚蠢。 Think of it as an executor of the commands given by the presenter, and reporter to the presenter of all the stuff that happened on the UI. 可以将其视为演示者给出的命令的执行者,并作为报告者将UI上发生的所有事情报告给演示者。 The interface should provide methods like "display this text", and / or calling presenter's methods like "the button was clicked". 界面应提供“显示此文本”之类的方法,和/或调用演示者的“单击按钮”之类的方法。

  • the presenter is the one in command. 主持人是主持人。 It drives your view behaviour and reacts to the inputs coming from the view itself. 它会驱动您的视图行为,并对来自视图本身的输入做出反应。 Ideally, it should abstract from anything Android related, in this way you can test the behaviour inside vanilla tests. 理想情况下,它应该从任何与Android相关的内容中抽象出来,这样您就可以测试普通测试中的行为。

Google has published a collection of samples to discuss and showcase different architectural tools and patterns for Android apps. Google已发布了一系列示例,以讨论和展示适用于Android应用的不同架构工具和模式。

To begin, very usefull to you to understand how this one works . 首先,对您了解这一工作原理非常有用。 And adapt to your sample. 并适应您的样品。

[...] This sample is the base for many of the variants. [...]此示例是许多变体的基础。 It showcases a simple implementation of the Model-View-Presenter pattern with no architectural frameworks. 它展示了没有架构框架的Model-View-Presenter模式的简单实现。 It uses manual dependency injection to provide a repository with local and remote data sources. 它使用手动依赖项注入为存储库提供本地和远程数据源。 Asynchronous tasks are handled with callbacks [...] 异步任务通过回调处理[...]

在此处输入图片说明

I highly recommend reading this article on medium: https://medium.com/@tinmegali/model-view-presenter-mvp-in-android-part-1-441bfd7998fe#.f4yiylrwa . 我强烈建议您在以下媒体上阅读本文: https//medium.com/@tinmegali/model-view-presenter-mvp-in-android-part-1-441bfd7998fe#.f4yiylrwa

In essence, all things related to the android SDK should be put in your "view" (and occasionally your model), which will usually be a fragment or activity. 本质上,所有与android SDK相关的事物都应放在您的“视图”(有时是模型)中,该视图通常是片段或活动。 Figuring out the difference between your model and presenter will be more up to you, however, you can think about your presenter as the thing that makes program logic decisions based on inputs to your application. 弄清模型与演示者之间的差异将完全由您决定,但是,您可以将演示者视为根据应用程序的输入来制定程序逻辑决策的事物。 Often, the mvp pattern is used in Android development to try to get around rotation and activity recreation issues so you may have luck using a static presenter for a small sample application. 通常,在Android开发中使用mvp模式来尝试解决轮换和活动娱乐问题,因此对于小型示例应用程序,使用静态演示者可能会很幸运。

Best of luck! 祝你好运!

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM