JavaRush /مدونة جافا /Random-AR /MVP في Android للصغار

MVP في Android للصغار

نشرت في المجموعة
عندما بدأت رحلتي كمطور لنظام Android، تسببت عبارة "هندسة تطبيقات الهاتف المحمول" في حيرة شديدة، ودفعني Google والمقالات عن حبري إلى مزيد من الاكتئاب - أنظر إلى الكتاب ولا أرى شيئًا. أعتقد أنك إذا كنت تقرأ هذا المقال، فقد سبق لك أن درست هذه الصورة أكثر من مرة وحاولت فهم ما يحدث: إن أفضل لاعب في Android للصغار - 1مشكلة فهم النهج المعماري في تطوير الهاتف المحمول، في رأيي، تكمن في تجريد الهندسة المعمارية نفسها. كل مطور لديه رؤيته الخاصة لكيفية تنفيذ هذا النمط أو ذاك بشكل صحيح. تم العثور على أمثلة أكثر أو أقل لائقة لتنفيذ MVP في قطاع الإنترنت الناطق باللغة الإنجليزية، وهو ليس مفاجئا. دعونا نلقي نظرة سريعة على ما هو وماذا وننتقل إلى مثال. النموذج - مستوى البيانات. لا أحب استخدام مصطلح "منطق الأعمال"، لذلك أسميه في تطبيقاتي المستودع وهو يتواصل مع قاعدة البيانات والشبكة. عرض - مستوى العرض. سيكون نشاطًا أو جزءًا أو عرضًا مخصصًا إذا كنت لا تحب الرقص بالدف والتفاعل مع دورة الحياة. اسمحوا لي أن أذكرك أنه في البداية تخضع جميع تطبيقات Android لبنية MVC ، حيث تكون وحدة التحكم عبارة عن نشاط أو جزء . المقدم عبارة عن طبقة بين العرض والنموذج. ينقل العرض الأحداث التي تحدث له، ويقوم المقدم بمعالجتها، إذا لزم الأمر، ويصل إلى النموذج ويعيد البيانات إلى العرض لعرضها. فيما يتعلق بنظام Android ومثال محدد، سأسلط الضوء على الجزء المهم - العقد. هذه هي الواجهة التي تصف جميع التفاعلات بين المكونات المذكورة أعلاه. تلخيص الجزء النظري:
  • عرض يعرف عن مقدم العرض؛
  • يعرف مقدم العرض عن العرض والنموذج (المستودع)؛
  • نموذج في حد ذاته؛
  • العقد يحكم التفاعلات بينهما.
في الواقع، المثال نفسه، لتبسيط التجربة، من خلال النقر على زر، سنقوم بتحميل صف من قاعدة البيانات وعرضه في TextView . على سبيل المثال، تحتوي قاعدة البيانات على قائمة بأفضل المطاعم في المدينة. لنبدأ بالعقد: لنقم بإنشاء واجهة MainContract:
public interface MainContract {
    interface View {
        void showText();
    }

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

    interface Repository {
        String loadMessage();
    }
}
في الوقت الحالي، نحن ببساطة نسلط الضوء على المكونات الثلاثة لتطبيقنا المستقبلي وما سيفعلونه. بعد ذلك سوف نقوم بوصف المستودع:
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 في إحدى الطرق ويمرر نفسه إلى منشئه.
  • عندما يتم إنشاء مقدم العرض، فإنه يتلقى عرضًا بشكل صريح ويقوم بإنشاء مثيل مستودع (بالمناسبة، يمكن جعله مفردًا)
  • عند الضغط على زر، يقرع العرض على مقدم العرض ويقول: "تم الضغط على الزر".
  • يتحول مقدم العرض إلى المستودع: "قم بتنزيل هذا الهراء من أجلي."
  • يقوم المستودع بتحميل "الأشياء" وتسليمها إلى المقدم.
  • يتحول مقدم العرض إلى العرض: "هذه هي البيانات، ارسمها"
هذا كل شيء يا شباب. ملحوظة: من المهم تحديد المسؤوليات بوضوح بين المكونات. على سبيل المثال، في أحد مشاريعي التدريبية، عند النقر فوق الزر، كان من الضروري تغيير البيانات في قاعدة البيانات. تم وصف النموذج بواسطة فئة POJO، وقمت بتمرير معلومات حول موقع العرض المسؤول عن المعلومات حول الكائن على الشاشة، وبحث مقدم العرض عن هذا الكائن في القائمة وأرسله ليتم كتابته في المستودع. هل يبدو كل شيء منطقيا؟ لكن معلمي أشار إلى ما يلي: يجب أن يقوم المستودع بالكتابة والقراءة فقط، ولا ينبغي له سحب المعلومات الضرورية من POJO وتحديد ما يحتاج إلى كتابته. ويجب على مقدم العرض أن يعطيه المعلومات التي يريد تسجيلها فقط وليس أكثر. لا يوجد إطار صارم لتنفيذ الهندسة المعمارية: قم بالتجربة والتجربة والبحث عما يناسبك شخصيًا. ولا تنسَ أن تُظهر لزملائك الكبار مراجعة التعليمات البرمجية =) المثال متاح على GitHub: https://github.com/admitrevskiy/MVP_Example
تعليقات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION