Moxy is MVP library for Android

Overview

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.
Comments
  • Duplicate entry MoxyReflector

    Duplicate entry MoxyReflector

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

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

    opened by user56i 30
  • Animate and Screen rotation 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) не спасает.

    Спасибо!

    help wanted 
    opened by crysan 26
  • Проблема с getSupportFragmentManager().popBackStack()

    Проблема с 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 (повторяющиеся естессно), в таком духе вобщем.

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

    help wanted 
    opened by KaNcHeR 25
  • Совсем простой пример.

    Совсем простой пример.

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

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

    СПАСИБО!

    help wanted 
    opened by crysan 23
  • MoxyReflector генерируется корректно через раз

    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"
    
    opened by asfdfdfd 21
  • Always need to do Clean Project

    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'
    
    opened by sanyok7734 19
  • Сохранение состояния фрагментов

    Сохранение состояния фрагментов

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

    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, но, ничего не изменилось)

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

    opened by NoNews 18
  • Crash at startup

    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)
    
    help wanted 
    opened by morder 15
  • lateinit property Presenter has not been initialized

    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}" )
        }
    }`
    help wanted 
    opened by jamesvanhallen 14
  • Callback method called multiply times

    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

    help wanted 
    opened by lectricas 13
  • FATAL EXCEPTION: ConcurrentModificationException при сохранении состояния активити

    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.

    opened by epereskokov 12
  • Проблема с жизненным циклом MvpDelegate

    Проблема с жизненным циклом 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 выдает ошибку в вышеприведенном виде. Я так понимаю происходит рассинхронизация методов, в ходе чего происходит одновременная запись и чтение из листа, в связи с чем случается падение. 
    
    opened by ermac95 4
  • Tab adapter : FragmentStateAdapter (ViewPager2) doesn't work with MvpFragment

    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!

    opened by GramLun 0
  • Fix ClassCastException with local presenters

    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.

    opened by KhanTF 0
  • Проблема в сгенерированном коде TestListView$$State

    Проблема в сгенерированном коде 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);
    		}
    	}
    
            ......
    
    }
    
    opened by dfazullin 0
  • change import android.support.v7 ... to import androidx.appcompat

    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

    opened by 5oftware 0
Releases(v1.5.3)
  • v1.5.3(Jun 14, 2017)

  • v1.5.2(Jun 14, 2017)

  • v1.5.1(Apr 14, 2017)

  • 1.5.0(Apr 13, 2017)

  • v1.4.6(Mar 10, 2017)

  • v1.4.5(Jan 16, 2017)

  • v1.4.4(Jan 10, 2017)

  • v1.4.3(Dec 29, 2016)

  • v1.3.3(Dec 7, 2016)

  • v1.3.2(Nov 29, 2016)

    • Fixed MvpFragment/MvpAppCompatFragment lifecycle callbacks
    • MvpView will be detached from Presenter:
      • inside onSaveInstanceState, if it will be called. You be able to not commit fragments transaction allowing state loss! Just use commit or commitNow ! If you don't use Cicerone.
      • inside onStop otherwise
      • after MvpView will be restarted, it will apply only new commands!
      • after MvpView will be recreated, it will apply all commands.
    • Added OneExecutionStateStrategy
    • Small changes (like javadocs)

    PS: Added MvpDelegate.onDestroyView() which should be called when view will be destroyed. Causes of this is that detached view can stay alive. Example of use this beyond of Fragment is there.

    Source code(tar.gz)
    Source code(zip)
  • v1.2.0(Nov 14, 2016)

  • v1.1.2(Nov 5, 2016)

  • v1.1.1(Nov 2, 2016)

  • v1.1.0(Oct 22, 2016)

  • v1.0.3(Oct 17, 2016)

  • v1.0.2(Oct 11, 2016)

  • v1.0.1(Oct 5, 2016)

  • v1.0.0(Sep 30, 2016)

    • Allowed to set custom PresentersStore. This object help you manage presenters instances. It can help to mock presenters for View tests.
    • Code style changed

    :star2: Bonus! :boom:

    • Added MvpAppCompatActivity and MvpAppCompatFragment via moxy-app-compat module.
    Source code(tar.gz)
    Source code(zip)
  • v0.5.4(Jul 8, 2016)

  • v0.5.3(Jul 7, 2016)

    • Now you can use typed MvpView. Thats allow you write some like this:
    interface LoadRefreshView<Data> extends MvpView
    {
        void showData(Data data)
    }
    
    public abstaract class LoadRefreshActivity<Data> extends MvpActivity implements LoadRefreshView<Data>
    {
        public abstract CustomAdapter<Data> getAdapter();
    
        void showData(Data data)
        {
            getAdapter().setData(data)
        }
    }
    
    public class NewsActivity extends LoadRefreshActivity<News>
    {
    ...
    }
    
    public class MessagesActivity extends LoadRefreshActivity<Message>
    {
    ...
    }
    
    
    • Changed moment when presenter was destroyed. Caution! Change your base classes similar to MvpActivity and MvpFragment
    • Memory optimization(presenter factory doesn't handle reference to default presenter)
    Source code(tar.gz)
    Source code(zip)
  • v0.4.1(Feb 29, 2016)

    • Annotation @GenerateViewState was deprecated because @InjectViewState generates view state, if it needed
    • Fixed bug of code generation for inner classes
    • Default StateStrategy of subclass View overrides default StateStrategy of View superclass
    Source code(tar.gz)
    Source code(zip)
  • v0.4.0(Feb 29, 2016)

    • MvpDelegate inject presenters in each superclass too
    • Single ParamsProdiver for different factories
    • Check presenter fields with @InjectPresenter that field is public or package local
    • Added global weak presenter type
    • Allowed to apply @InjectPresenter to typed presenter
    Source code(tar.gz)
    Source code(zip)
Android app built with MVP architectural approach and uses Marvel Comics API that allows developers everywhere to access information about Marvel's vast library of comics. :zap:

Villains & Heroes Android app built with MVP architectural approach and uses Marvel Comics API that allows developers everywhere to access information

André Mion 53 Jul 13, 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

Hannes Dorfmann 5.5k Dec 25, 2022
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

Konstantin Mikheev 2k Nov 18, 2022
Minimal UI library for Android inspired by React

Anvil - reactive views for Android Anvil is a small Java library for creating reactive user interfaces. Originally inspired by React, it suits well as

null 1.4k Dec 23, 2022
A Mosby based VIPER library for Android

Moviper A Mosby based VIPER library for Android Why Moviper? You got tired because of fact that your Activities and Fragments were becoming god classe

Mateusz Koślacz 78 Nov 29, 2022
Crossword library for Android

Ararat Ararat is a crossword library for Android, written for and used by alphacross. It includes: Parsers for various formats CrosswordRenderer, whic

Akop Karapetyan 28 Oct 3, 2022
The most complete and powerful data-binding library and persistence infra for Kotlin 1.3, Android & Splitties Views DSL, JavaFX & TornadoFX, JSON, JDBC & SQLite, SharedPreferences.

Lychee (ex. reactive-properties) Lychee is a library to rule all the data. ToC Approach to declaring data Properties Other data-binding libraries Prop

Mike 112 Dec 9, 2022
A lightweight, good expandability Android library used for displaying different pages like loading, error, empty, timeout or even your custom page when you load a page

中文 | English LoadSir ?? ?? LoadSir是一个高效易用,低碳环保,扩展性良好的加载反馈页管理框架,在加载网络或其他数据时候,根据需求切换状态页面, 可添加自定义状态页面,如加载中,加载失败,无数据,网络超时,如占位图,登录失效等常用页面。可配合网络加载框架,结合返回 状态

KingJA 3.3k Dec 21, 2022
Android part of the Android Studio(IntellijIDEA) OkHttp Profiler plugin

OkHttpProfiler Android Library Created by LocaleBro.com - Android Localization Platform The OkHttp Profiler plugin can show requests from the OkHttp l

Ievgenii 261 Dec 8, 2022
Android common lib, include ImageCache, HttpCache, DropDownListView, DownloadManager, Utils and so on

android-common-lib 关于我,欢迎关注 微博:Trinea 主页:trinea.cn 邮箱:trinea.cn#gmail.com 微信:codek2 主要包括:缓存(图片缓存、预取缓存、网络缓存)、公共View(下拉及底部加载更多ListView、底部加载更多ScrollView、

Trinea 5k Dec 30, 2022
dexposed enable 'god' mode for single android application.

What is it? Dexposed is a powerful yet non-invasive runtime AOP (Aspect-oriented Programming) framework for Android app development, based on the work

Alibaba 4.5k Dec 28, 2022
A small, yet full-featured framework that allows building View-based Android applications

Conductor A small, yet full-featured framework that allows building View-based Android applications. Conductor provides a light-weight wrapper around

BlueLine Labs 3.9k Jan 6, 2023
A Job Queue specifically written for Android to easily schedule jobs (tasks) that run in the background, improving UX and application stability.

This Project is Deprecated! Thanks to everybody who've used Android Priority JobQueue. It was designed in a world where there was no JobScheduler, RxJ

Yigit Boyar 3.4k Dec 31, 2022
A plugin system that runs like a browser, but instead of load web pages, it load apk plugins which runs natively on Android system.

Android Dynamic Loader Android Dynamic Loader is a plugin system. The host application is like a browser, but instead of load web pages, it load plugi

Tu Yimin 1.4k Dec 28, 2022
LiteOrm is a fast, small, powerful ORM framework for Android. LiteOrm makes you do CRUD operarions on SQLite database with a sigle line of code efficiently.

#LiteOrm:Android高性能数据库框架 A fast, small, powerful ORM framework for Android. LiteOrm makes you do CRUD operarions on SQLite database with a sigle line

马天宇 1.5k Nov 19, 2022
🚀Plugin for Android Studio And IntelliJ Idea to generate Kotlin data class code from JSON text ( Json to Kotlin )

JsonToKotlinClass Hi, Welcome! This is a plugin to generate Kotlin data class from JSON string, in another word, a plugin that converts JSON string to

Seal 2.8k Jan 3, 2023
Kick-starts Android application development.

Synopsis If you've made it here, chances are you are not quite as satisfied with the Android application framework as you could be. Same for us, that'

Matthias Käppler 1.3k Dec 4, 2022
Rosie is an Android framework to create applications following the principles of Clean Architecture.

Rosie The only way to make the deadline—the only way to go fast—is to keep the code as clean as possible at all times. — Robert C. Martin in Clean Cod

Karumi 1.8k Dec 28, 2022
Create kotlin android project with one line of command.

README This is an android application template project built with kotlin language and some useful libraries. It provides a creator script to quickly c

nekocode 1.6k Dec 20, 2022