Мен Android иштеп чыгуучусу катары саякатымды баштаганда, "Мобилдик тиркемелердин архитектурасы" деген сөздөр мени катуу таң калтырды, Google жана Хабредеги макалалар мени ого бетер депрессияга алып келди - мен китепти карасам, эч нерсе көргөн жокмун. Менимче, эгер сиз бул макаланы окуп жатсаңыз, анда сиз бул сүрөттү бир нече жолу изилдеп, эмне болуп жатканын түшүнүүгө аракет кылгансыз: Мобилдик өнүгүүдө архитектуралык мамилени түшүнүү маселеси, менин оюмча, архитектуранын абстракттуулугунда. Ар бир иштеп чыгуучунун тигил же бул үлгүнү кантип туура ишке ашыруу боюнча өзүнүн көз карашы бар. MVP ишке ашыруунун аздыр-көптүр татыктуу мисалдары Интернеттин англис тилдүү секторунда табылган, бул таң калыштуу эмес. Келгиле, эмне экенин кыскача карап көрөлү жана бир мисалга өтөбүз. Модель - маалымат деңгээли. Мен "бизнес логикасы" деген терминди колдонгонду жактырбайм, андыктан менин тиркемелеримде мен аны Репозиторий деп атайм жана ал маалымат базасы жана тармак менен байланышат. Көрүү — дисплей деңгээли. Бул Activity , Fragment же Custom View болот , эгерде сиз дап менен бийлегенди жана жашоо цикли менен өз ара аракеттенүүнү жактырбасаңыз. Эске сала кетейин, алгач бардык Android тиркемелери MVC түзүмүнө баш ийген , мында Controller Activity же Fragment болуп саналат . Алып баруучу - Көрүнүш менен Моделдин ортосундагы катмар. Көрүнүш өзүнө келип түшкөн окуяларды өткөрүп берет, алып баруучу аларды иштетет, зарыл болсо, Моделге кире алат жана көрсөтүү үчүн Көрүнүшкө маалыматтарды кайтарат. Android жана конкреттүү мисал менен байланыштуу, мен маанилүү бөлүгүн баса белгилей кетүү - Келишим. Бул жогоруда аталган компоненттердин ортосундагы бардык өз ара аракеттенүүнү сүрөттөгөн интерфейс. Теориялык бөлүгүн жыйынтыктоо үчүн:
- Көрүү Алып баруучу жөнүндө билет;
- Алып баруучу Көрүү жана Модель (Репозиторий) жөнүндө билет;
- өзүнчө модели;
- Келишим алардын ортосундагы өз ара мамилелерди жөнгө салат.
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()");
}
}
Мен дап менен бийлөө жана жашоо цикли жөнүндө жазганым эсиңдеби? Алып баруучу өзүнүн Көрүнүшүнө жараша жашайт, татаал колдонуучу сценарийлерин иштеп чыгууда, мен сизге Алып баруучудагы бардык View кайра чалууларды кайталоону жана аларды өз убагында түшүнүү үчүн Активдүүлүк/Фрагменттин жашоо циклин кайталап, тийиштүү учурларда чалууну сунуштайм. Учурда “аралык катмарда” orнип турган маалыматтар менен аткарылышы керек. Акыр-аягы, көрүү:
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()
методдо Презентациянын инстанциясын түзүп, анын конструкторуна өтөт. - Алып баруучу түзүлгөндө, ал ачык түрдө Көрүнүштү кабыл алат жана Репозиторийдин инстанциясын түзөт (айтмакчы, аны Singleton кылса болот)
- Бир баскыч басылганда, Көрүнүш алып баруучуну тыкылдатып: "Баскылды" дейт.
- Алып баруучу Репозиторийге кайрылат: "Мага бул келесоону жүктөп алыңыз."
- Репозиторий "заттарды" жүктөйт жана алып баруучуга жеткирет.
- Алып баруучу Көрүнүшкө кайрылат: "Мына маалымат сиз үчүн, аны тартыңыз"
GO TO FULL VERSION