當我開始擔任Android 開發者的旅程時,「行動應用架構」這個詞讓我深感困惑,Google 和Habré 上的文章讓我陷入了更大的沮喪——我看著書,什麼也沒看到。我想如果你正在閱讀這篇文章,你已經不只一次地研究過這張圖,並試圖理解正在發生的事情: 在我看來,理解行動開發中的架構方法的問題在於架構本身的抽象性。每個開發人員對於如何正確實現這個或那個模式都有自己的願景。在互聯網的英語領域中或多或少都可以找到 MVP 實施的不錯例子,這並不奇怪。讓我們簡要地了解一下什麼是什麼,然後繼續看一個範例。 模型-資料等級。我不喜歡使用「業務邏輯」這個術語,所以在我的應用程式中我將其稱為儲存庫,它與資料庫和網路進行通訊。 視圖——顯示層級。如果你不喜歡手鼓跳舞以及與生命週期交互,那麼它將是Activity、Fragment或Custom View 。讓我提醒您,最初所有 Android 應用程式都從屬於MVC結構,其中控制器是Activity或Fragment。 Presenter是View和Model之間的一層。View 傳輸發生在它身上的事件,presenter 處理它們,如有必要,存取 Model 並將資料傳回 View 進行渲染。關於Android和一個具體的例子,我將重點放在重要的部分——合約。這是描述上述元件之間所有互動的介面。 總結理論部分:
- View 知道 Presenter;
- Presenter了解View和Model(Repository);
- 自行建模;
- 契約控制著它們之間的相互作用。
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()");
}
}
你還記得我寫過關於手鼓跳舞和生命週期的文章嗎?Presenter和View的生命週期一樣長,在開發複雜的用戶場景時,我建議你複製Presenter中的所有View回調並在適當的時刻調用它們,複製Activity/Fragment的生命週期,以便及時了解需要什麼使用當前掛在「中間層」中的資料來完成。 最後,查看:
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()");
}
}
這是怎麼回事?
- Activity,也稱為 View,
onCreate()
在方法中建立 Presenter 實例並將其傳遞給其建構函式。 - 當建立Presenter時,它明確接收一個View並建立一個Repository實例(順便說一下,可以將其做成Singleton)
- 當按下按鈕時,視圖會敲擊演示者並說:“按鈕已按下。”
- 演示者轉向存儲庫:“給我下載這個垃圾。”
- 儲存庫載入“內容”並將其傳遞給演示者。
- 演示者轉向視圖:“這是給你的數據,畫出來”
GO TO FULL VERSION