JavaRush /จาวาบล็อก /Random-TH /MVP ใน Android สำหรับเจ้าตัวน้อย
Алексей Дмитревский
ระดับ
Москва

MVP ใน Android สำหรับเจ้าตัวน้อย

เผยแพร่ในกลุ่ม
เมื่อฉันเริ่มต้นการเดินทางในฐานะนักพัฒนา Android คำว่า "สถาปัตยกรรมแอปพลิเคชันมือถือ" ทำให้ฉันสับสนอย่างมาก Google และบทความเกี่ยวกับHabré ทำให้ฉันซึมเศร้ามากยิ่งขึ้น - ฉันดูหนังสือแล้วไม่เห็นอะไรเลย ฉันคิดว่าหากคุณอ่านบทความนี้แสดงว่าคุณได้ศึกษารูปภาพนี้มากกว่าหนึ่งครั้งแล้วและพยายามที่จะเข้าใจว่าเกิดอะไรขึ้น: MVP ใน Android สำหรับลูกน้อย - 1ในความคิดของฉันปัญหาในการทำความเข้าใจแนวทางสถาปัตยกรรมในการพัฒนามือถือนั้นอยู่ที่ความเป็นนามธรรมของสถาปัตยกรรมนั่นเอง นักพัฒนาแต่ละคนมีวิสัยทัศน์ของตนเองเกี่ยวกับวิธีการใช้รูปแบบนี้หรือรูปแบบนั้นอย่างถูกต้อง ตัวอย่างการใช้งาน MVP ที่ดีไม่มากก็น้อยพบได้ในภาคอินเทอร์เน็ตที่พูดภาษาอังกฤษ ซึ่งไม่น่าแปลกใจเลย เรามาดูกันสั้นๆ ว่าอะไรคืออะไรและมาดูตัวอย่างกัน รุ่น - ระดับข้อมูล ฉันไม่ชอบใช้คำว่า "ตรรกะทางธุรกิจ" ดังนั้นในแอปพลิเคชันของฉัน ฉันจึงเรียกมันว่าRepositoryและมันจะสื่อสารกับฐานข้อมูลและเครือข่าย มุมมอง — ระดับการแสดงผล มันจะเป็นกิจกรรม , ส่วนย่อยหรือมุมมองแบบกำหนดเองหากคุณไม่ชอบการเต้นรำกับแทมบูรีนและมีปฏิสัมพันธ์กับวงจรชีวิต ฉันขอเตือนคุณว่าในตอนแรกแอปพลิเค ชัน Android ทั้งหมดอยู่ภายใต้ โครงสร้าง MVCโดยที่ตัวควบคุมคือกิจกรรมหรือแฟรกเมนต์ ผู้นำเสนอเป็นเลเยอร์ระหว่าง View และ Model View จะส่งเหตุการณ์ที่เกิดขึ้น ผู้นำเสนอจะประมวลผลเหตุการณ์เหล่านั้น หากจำเป็น เข้าถึงโมเดลและส่งคืนข้อมูลไปยัง View เพื่อเรนเดอร์ ในส่วนที่เกี่ยวข้องกับ Android และตัวอย่างเฉพาะ ฉันจะเน้นส่วนสำคัญ - สัญญา นี่คืออินเทอร์เฟซที่อธิบายการโต้ตอบทั้งหมดระหว่างส่วนประกอบข้างต้น เพื่อสรุปส่วนทางทฤษฎี:
  • ดูรู้เกี่ยวกับผู้นำเสนอ;
  • ผู้นำเสนอรู้เกี่ยวกับ View และ Model (Repository)
  • โมเดลด้วยตัวเอง
  • สัญญาควบคุมการโต้ตอบระหว่างกัน
จริงๆ แล้ว ตัวอย่างนั้นเอง เพื่อความง่ายของการทดสอบ โดยการคลิกที่ปุ่ม เราจะโหลดแถวจากฐานข้อมูลและแสดงในTextView ตัวอย่างเช่น ฐานข้อมูลประกอบด้วยรายชื่อร้านอาหารที่ดีที่สุดในเมือง เริ่มต้นด้วยสัญญา: มาสร้างอินเทอร์เฟซกันเถอะ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: “ดาวน์โหลดเรื่องไร้สาระนี้ให้ฉันหน่อย”
  • พื้นที่เก็บข้อมูลจะโหลดและส่ง "เนื้อหา" ให้กับผู้นำเสนอ
  • ผู้นำเสนอหันไปดู: “นี่คือข้อมูลสำหรับคุณ วาดมัน”
แค่นั้นแหละครับเพื่อนๆ ป.ล. การแบ่งแยกความรับผิดชอบระหว่างองค์ประกอบต่างๆ อย่างชัดเจนเป็นสิ่งสำคัญ ตัวอย่างเช่น ในโปรเจ็กต์การฝึกอบรมรายการหนึ่งของฉัน เมื่อคลิกปุ่ม จำเป็นต้องเปลี่ยนข้อมูลในฐานข้อมูล แบบจำลองนี้อธิบายโดยคลาส POJO ฉันส่งข้อมูลเกี่ยวกับตำแหน่งของมุมมองซึ่งรับผิดชอบข้อมูลเกี่ยวกับวัตถุบนหน้าจอ ผู้นำเสนอค้นหาวัตถุนี้ในรายการและส่งไปเขียนลงใน Repository ทุกอย่างดูสมเหตุสมผลไหม? แต่ที่ปรึกษาของฉันชี้ให้เห็นสิ่งต่อไปนี้: Repository ควรเขียนและอ่านเท่านั้น ไม่ควรดึงข้อมูลที่จำเป็นออกจาก POJO และตัดสินใจว่าจะต้องเขียนอะไร ผู้นำเสนอจะต้องให้ข้อมูลที่จะบันทึกเท่านั้นและไม่มีอะไรเพิ่มเติม ไม่มีกรอบการทำงานที่เข้มงวดสำหรับการนำสถาปัตยกรรมไปใช้: ทดลอง พยายาม ค้นหาสิ่งที่สะดวกสำหรับคุณเป็นการส่วนตัว และอย่าลืมแสดงให้สหายรุ่นพี่ของคุณดูเกี่ยวกับ Code Review =) ตัวอย่างมีอยู่ใน GitHub: https://github.com/admitrevskiy/MVP_Example
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION