JavaRush /وبلاگ جاوا /Random-FA /MVP در اندروید برای کوچکترها

MVP در اندروید برای کوچکترها

در گروه منتشر شد
وقتی سفرم را به عنوان یک توسعه‌دهنده اندروید شروع کردم، کلمات «معماری برنامه‌های موبایل» باعث گیجی عمیق من شد، گوگل و مقالاتی در Habré من را به افسردگی شدیدتری سوق دادند - به کتاب نگاه می‌کنم و چیزی نمی‌بینم. فکر می‌کنم اگر در حال خواندن این مقاله هستید، قبلاً بیش از یک بار این تصویر را مطالعه کرده‌اید و سعی کرده‌اید بفهمید چه اتفاقی می‌افتد: MVP در اندروید برای کوچولوها - 1به نظر من مشکل درک رویکرد معماری در توسعه تلفن همراه در انتزاعی بودن خود معماری نهفته است. هر توسعه دهنده دیدگاه خود را در مورد نحوه اجرای صحیح این یا آن الگو دارد. نمونه های کم و بیش مناسبی از پیاده سازی MVP در بخش انگلیسی زبان اینترنت یافت شد که جای تعجب نیست. بیایید به طور خلاصه به چیستی چیست نگاه کنیم و به یک مثال برویم. مدل - سطح داده. من دوست ندارم از اصطلاح "منطق تجاری" استفاده کنم، بنابراین در برنامه هایم آن را مخزن می نامم و با پایگاه داده و شبکه ارتباط برقرار می کند. نمایش - سطح نمایش. اگر رقصیدن با تنبور و تعامل با چرخه زندگی را دوست ندارید، فعالیت ، قطعه یا نمای سفارشی خواهد بود . اجازه دهید به شما یادآوری کنم که در ابتدا همه برنامه های اندرویدی تابع ساختار MVC هستند که در آن Controller یک Activity یا Fragment است . Presenter یک لایه بین View و Model است. View رویدادهایی را که برای آن اتفاق می افتد منتقل می کند، ارائه دهنده آنها را پردازش می کند، در صورت لزوم به Model دسترسی پیدا می کند و داده ها را برای رندر به View برمی گرداند. در رابطه با اندروید و یک مثال خاص، قسمت مهم - قرارداد را برجسته می کنم. این رابطی است که تمام تعاملات بین اجزای فوق را توصیف می کند. به طور خلاصه بخش نظری:
  • مشاهده درباره ارائه کننده می داند.
  • ارائه دهنده در مورد View و Model (Repository) می داند.
  • مدل به خودی خود؛
  • قرارداد بر تعاملات بین آنها حاکم است.
در واقع، خود مثال، برای سادگی آزمایش، با کلیک بر روی یک دکمه، یک ردیف از پایگاه داده بارگیری می کنیم و آن را در TextView نمایش می دهیم . به عنوان مثال، پایگاه داده حاوی لیستی از بهترین رستوران های شهر است. بیایید با قرارداد شروع کنیم: بیایید یک رابط ایجاد کنیم 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 آن زنده است، در هنگام توسعه سناریوهای پیچیده کاربر، به شما توصیه می‌کنم که همه تماس‌های 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 را در یک متد ایجاد می کند و خود را به سازنده آن منتقل می کند.
  • هنگامی که یک ارائه کننده ایجاد می شود، به صراحت یک View دریافت می کند و یک نمونه مخزن ایجاد می کند (به هر حال، می توان آن را یک Singleton ساخت)
  • وقتی دکمه ای فشار داده می شود، View به ارائه کننده ضربه می زند و می گوید: "دکمه فشرده شد."
  • ارائه دهنده به سمت مخزن می رود: "این مزخرف را برای من دانلود کنید."
  • Repository "موارد" را بارگیری می کند و به ارائه کننده تحویل می دهد.
  • ارائه‌دهنده به View روی می‌آورد: «این‌ها داده‌ها برای شما هستند، آن‌ها را بکشید»
همین، بچه ها. PS مهم است که به وضوح مسئولیت ها بین اجزا مشخص شود. به عنوان مثال، در یکی از پروژه های آموزشی من، هنگام کلیک بر روی یک دکمه، نیاز به تغییر داده ها در پایگاه داده بود. مدل توسط یک کلاس POJO توضیح داده شد، من اطلاعاتی را در مورد مکان نمای که مسئول اطلاعات مربوط به شی روی صفحه است، ارسال کردم، Presenter این شی را در لیست جستجو کرد و آن را فرستاد تا به مخزن نوشته شود. آیا همه چیز منطقی به نظر می رسد؟ اما مربی من به موارد زیر اشاره کرد: مخزن فقط باید نوشتن و خواندن انجام دهد، نباید اطلاعات لازم را از POJO بیرون بکشد و تصمیم بگیرد که چه چیزی باید بنویسد. ارائه دهنده باید فقط اطلاعاتی را برای ضبط به او بدهد و نه بیشتر. هیچ چارچوب دقیقی برای پیاده‌سازی معماری وجود ندارد: آزمایش کنید، امتحان کنید، به دنبال چیزی باشید که شخصاً برای شما مناسب است. و فراموش نکنید که در بررسی کد به رفقای ارشد خود نشان دهید =) مثال در GitHub موجود است: https://github.com/admitrevskiy/MVP_Example
نظرات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION