Moxy is MVP library for Android

Last update: May 5, 2022

Moxy

This Moxy repository is deprecated and no longer supported.

Please migrate to the actual version of the Moxy framework at Moxy communuty repo.

Description

Maven Central license

Moxy is a library that helps to use MVP pattern when you do the Android Application. Without problems of lifecycle and boilerplate code!

The main idea of using Moxy: schematic_using See what's happening here in the wiki.

Capabilities

Moxy has a few killer features in other ways:

  • Presenter stay alive when Activity recreated(it simplify work with multithreading)
  • Automatically restore all that user see when Activity recreated(including dynamic content is added)
  • Capability to changes of many Views from one Presenter

Sample

View interface

public interface HelloWorldView extends MvpView {
	void showMessage(int message);
}

Presenter

@InjectViewState
public class HelloWorldPresenter extends MvpPresenter<HelloWorldView> {
	public HelloWorldPresenter() {
		getViewState().showMessage(R.string.hello_world);
	}
}

View implementation

public class HelloWorldActivity extends MvpAppCompatActivity implements HelloWorldView {

	@InjectPresenter
	HelloWorldPresenter mHelloWorldPresenter;

	private TextView mHelloWorldTextView;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_hello_world);

		mHelloWorldTextView = ((TextView) findViewById(R.id.activity_hello_world_text_view_message));
	}

	@Override
	public void showMessage(int message) {
		mHelloWorldTextView.setText(message);
	}
}

Here you can see "Github" sample application.

Wiki

For all information check Moxy Wiki

Android studio templates

In order to avoid boilerplate code creating for binding activity, fragments and its presentation part, we propose to use Android Studio templates for Moxy.

Templates located in /moxy-templates

Links

Telegram channel (en)
Telegram channel (ru)
References
FAQ

Integration

Base modules integration:

dependencies {
  ...
  compile 'com.arello-mobile:moxy:1.5.5'
  annotationProcessor 'com.arello-mobile:moxy-compiler:1.5.5'
}

For additional base view classes MvpActivity and MvpFragment add this:

dependencies {
  ...
  compile 'com.arello-mobile:moxy-android:1.5.5'
}

If you are planning to use AppCompat, then you can use MvpAppCompatActivity and MvpAppCompatFragment. Then add this:

dependencies {
  ...
  compile 'com.arello-mobile:moxy-app-compat:1.5.5'
  compile 'com.android.support:appcompat-v7:$support_version'
}

AndroidX module integration

If you use AndroidX, use MvpAppCompatActivity and MvpAppCompatFragment add this (thanks to @jordan1997):

implementation 'tech.schoolhelper:moxy-x-androidx:1.7.0'

AndroidX(Google material) module integration

If you use google material, use MvpBottomSheetDialogFragment add this (thanks to @jordan1997):

implementation 'tech.schoolhelper:moxy-x-material:1.7.0'

Note: @jordan1997 creates fork of Moxy — feel free to use it fully (instead of use only this module dependency) on your opinion.

Kotlin

If you are using kotlin, use kapt instead of provided/apt dependency type:

apply plugin: 'kotlin-kapt'

dependencies {
  ...
  kapt 'com.arello-mobile:moxy-compiler:1.5.5'
}

ProGuard

Moxy is completely without reflection! No special ProGuard rules required.

License

The MIT License (MIT)

Copyright (c) 2016 Arello Mobile

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

GitHub

https://github.com/Arello-Mobile/Moxy
Comments
  • 1. Duplicate entry MoxyReflector

    Добрый день. Столкнулся с проблемой в случае использования библиотеки Moxy одновременно в модуле приложения и модуле библиотеки. Поскольку 2 класса MoxyReflector имеют одинаковый пакет. Подскажите решение.

    Java.util.zip.ZipException: duplicate entry: com/arellomobile/mvp/MoxyReflector.class

    Reviewed by user56i at 2017-01-11 12:16
  • 2. Animate and Screen rotation 2

    Здравствуйте!

    Продолжение вот этого вопроса: #37 Есть одно активити и 3 дополнительных слоя, которые вызываем так:

    Activity:

    public class StartActivity extends MvpAppCompatActivity implements StartActivityView {
        @InjectPresenter
        StartActivityPresenter pStartActivityPresenter;
    
        @BindView(R.id.rootContainer) ViewGroup rootContainer;
    
        Scene scene_setusergendername;
        Scene scene_selectchild;
        Scene scene_setchildname;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_start);
    
            ButterKnife.bind(this);
    
            scene_setusergendername = Scene.getSceneForLayout(rootContainer, R.layout.scene_setusergendername, this);
            scene_selectchild = Scene.getSceneForLayout(rootContainer, R.layout.scene_selectchild, this);
            scene_setchildname = Scene.getSceneForLayout(rootContainer, R.layout.scene_setchildname, this);
        }
    
        public void goSetUserGenderName(View view) {
            pStartActivityPresenter.changeScene("SetUserGenderName");
        }
    
        public void goSelectChild(View view) {
            pStartActivityPresenter.changeScene("SelectChild");
        }
    
        public void goSetChildName(View view) {
            pStartActivityPresenter.changeScene("SetChildName");
        }
    
        @Override
        public void showScene_SetUserGenderName() {
            TransitionManager.go(scene_setusergendername, TransitionInflater.from(StartActivity.this).inflateTransition(R.transition.fade_out_in));
        }
    
        @Override
        public void showScene_SelectChild() {
            TransitionManager.go(scene_selectchild, TransitionInflater.from(StartActivity.this).inflateTransition(R.transition.fade_out_in));
        }
    
        @Override
        public void showScene_SetChildName() {
            TransitionManager.go(scene_setchildname, TransitionInflater.from(StartActivity.this).inflateTransition(R.transition.fade_out_in));
        }
    }
    

    Presenter:

    @InjectViewState
    public class StartActivityPresenter extends MvpPresenter<StartActivityView> {
        public StartActivityPresenter() {    }
    
        public void changeScene(String scenename) {
            if ("SetUserGenderName".equals(scenename)) {
                getViewState().showScene_SetUserGenderName();
            }
            else if ("SelectChild".equals(scenename)) {
                getViewState().showScene_SelectChild();
            }
            else if ("SetChildName".equals(scenename)) {
                getViewState().showScene_SetChildName();
            }
        }
    }
    

    View:

    public interface StartActivityView extends MvpView {
        void showScene_SetUserGenderName();
        void showScene_SelectChild();
        void showScene_SetChildName();
    }
    

    При нажатии кнопок на слоях, переходы обрабатываются нормально, претензий нет. Как только произошел поворот устройства, то срабатывает событие goSetUserGenderName. Т.е. после старта приложения нажали кнопку 1 раз - перешли на второй экран, нажали на кнопку снова - перешли на третий, еще раз - на четвертый экран. Повернули устройство - автоматом перешли на второй. Как сохранить состояние экрана в этом случае? isInRestoreState(this) не спасает.

    Спасибо!

    Reviewed by crysan at 2016-11-11 03:57
  • 3. Проблема с getSupportFragmentManager().popBackStack()

    Ребята привет. Я конечно думаю что это у меня от некой неопытности, но всё же. getSupportFragmentManager().beginTransaction().replace(R.id.main_container, fragment).addToBackStack(null).commit(); При сворачивании приложения(onPause(), onStop()), и возврата на него(onResume()), всё идеально. Но при переключении на другой фрагмент(onPause(), onStop()), и возврата (onResume()) через getSupportFragmentManager().popBackStack(); дублируется состояние вьюхи (ViewState автоматически применяет к ней все команды, которые Presenter выдавал раньше), ну например адаптер теперь имеет не 2 элемента, а 4 (повторяющиеся естессно), в таком духе вобщем.

    Подскажите что делаю не так. Спасибо

    Reviewed by KaNcHeR at 2016-10-08 19:21
  • 4. Совсем простой пример.

    Здравствуйте!

    ЕСЛИ НЕ СЛОЖНО, то можете привести совсем простой пример с использованием архитектуры Moxy? Как например, в одной активити две кнопки и слой RelativeLayout. При нажатии на кнопки, в слой загружается один из двух фрагментов. Интересует реализация задачи с позиции Моху и сохранении жизненного цикла.

    СПАСИБО!

    Reviewed by crysan at 2016-10-25 05:44
  • 5. MoxyReflector генерируется корректно через раз

    Записал короткое двухминутное видео для иллюстрации проблемы http://take.ms/ovLac

    В проекте используется java и kotlin (1.1.3-2)

    Кусок build.gradle:

    buildscript {
        ext.kotlin_version = '1.1.3-2'
        repositories {
            jcenter()
        }
        dependencies {
            classpath 'com.android.tools.build:gradle:2.3.3'
            classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
            classpath 'com.google.gms:google-services:3.1.0'
    
            // NOTE: Do not place your application dependencies here; they belong
            // in the individual module build.gradle files
        }
    }
    

    Кусок app/build.gradle:

    apply plugin: 'kotlin-android'
    apply plugin: 'kotlin-kapt'
    
    // скипнуто
    
    compile 'com.arello-mobile:moxy:1.5.3'
    compile 'com.arello-mobile:moxy-android:1.5.3'
    compile 'com.arello-mobile:moxy-app-compat:1.5.3'    
    kapt 'com.arello-mobile:moxy-compiler:1.5.3'
    
    compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
    
    Reviewed by asfdfdfd at 2017-07-18 11:09
  • 6. Always need to do Clean Project

    Здравствуйте. Решил попробовать Moxy взял ваш код с презентации и написал на kotlin. Но вот беда появилась ошибка

    kotlin.UninitializedPropertyAccessException: lateinit property counterPresenter has not been initialized

    делаю Clean Project и нормально, потом делаю изменения в коде и опять ошибка пока не сделаю Clean Project.

    @InjectViewState
    class CounterPresenter : MvpPresenter<CounterView>() {
    
        var count: Int = 0
    
        init {
            viewState.showView(count)
        }
    
        fun onPlusClick() {
            count++
            viewState.showView(count)
        }
    }
    
    
    interface CounterView : MvpView {
        fun showView(count: Int)
    }
    
    class CounterFragment : MvpAppCompatFragment(), CounterView {
    
        @InjectPresenter
        lateinit var counterPresenter: CounterPresenter
    
        override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
            return inflater?.inflate(R.layout.fragment, container, false)
        }
    
        override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
            parentView.setBackgroundColor(arguments.getInt("color", 0))
    
            button.setOnClickListener {
                countPlus()
            }
        }
    
        fun countPlus() {
            counterPresenter.onPlusClick()
        }
        
        override fun showView(count: Int) {
            textCounter.text = "$count"
        }
    }
    
    
        compile 'com.arello-mobile:moxy:1.5.3'
        compile 'com.arello-mobile:moxy-android:1.5.3'
        compile 'com.arello-mobile:moxy-app-compat:1.5.3'
        kapt 'com.arello-mobile:moxy-compiler:1.5.3'
    
    Reviewed by sanyok7734 at 2017-05-29 17:18
  • 7. Сохранение состояния фрагментов

    Здравствуйте! Есть небольшая проблема с сохранением состояния фрагментов.

    1. Есть SplashScreenActivity, которая может показывать 1 из 2-х фрагментов. View:
    public interface SplashScreenView extends MvpView {
        void showMainActivityWithLoginFragment();  //если токен отсутствует
        void showMainActivityWithMainFragment(); //если есть токен
        void showErrorConnection();
        void goneErrorConnection();
    }
    
    1. MainActivity View:
    public interface MainActivityView extends MvpView {
        void showMainFragment();
        void showLoginFragment();
    }
    
    
    1. LoginFragment View:
    public interface LoginView extends MvpView {
    
        void visibleHeader();
        void goneHeader();
        void showSystemError(String errorText);
        void showPhoneError();
        void showPasswordError();
        void goneSystemError();
        void gonePhoneError();
        void gonePasswordError();
        void startErrorAnimation(TextView tvError);
        void showProgress(boolean progress);
        void showMainFragment();
    }
    
    1. MainFragment c viewPager В нём происходит только инициализация viewPager+tabLayout, view-интерфейс пустой.

    Насколько мне известно, по умолчанию, стоит стратегия AddToEndStrategy ко всем view-командам. Получается, что при перевороте экрана, накопленные команды во view запустятся заново. Но, при перевороте экрана, если я нахожусь в LoginFragment, состояние EditText не сохраняется. Так же, если я нахожусь в MainFragment, при перевороте открывается LoginFragment. Для решения этой проблемы пробовал использовать @StateStrategyType(SingleStateStrategy.class) к методам запуска MainFragment, но, ничего не изменилось)

    Скорее всего, проблема в неправильных стратегиях. Какие использовать в данном случае — не совсем понятно.

    Reviewed by NoNews at 2016-12-15 10:33
  • 8. Crash at startup

    gradle file

    apply plugin: 'com.neenbedankt.android-apt'
    ...
    compile 'com.android.support:appcompat-v7:25.0.1'
    ...
    apt 'com.google.dagger:dagger-compiler:2.8'
    compile 'com.google.dagger:dagger:2.8'
    ...
    compile 'com.arello-mobile:moxy:1.4.5'
    provided 'com.arello-mobile:moxy-compiler:1.4.5'
    compile 'com.arello-mobile:moxy-android:1.4.5'
    compile 'com.arello-mobile:moxy-app-compat:1.4.5'
    

    crash

    java.lang.NoClassDefFoundError: Failed resolution of: Lcom/arellomobile/mvp/MoxyReflector;
    at com.arellomobile.mvp.MvpProcessor.getMvpPresenters(MvpProcessor.java:82)
    at com.arellomobile.mvp.MvpDelegate.onCreate(MvpDelegate.java:101)
    at com.arellomobile.mvp.MvpAppCompatFragment.onCreate(MvpAppCompatFragment.java:23)
    at some.package.BaseFragment.onCreate(BaseFragment.java:26)
    
    Reviewed by morder at 2017-02-20 12:24
  • 9. lateinit property Presenter has not been initialized

    routesPresenter.getRoutes("18089") thrown exception:

    kotlin.UninitializedPropertyAccessException: lateinit property routesPresenter has not been initialized

    class MainFragment: MvpAppCompatFragment(), RoutesView {
        @InjectPresenter
        lateinit var routesPresenter: RoutesPresenter
    
        var adapter: RoutesAdapter = RoutesAdapter()
    
        companion object{
    
            fun newInstance(): MainFragment {
                return MainFragment()
            }
    
        }
    
        override fun onCreateView(inflater: LayoutInflater?, container: ViewGroup?, savedInstanceState: Bundle?): View? {
            App.appComponent.inject(this)
            val v = inflater?.inflate(R.layout.fragment_main, container, false)
            return v
        }
    
        override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
            super.onViewCreated(view, savedInstanceState)
    
            recyclerView.layoutManager = LinearLayoutManager(activity)
            recyclerView.adapter = adapter
    
            routesPresenter.getRoutes("18089")
    
        }
    
        override fun onSuccess(list: List<Route>) {
             Log.d("MainFragment", "onSuccess")
            adapter.setItems(list)
        }
    
        override fun onEmptyData() {
            Log.d("MainFragment", "onEmpty")
        }
    
        override fun onError(e: Throwable) {
            Log.e("MainFragment", "error ${e.message}" )
        }
    }`
    Reviewed by jamesvanhallen at 2016-11-03 07:54
  • 10. Callback method called multiply times

    public void loadTeasers(int skip, boolean refresh, Category category) {
            getViewState().showProgress();
    
            Subscription s2 = ActiveAndroidHelper.getSources()
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(teasers -> {
                        getViewState().onTeasersLoaded(teasers);
                        getViewState().hideProgress();
                    }, this::onError);
            unsubscribeOnDestroy(s2);
        }
    

    Suppose we have simple method which loads some data from network. I want to refresh my network data every onResume method. And, in this case, on each call of loadTeasers(true, new Category()), the callback method onTeasersLoaded(teasers) is called N times, where N is the number of onResume methods (and loadTeasers) executed. I think I need to unsubscribe and null the previous subsribition, but which method to use here? Thanks

    Reviewed by lectricas at 2017-01-23 08:34
  • 11. FATAL EXCEPTION: ConcurrentModificationException при сохранении состояния активити

    FATAL EXCEPTION: java.util.ConcurrentModificationException at java.util.ArrayList$Itr.next(ArrayList.java:860) at java.util.AbstractCollection.addAll(AbstractCollection.java:343) at com.arellomobile.mvp.viewstate.MvpViewState.detachView(MvpViewState.java:84) at com.arellomobile.mvp.MvpPresenter.detachView(MvpPresenter.java:72) at com.arellomobile.mvp.MvpDelegate.onDetach(MvpDelegate.java:143) at com.arellomobile.mvp.MvpAppCompatActivity.onSaveInstanceState(MvpAppCompatActivity.java:44) at android.app.Activity.performSaveInstanceState(Activity.java:1555) at android.app.Instrumentation.callActivityOnSaveInstanceState(Instrumentation.java:1392) ...

    Вылетает при переключении на другое приложение (нажатии на home button). Вылетает не всегда, иногда на первый, иногда на третий-четвертый раз переключения. Иногда та же ошибка вызывает при восстановлении состояния, то есть в attachView().

    Кусок кода, в котором происходит данная ошибка: MVPViewState.java :

        public void detachView(View view) {
    	      mViews.remove(view);
    	      mInRestoreState.remove(view);
    		Set<ViewCommand<View>> currentState = Collections.newSetFromMap(new WeakHashMap<ViewCommand<View>, Boolean>());
    		currentState.addAll(mViewCommands.getCurrentState());
    		mViewStates.put(view, currentState);
    	   }
    

    Не совсем понятно, даже чисто теоретически при каких условиях может вылететь эта ошибка? Дебаггер в режиме логгирования отлавливает заход только одного потока в этот метод, после чего вылетает COncurrentModificationException.

    Reviewed by epereskokov at 2018-08-27 07:24
  • 12. Проблема с жизненным циклом MvpDelegate

    Добрый день. На большом количестве устройств - от 9 до 12 версии андроид происходит вылет со следующей ошибкой

    Fatal Exception: java.util.ConcurrentModificationException at java.util.ArrayList$Itr.next(ArrayList.java:860) at moxy.MvpDelegate.onAttach(MvpDelegate.java:166) at moxy.MvpAppCompatFragment.onStart(MvpAppCompatFragment.java:38) at androidx.fragment.app.Fragment.performStart(Fragment.java:2731) at androidx.fragment.app.FragmentStateManager.start(FragmentStateManager.java:365) at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1206) at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1368) at androidx.fragment.app.FragmentManager.moveFragmentToExpectedState(FragmentManager.java:1446) at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1509) at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2637) at androidx.fragment.app.FragmentManager.dispatchStart(FragmentManager.java:2595) at androidx.fragment.app.Fragment.performStart(Fragment.java:2740) at androidx.fragment.app.FragmentStateManager.start(FragmentStateManager.java:365) at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1206) at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1368) at androidx.fragment.app.FragmentManager.moveFragmentToExpectedState(FragmentManager.java:1446) at androidx.fragment.app.FragmentManager.moveToState(FragmentManager.java:1509) at androidx.fragment.app.FragmentManager.dispatchStateChange(FragmentManager.java:2637) at androidx.fragment.app.FragmentManager.dispatchStart(FragmentManager.java:2595) at androidx.fragment.app.FragmentController.dispatchStart(FragmentController.java:258) at androidx.fragment.app.FragmentActivity.onStart(FragmentActivity.java:550) at androidx.appcompat.app.AppCompatActivity.onStart(AppCompatActivity.java:210) at moxy.MvpAppCompatActivity.onStart(MvpAppCompatActivity.java:32) at modulbank.ru.commonapp.ui.main.MainActivity.onStart(MainActivity.kt:274) at android.app.Instrumentation.callActivityOnStart(Instrumentation.java:1456) at android.app.Activity.performStart(Activity.java:8076) at android.app.ActivityThread.handleStartActivity(ActivityThread.java:3665) at android.app.servertransaction.TransactionExecutor.performLifecycleSequence(TransactionExecutor.java:221) at android.app.servertransaction.TransactionExecutor.cycleToPath(TransactionExecutor.java:201) at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:173) at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2215) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loopOnce(Looper.java:346) at android.os.Looper.loop(Looper.java:475) at android.app.ActivityThread.main(ActivityThread.java:7889) at java.lang.reflect.Method.invoke(Method.java) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1009)

       Экран приложения, где происходит вылет не определен, крашлитика firebase выдает ошибку в вышеприведенном виде. Я так понимаю происходит рассинхронизация методов, в ходе чего происходит одновременная запись и чтение из листа, в связи с чем случается падение. 
    
    Reviewed by ermac95 at 2022-03-14 11:23
  • 13. Tab adapter : FragmentStateAdapter (ViewPager2) doesn't work with MvpFragment

    I'm trying to create TabAdapter class that inherits FragmentStateAdapter. So in function createFragment I need to return my framents which inherits MvpFragment, but it says: image And if function will inherits Fragment IDE says "Type mismatch" under my custom fragments: image Maybe I could use other class (not FragmentStateAdapter) which compatible with Moxy. I dont know how to fix it, pls help!

    Reviewed by GramLun at 2021-01-31 13:32
  • 14. Fix ClassCastException with local presenters

    After obfuscation, the names of the presenter classes have the same name, as a result of which an error occurs when we get the presenter from the map and bring it to a certain type.

    Reviewed by KhanTF at 2020-03-10 08:37
  • 15. Проблема в сгенерированном коде TestListView$$State

    Решил обновить проект. Перешел на Androidx и с com.github.moxy на com.arello-mobile Проблему со всеми импортами решил, но появилась ошибка кодогенерации moxy (то есть при com.github.moxy - такого не было)

    Мой gradle

    dependencies {
       ...
        // Moxy
        implementation "com.arello-mobile:moxy:$moxyVersion" //moxyVersion = '1.5.5'
        implementation 'tech.schoolhelper:moxy-x-androidx:1.7.0'
        kapt "com.arello-mobile:moxy-compiler:$moxyVersion"
       ...
    }
    
    

    Fragment

    class TestListFragment: BaseListFragment<String, TestListView, TestListPresenter, StringPaginationAdapter>(), TestListView {
    
        @InjectPresenter
        lateinit var presenter: TestListPresenter
    
        @ProvidePresenter
        fun providePresenter(): TestListPresenter = TestListPresenter()
    
        override fun initPresenter() = presenter
    
        override fun initAdapter() = StringPaginationAdapter()
    }
    

    Родительский Fragment

    abstract class BaseListFragment<
            ITEM: Any,
            VIEW: BaseListView<ITEM>,
            PRESENTER: BaseListPresenter<ITEM, VIEW>,
            A: BasePaginationAdapter<ITEM>
        > : BaseFragment(), BaseListView<ITEM>, PaginationRecyclerView.OnLoadMore {
    
        val listPresenter: PRESENTER by lazy { initPresenter() }
    
        abstract fun initPresenter(): PRESENTER
    
        val adapter: A by lazy { initAdapter() }
    
        open val emptyListLayoutRes = R.layout.layout_base_empty_list
        private var emptyLayout: View? = null
        override val layoutRes = R.layout.layout_base_list
    
        abstract fun initAdapter(): A
    
        override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
            val layout = super.onCreateView(inflater, container, savedInstanceState)
            layout.findViewById<FrameLayout>(R.id.flListContent)?.run {
                instanceEmptyList(inflater, container?.findViewById(R.id.flListContent))?.let {
                    emptyLayout = it
                    [email protected](emptyLayout)
                    hideEmptyList()
                }
            }
            return layout
        }
    
        private fun instanceEmptyList(inflater: LayoutInflater, container: ViewGroup?): View? {
            return if (emptyListLayoutRes != -1) { inflater.inflate(emptyListLayoutRes, container, false) }
            else { null }
        }
    
        override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
            initRecyclerView(rvList)
            initRefresher()
            super.onViewCreated(view, savedInstanceState)
        }
    
        open fun initRecyclerView(recyclerView: PaginationRecyclerView) {
            recyclerView.adapter = adapter
            recyclerView.withPagination = [email protected]
            recyclerView.listener = this
        }
    
        override fun updateList(list: List<ITEM>) {
            rlRefresher?.isRefreshing = false
            adapter.update(list)
        }
    
        open fun getRefresherLayout(): SwipeRefreshLayout? = rlRefresh
    
        open fun getRecyclerView(): PaginationRecyclerView = prvList
    }
    

    View

    interface TestListView : BaseListView<String>
    

    Родительский View

    @StateStrategyType(AddToEndSingleStrategy::class)
    interface BaseListView <I>: BaseView {
        ...
        fun updateList(list: List<I>)
        ...
    }
    

    Сгенерированный код TestListView$$State (Ругается на "List<? extends I>", Не знает "I")

    public class TestListView$$State extends MvpViewState<TestListView> implements TestListView {
    
            ......
    
    	@Override
    	public void updateList(List<? extends I> list) {
    		UpdateListCommand updateListCommand = new UpdateListCommand(list);
    		mViewCommands.beforeApply(updateListCommand);
    
    		if (mViews == null || mViews.isEmpty()) {
    			return;
    		}
    
    		for (TestListView view : mViews) {
    			view.updateList(list);
    		}
    
    		mViewCommands.afterApply(updateListCommand);
    	}
    
    	public class UpdateListCommand extends ViewCommand<TestListView> {
    		public final List<? extends I> list;
    
    		UpdateListCommand(List<? extends I> list) {
    			super("updateList", AddToEndSingleStrategy.class);
    
    			this.list = list;
    		}
    
    		@Override
    		public void apply(TestListView mvpView) {
    			mvpView.updateList(list);
    		}
    	}
    
            ......
    
    }
    
    Reviewed by dfazullin at 2019-12-12 12:46
  • 16. change import android.support.v7 ... to import androidx.appcompat

    After migrating to AndroidX I faced the problem of underling errors in activities which extend MvpAppCompatActivity. I think it is because of using import android.support.v7 … instead of import androidx.appcompat… in moxy-x-app-compat-1.7.0-sources.jar!\com\arellomobile\mvp\MvpAppCompatActivity.java

    Reviewed by 5oftware at 2019-08-02 19:35
Nucleus is an Android library, which utilizes the Model-View-Presenter pattern to properly connect background tasks with visual parts of an application.

Nucleus Deprecation notice Nucleus is not under develpment anymore. It turns out that Redux architecture scales way better than MVP/MVI/MVVM/MVxxx and

May 4, 2022
A Model-View-Presenter / Model-View-Intent library for modern Android apps

Mosby A Model-View-Presenter and Model-View-Intent library for Android apps. Dependency dependencies { compile 'com.hannesdorfmann.mosby3:mvi:3.1.1

May 24, 2022
Extendable MVI framework for Kotlin Multiplatform with powerful debugging tools (logging and time travel), inspired by Badoo MVICore library
Extendable MVI framework for Kotlin Multiplatform with powerful debugging tools (logging and time travel), inspired by Badoo MVICore library

Should you have any questions or ideas please welcome to the Slack channel: #mvikotlin Inspiration This project is inspired by Badoo MVICore library.

May 17, 2022
Movie app that receives popular movies and allows the user to search for the specific movie through the Rest API with help of retrofit library &MVVM architecture.
 Movie app that receives popular movies and allows the user to search for the specific movie through the Rest API with help of retrofit library &MVVM architecture.

MovieClue Millions of movies, TV shows and people to discover. Explore now Movie app that recieves popular movies and allow the user to search for spe

Mar 31, 2022
📝 A demo todo/notes app which demonstrates the use of MVVM architecture, Navigation Component Library, Room Database, LiveData, Coroutines
📝 A demo todo/notes app which demonstrates the use of MVVM architecture, Navigation Component Library, Room Database, LiveData, Coroutines

?? MyNotes A demo notes/todo app which demonstrates the use of MVVM architecture, Navigation Component Library, Room Database, LiveData, Coroutines et

May 9, 2022
Android Clean Architecture💎 Base Project Android with Kotlin and MVVM applying clean architecture
 Android Clean Architecture💎 Base Project Android with Kotlin and MVVM applying clean architecture

Android Clean Architecture?? Base Project Android with Kotlin and MVVM applying clean architecture

May 18, 2022
Pick any of your favorite github repository and create a mini android app showing its details on an android app.
Pick any of your favorite github repository and create a mini android app showing its details on an android app.

Github Browser Pick any of your favorite github repository and create a mini android app showing its details on an android app. Screens navigation gra

Apr 17, 2022
MVVM for Android

AndroidBinding MVVM for Android What's New Pre Compiled version available on root directory android-binding.gen.zip for activity/application template

Apr 21, 2022
A data-binding Presentation Model(MVVM) framework for the Android platform.

PLEASE NOTE, THIS PROJECT IS NO LONGER BEING MAINTAINED. As personal time contraints, I am currently unable to keep up. Please use official android da

May 18, 2022
A full-featured framework that allows building android applications following the principles of Clean Architecture.

EasyMVP A powerful, and very simple MVP library with annotation processing and bytecode weaving. EasyMVP eliminates the boilerplate code for dealing w

Apr 24, 2022
MVVM RECIPE ANDROID APP Is an app where I show how to use MVVM, retrofit, dagger hilt, coroutine, liveData, Kotlin, navigation component, and so on...
MVVM RECIPE ANDROID APP Is an app where I show how to use MVVM, retrofit, dagger hilt, coroutine, liveData, Kotlin, navigation component, and so on...

MVVM RECIPE ANDROID APP Is an app where I show how to use MVVM, retrofit, dagger hilt, coroutine, liveData, kotlin, navigation component, and so on...

Apr 4, 2022
Membuat Aplikasi Github User MVVM dengan Android Studio
Membuat Aplikasi Github User MVVM dengan Android Studio

Membuat Aplikasi Github User MVVM dengan Android Studio. Ini hanya untuk referensi bagi kalian yang mengikuti Submission Dicoding Github User App.

Mar 21, 2022
Kotlin Multiplatform Router for Android and iOS
Kotlin Multiplatform Router for Android and iOS

A powerful Kotlin Multiplatform Router for Android and iOS Support I am happy to help you with any problem on gitter Feel free to open any new issue!

Apr 12, 2022
Model-View-ViewModel architecture components for mobile (android & ios) Kotlin Multiplatform development
Model-View-ViewModel architecture components for mobile (android & ios) Kotlin Multiplatform development

Mobile Kotlin Model-View-ViewModel architecture components This is a Kotlin Multiplatform library that provides architecture components of Model-View-

May 17, 2022
Tutorial MVVM Fast Android Networking
Tutorial MVVM Fast Android Networking

MVVM-FAN Tutorial MVVM Fast Android Networking Tutorial Build with Android Studio https://youtu.be/nXX-NQIoGjk Tutorial Build with Step by Step https:

Mar 19, 2022
🧬 Android DataBinding kit for notifying data changes from Model layers to UI layers on MVVM architecture.
🧬 Android DataBinding kit for notifying data changes from Model layers to UI layers on MVVM architecture.

?? Android DataBinding kit for notifying data changes from Model layers to UI layers on MVVM architecture.

May 19, 2022
LukohSplash is based on Android latest architectural components,Jetpack, and follows MVVM design pattern.
LukohSplash is based on Android latest architectural components,Jetpack, and follows MVVM design pattern.

?? The LukohSplash by open-source contributor, Lukoh. LukohSplash LukohSplash is based on Android latest architectural components,Jetpack, and follows

May 3, 2022
Android Jetpack MVVM Boilerplate. Integrated with Jetpack dependencies, Hilt, Room, Okhttp, Retrofit, etc.
Android Jetpack MVVM Boilerplate. Integrated with Jetpack dependencies, Hilt, Room, Okhttp, Retrofit, etc.

Android Jetpack MVVM Boilerplate Android Jetpack MVVM Boilerplate a Jetpack based, MVVM boilerplate template project for Modern Android. Features Here

Oct 27, 2021
An Android Template with MVVM and Clean Architecture
An Android Template with MVVM and Clean Architecture

MVVMTemplate ??‍ A simple Android template that lets you create an Android project quickly. How to use ?? Just click on button to create a new repo st

May 16, 2022