JavaRush /Java блогы /Random-KK /Кішкентайлар үшін Android жүйесіндегі MVP
Алексей Дмитревский
Деңгей
Москва

Кішкентайлар үшін Android жүйесіндегі MVP

Топта жарияланған
Мен Android әзірлеушісі ретінде саяхатымды бастаған кезде, «Мобильдік қолданбалар архитектурасы» деген сөздер мені қатты таң қалдырды, Google және Хабре туралы мақалалар мені одан да қатты депрессияға ұшыратты - мен кітапқа қарап, ештеңе көрмеймін. Менің ойымша, егер сіз осы мақаланы оқып жатсаңыз, сіз бұл суретті бірнеше рет зерттеп, не болып жатқанын түсінуге тырыстыңыз: Кішкентайлар үшін Android жүйесіндегі MVP - 1Мобильді дамудағы архитектуралық тәсілді түсіну мәселесі, менің ойымша, сәулеттің абстрактілілігінде жатыр. Әрбір әзірлеушінің осы немесе басқа үлгіні қалай дұрыс жүзеге асыруға болатыны туралы өз көзқарасы бар. Интернеттің ағылшын тілді секторында MVP енгізудің азды-көпті лайықты мысалдары табылды, бұл таңқаларлық емес. Ненің не екенін қысқаша қарастырып, мысалға көшейік. Модель – деректер деңгейі. Мен «бизнес логикасы» терминін пайдаланғанды ​​ұнатпаймын, сондықтан менің қолданбаларымда мен оны Репозиторий деп атаймын және ол дерекқормен және желімен байланысады. Көрініс — дисплей деңгейі. Егер сіз бубен билегенді және өмірлік циклмен әрекеттесуді ұнатпасаңыз, бұл Activity , Fragment немесе Custom View болады . Естеріңізге сала кетейін, бастапқыда барлық Android қолданбалары MVC құрылымына бағынады , мұнда контроллер әрекет немесе фрагмент болып табылады . Баяндамашы – Көрініс пен Үлгі арасындағы қабат. Көрініс оған орын алған оқиғаларды жібереді, баяндамашы оларды өңдейді, қажет болса, Үлгіге қол жеткізеді және деректерді көрсету үшін Көрініске қайтарады. Android-ге және нақты мысалға қатысты мен маңызды бөлікті - Келісімшартты бөліп көрсетемін. Бұл жоғарыда аталған компоненттер арасындағы барлық өзара әрекеттесуді сипаттайтын интерфейс. Теориялық бөлімді қорытындылау үшін:
  • Көрініс Жүргізуші туралы біледі;
  • Баяндамашы Көрініс және Үлгі (Репозиторий) туралы біледі;
  • Өздігінен үлгі;
  • Шарт олардың арасындағы өзара әрекетті реттейді.
Іс жүзінде мысалдың өзі эксперименттің қарапайымдылығы үшін түймені басу арқылы дерекқордан жолды жүктеп, оны TextView ішінде көрсетеміз . Мысалы, мәліметтер базасында қаладағы ең жақсы мейрамханалардың тізімі бар. Келісімшарттан бастайық: интерфейсті жасайық MainContract:
public interface MainContract {
    interface View {
        void showText();
    }

    interface Presenter {
        void onButtonWasClicked();
        void onDestroy();
    }

    interface Repository {
        String loadMessage();
    }
}
Әзірге біз болашақ қолданбамыздың 3 құрамдас бөлігін және олардың не істейтінін бөлектеп жатырмыз. Әрі қарай біз репозиторийді сипаттаймыз:
public class MainRepository implements MainContract.Repository {

    private static final String TAG = "MainRepository";
    @Override
    public String loadMessage() {
        Log.d(TAG, "loadMessage()");
        /** Здесь обращаемся к БД or сети.
         * Я специально ничего не пишу, чтобы не загромождать пример
         * DBHelper'ами и прочими не относяшимеся к теме an objectми.
         * Поэтому я буду возвращать строку Сосисочная =)
         */
        return "Сосисочная у Лёхи»;
    }
}
Онымен бәрі түсінікті, тек деректерді жүктеу және түсіру. Келесі жүргізуші:
public class MainPresenter implements MainContract.Presenter {
    private static final String TAG = "MainPresenter";

    //Компоненты MVP applications
    private MainContract.View mView;
    private MainContract.Repository mRepository;

    //Сообщение
    private String message;


    //Обрати внимание на аргументы конструктора - мы передаем экземпляр View, а Repository просто создаём конструктором.
    public MainPresenter(MainContract.View mView) {
        this.mView = mView;
        this.mRepository = new MainRepository();
        Log.d(TAG, "Constructor");
    }

    //View сообщает, что кнопка была нажата
    @Override
    public void onButtonWasClicked() {
        message = mRepository.loadMessage();
        mView.showText(message);
        Log.d(TAG, "onButtonWasClicked()");
    }

    @Override
    public void onDestroy() {
        /**
         * Если бы мы работали например с RxJava, в этом классе стоило бы отписываться от подписок
         * Кроме того, при работе с другими методами асинхронного андроида,здесь мы боремся с утечкой контекста
         */

        Log.d(TAG, "onDestroy()");
    }
}
Дабылмен билеу және өмірлік цикл туралы жазғаным есіңізде ме? Баяндамашы өзінің Көрінісінің өмір сүретін уақытында өмір сүреді, күрделі пайдаланушы сценарийлерін жасағанда, мен сізге Презентациядағы барлық Көрініс кері шақыруларының көшірмесін жасауға және оларды уақытында түсіну үшін Әрекет/Фрагменттің өмірлік циклін қайталай отырып, тиісті сәттерде қоңырау шалуға кеңес беремін. қазіргі уақытта «аралық қабатта» ілулі тұрған деректермен орындалуы керек. Соңында, қараңыз:
public class MainActivity extends AppCompatActivity implements MainContract.View {

    private static final String TAG = "MainActivity";

    private MainContract.Presenter mPresenter;

    private Button mButton;

    private TextView myTv;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        //Создаём Presenter и в аргументе передаём ему this - эта Activity расширяет интерфейс MainContract.View
        mPresenter = new MainPresenter(this);

        myTv = (TextView) findViewById(R.id.text_view);
        mButton = (Button) findViewById(R.id.button);

        mButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mPresenter.onButtonWasClicked();
            }
        });
        Log.d(TAG, "onCreate()");
    }

    @Override
    public void showText(String message) {
        myTv.setText(message);
        Log.d(TAG, "showMessage()");
    }

    //Вызываем у Presenter метод onDestroy, чтобы избежать утечек контекста и прочих неприятностей.
    @Override
    public void onDestroy() {
        super.onDestroy();
        mPresenter.onDestroy();
        Log.d(TAG, "onDestroy()");
    }
}
Не болып жатыр?
  • Көрініс деп те белгілі әрекет onCreate()әдісте Presenter данасын жасайды және өзін оның конструкторына береді.
  • Баяндамашы жасалғанда, ол анық Көрініс алады және репозиторий данасын жасайды (айтпақшы, оны Singleton жасауға болады)
  • Түйме басылғанда, Көрініс баяндамашыны қағып: «Түйме басылды» дейді.
  • Жүргізуші репозиторийге бұрылады: «Маған мына сұмдықты жүктеп алыңыз».
  • Репозиторий «заттарды» жүктеп, Баяндамашыға жеткізеді.
  • Баяндамашы Көрініске бұрылады: «Міне, сіз үшін деректер, оны сызыңыз»
Міне, балалар. PS Құрамдас бөліктер арасындағы жауапкершілікті нақты бөлу маңызды. Мысалы, менің оқу жобаларымның бірінде түймені басқан кезде дерекқордағы деректерді өзгерту қажет болды. Модельді POJO класы сипаттады, мен экрандағы an object туралы ақпаратқа жауап беретін көріністің орны туралы ақпаратты бердім, Баяндамашы бұл нысанды тізімнен іздеп, оны Репозиторийге жазуға жіберді. Барлығы логикалық сияқты ма? Бірақ менің тәлімгерім мынаны атап өтті: Репозиторий ТЕК жазу және оқумен айналысуы керек, ол қажетті ақпаратты POJO-дан шығармауы және не жазу керектігін шешуі керек. Баяндамашы оған тек жазу үшін ақпаратты ғана беруі керек, басқа ештеңе жоқ. Архитектураны жүзеге асыру үшін қатаң негіз жоқ: эксперимент жасаңыз, көріңіз, өзіңізге ыңғайлы нәрсені іздеңіз. Аға жолдастарыңызға codeты қарап шығуды көрсетуді ұмытпаңыз =) Мысал GitHub сайтында қолжетімді: https://github.com/admitrevskiy/MVP_Example
Пікірлер
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION