เมื่อฉันเริ่มต้นการเดินทางในฐานะนักพัฒนา Android คำว่า "สถาปัตยกรรมแอปพลิเคชันมือถือ" ทำให้ฉันสับสนอย่างมาก Google และบทความเกี่ยวกับHabré ทำให้ฉันซึมเศร้ามากยิ่งขึ้น - ฉันดูหนังสือแล้วไม่เห็นอะไรเลย ฉันคิดว่าหากคุณอ่านบทความนี้แสดงว่าคุณได้ศึกษารูปภาพนี้มากกว่าหนึ่งครั้งแล้วและพยายามที่จะเข้าใจว่าเกิดอะไรขึ้น:
ในความคิดของฉันปัญหาในการทำความเข้าใจแนวทางสถาปัตยกรรมในการพัฒนามือถือนั้นอยู่ที่ความเป็นนามธรรมของสถาปัตยกรรมนั่นเอง นักพัฒนาแต่ละคนมีวิสัยทัศน์ของตนเองเกี่ยวกับวิธีการใช้รูปแบบนี้หรือรูปแบบนั้นอย่างถูกต้อง ตัวอย่างการใช้งาน MVP ที่ดีไม่มากก็น้อยพบได้ในภาคอินเทอร์เน็ตที่พูดภาษาอังกฤษ ซึ่งไม่น่าแปลกใจเลย เรามาดูกันสั้นๆ ว่าอะไรคืออะไรและมาดูตัวอย่างกัน รุ่น - ระดับข้อมูล ฉันไม่ชอบใช้คำว่า "ตรรกะทางธุรกิจ" ดังนั้นในแอปพลิเคชันของฉัน ฉันจึงเรียกมันว่าRepositoryและมันจะสื่อสารกับฐานข้อมูลและเครือข่าย มุมมอง — ระดับการแสดงผล มันจะเป็นกิจกรรม , ส่วนย่อยหรือมุมมองแบบกำหนดเองหากคุณไม่ชอบการเต้นรำกับแทมบูรีนและมีปฏิสัมพันธ์กับวงจรชีวิต ฉันขอเตือนคุณว่าในตอนแรกแอปพลิเค ชัน Android ทั้งหมดอยู่ภายใต้ โครงสร้าง MVCโดยที่ตัวควบคุมคือกิจกรรมหรือแฟรกเมนต์ ผู้นำเสนอเป็นเลเยอร์ระหว่าง View และ Model View จะส่งเหตุการณ์ที่เกิดขึ้น ผู้นำเสนอจะประมวลผลเหตุการณ์เหล่านั้น หากจำเป็น เข้าถึงโมเดลและส่งคืนข้อมูลไปยัง View เพื่อเรนเดอร์ ในส่วนที่เกี่ยวข้องกับ Android และตัวอย่างเฉพาะ ฉันจะเน้นส่วนสำคัญ - สัญญา นี่คืออินเทอร์เฟซที่อธิบายการโต้ตอบทั้งหมดระหว่างส่วนประกอบข้างต้น เพื่อสรุปส่วนทางทฤษฎี:
- ดูรู้เกี่ยวกับผู้นำเสนอ;
- ผู้นำเสนอรู้เกี่ยวกับ View และ Model (Repository)
- โมเดลด้วยตัวเอง
- สัญญาควบคุมการโต้ตอบระหว่างกัน
MainContract
:
public interface MainContract {
interface View {
void showText();
}
interface Presenter {
void onButtonWasClicked();
void onDestroy();
}
interface Repository {
String loadMessage();
}
}
สำหรับตอนนี้ เราเพียงแต่เน้นองค์ประกอบ 3 ประการของแอปพลิเคชันในอนาคตของเราและสิ่งที่พวกเขาจะทำ ต่อไปเราจะอธิบาย Repository:
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 ยังคงอยู่ เมื่อพัฒนาสถานการณ์ผู้ใช้ที่ซับซ้อน ฉันขอแนะนำให้คุณทำซ้ำการเรียกกลับ View ทั้งหมดใน Presenter และโทรหาพวกเขาในช่วงเวลาที่เหมาะสม โดยทำซ้ำวงจรการใช้งานของกิจกรรม/แฟรกเมนต์ เพื่อให้เข้าใจในเวลาที่เหมาะสม จำเป็นต้องดำเนินการกับข้อมูลที่ค้างอยู่ใน "interlayer" ในปัจจุบัน และสุดท้าย ดู:
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()
จะสร้างอินสแตนซ์ของผู้นำเสนอในวิธีการและส่งผ่านตัวเองไปยังตัวสร้าง - เมื่อผู้นำเสนอถูกสร้างขึ้น มันจะได้รับมุมมองอย่างชัดเจนและสร้างอินสแตนซ์พื้นที่เก็บข้อมูล (โดยวิธีการนั้น สามารถสร้างเป็นซิงเกิลตันได้)
- เมื่อกดปุ่ม View จะเคาะผู้นำเสนอแล้วพูดว่า: “กดปุ่มแล้ว”
- ผู้นำเสนอหันไปที่ Repository: “ดาวน์โหลดเรื่องไร้สาระนี้ให้ฉันหน่อย”
- พื้นที่เก็บข้อมูลจะโหลดและส่ง "เนื้อหา" ให้กับผู้นำเสนอ
- ผู้นำเสนอหันไปดู: “นี่คือข้อมูลสำหรับคุณ วาดมัน”
GO TO FULL VERSION