arello-mobile / moxy Goto Github PK
View Code? Open in Web Editor NEWMoxy is MVP library for Android
Home Page: https://github.com/Arello-Mobile/Moxy/wiki
License: MIT License
Moxy is MVP library for Android
Home Page: https://github.com/Arello-Mobile/Moxy/wiki
License: MIT License
View interface:
public interface CloseableView extends MvpView {
@StateStrategyType(SkipStrategy.class)
void close();
}
View implementation (Fragment):
@Override
public void close() {
if (getActivity() != null) getActivity().onBackPressed();
}
Presenter:
public void apply() {
localBroadcastManager.sendBroadcast(intent);
getViewState().close();
}
По нажатию на кнопку во вью вызывается метод apply
презентера. В close
текущий фрагмент выкидывается из backstack'a, и на его место встает предыдущий. В итоге во CloseableView$$State
в методе close
выкидывается NullPointerException
т.к. getCurrentState
теперь возвращает null
:
@Override
public void close() {
CloseCommand closeCommand = new CloseCommand();
mViewCommands.beforeApply(closeCommand);
if (mViews == null || mViews.isEmpty()) {
return;
}
for(CloseableView view : mViews) {
view.close();
getCurrentState(view).add(closeCommand);
}
mViewCommands.afterApply(closeCommand);
}
If you add a method that returns a value to the View (both interface and implementation) - generated code will contain error and won't be compiled.
Specifically, generated method with return value will contain:
if (mViews == null || mViews.isEmpty())
{
return; //compile-time error. missing return value
}
This statement should return null;
at least.
hey, I have this code:
class MainActivity : MvpAppCompatActivity(), MainViewInterface, AnkoLogger {
@InjectPresenter
lateinit var mainPresenter: MainPresenter
val recyclerView: RecyclerView by bindView(R.id.track_list)
val fab: FloatingActionButton by bindView(R.id.fab)
val cLayout: CoordinatorLayout by bindView(R.id.main_coordinator)
val realm: Realm = Realm.getDefaultInstance()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
MyApplication.graph.inject(this)
recyclerView.layoutManager = LinearLayoutManager(this)
mainPresenter.loadAllTracks() //error here
}
ViewState:
@StateStrategyType(value = AddToEndSingleStrategy::class) //not sure about this thing
interface MainViewInterface : MvpView {
fun successLoadingTracks(tracks: List<Track>)
}
Presenter
@InjectViewState
class MainPresenter : MvpPresenter<MainViewInterface>() {
fun loadAllTracks() {
viewState.successLoadingTracks(ArrayList())
}
}
And I get this error when trying to access presenter var. Kotlin plugin is up to date.
Ребята привет. Я конечно думаю что это у меня от некой неопытности, но всё же. getSupportFragmentManager().beginTransaction().replace(R.id.main_container, fragment).addToBackStack(null).commit();
При сворачивании приложения(onPause(), onStop()), и возврата на него(onResume()), всё идеально. Но при переключении на другой фрагмент(onPause(), onStop()), и возврата (onResume()) через
getSupportFragmentManager().popBackStack();
дублируется состояние вьюхи (ViewState автоматически применяет к ней все команды, которые Presenter выдавал раньше), ну например адаптер теперь имеет не 2 элемента, а 4 (повторяющиеся естессно), в таком духе вобщем.
Подскажите что делаю не так. Спасибо
Здравствуйте!
Возникла проблема с использованием фрагментов. (при возврате через onBackPressed к прошлому фрагменту из стека)
Что происходит:
MainActivity:
@Override
public void showNumberFragment() {
getSupportFragmentManager()
.beginTransaction()//first fragment in app
.replace(R.id.ltContainer, NumberFragment.newInstance())
.commit();
}
@Override
public void showSmsKeyFragment() {
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.ltContainer, SmsKeyFragment.newInstance())
.addToBackStack(null)
.commit();
}
MainPresenter
@InjectViewState
public class MainPresenter extends MvpPresenter<MainView> {
//@formatter:off
@Inject RestApi restApi;
@Inject PreferenceHelper preferenceHelper;
//@formatter:on
public MainPresenter() {
App.getAppComponent().inject(this);
}
public void showFragment() {
if (preferenceHelper.isFirstRun()) {
getViewState().showNumberFragment();
}
}
}
1 из фрагментов: (оба типичные)
public class SmsKeyFragment extends BaseFragment implements SmsKeyView {
private static final int LAYOUT = R.layout.fragment_sms_key;
//@formatter:off
@InjectPresenter SmsKeyPresenter smsKeyPresenter;
@BindView(R.id.btnOk) Button btnOk;
@BindView(R.id.etSmsKey) EditText etSmsKey;
@BindView(R.id.tvError) TextView tvError;
@BindView(R.id.tvTimeCounter) TextView tvTimeCounter;
//@formatter:on
public static SmsKeyFragment newInstance() {
SmsKeyFragment fragment = new SmsKeyFragment();
Bundle args = new Bundle();
fragment.setArguments(args);
return fragment;
}
@Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
final Bundle savedInstanceState) {
View view = inflater.inflate(LAYOUT, container, false);
ButterKnife.bind(this,view);
setupListeners();
// smsKeyPresenter.startTimer();
return view;
}
private void setupListeners() {
btnOk.setOnClickListener(v->smsKeyPresenter.onClickOk(etSmsKey.getText().toString()));
etSmsKey.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
}
@Override
public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
smsKeyPresenter.checkSmsKey(charSequence);
}
@Override
public void afterTextChanged(Editable editable) {
}
});
}
@Override
public void updateTimeCounter(String time) {
getActivity().runOnUiThread(() -> tvTimeCounter.setText(time));
}
@Override
public void onViewCreated(final View view, final Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
@Override
public void showMapFragment() {
hideKeyboard();
((MainActivity) getActivity()).showMapFragment();
}
@Override
public void activeOkButton() {
// FIXME: 10.11.2016
}
@Override
public void noActiveOkButton() {
//// FIXME: 10.11.2016
}
@Override
public void goneError() {
tvError.setVisibility(View.GONE);
}
@Override
public void showError(String errorMessage) {
tvError.setText(errorMessage);
tvError.startAnimation(AnimationUtils.loadAnimation(getContext(),R.anim.error_transition));
tvError.setVisibility(View.VISIBLE);
}
}
Презентер такой же по формату как в MainActivity.
https://github.com/Arello-Mobile/Moxy/tree/master/moxy-templates
"loyers" insted of "layers" :-)
Hi, Im had issues when view method has AddToEndSingle strategy and implementation of this method call MenuItems. Basically in the moment after screen rotate menu items still null when ViewState try to reapply commands to view. What can I do in that situation?
В обычном фрагменте есть фикс на закрытие активности:
if (isRemoving() || getActivity().isFinishing()) {
getMvpDelegate().onDestroy();
}
В саппортовском фрагменте этого фикса нет:
if (isRemoving()) {
getMvpDelegate().onDestroy();
}
Android DataBinding хорошо уживается с Moxy?
Можно их комбинировать?
Здравствуйте!
Продолжение вот этого вопроса: #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) не спасает.
Спасибо!
I can't find any proguard rules for moxy. I use moxy 0.5.4 and after building with proguard @InjectPresenter returns null.
With this line -keep class * extends com.arellomobile.mvp.PresenterBinder
it works. Does moxy need any additional rules?
AppCompatActivity shoud be extends from FragmentActivity.
FragmentActivity shoud be extends from Activity.
etc
it is important because some librarys expects
Hi.
I am playing with your lib and see some strange behaivour when building from the command line using gradlew. Executing gradlew assembleDebug
will fail if I have android-apt version 1.8 (most recent for now) declared. Stacktrace:
Caused by: java.lang.NoSuchFieldError: DEFAULT
at com.arellomobile.mvp.compiler.MvpCompiler.process(MvpCompiler.java:85)
at com.sun.tools.javac.processing.JavacProcessingEnvironment.callProcessor(JavacProcessingEnvironment.java:793)
at com.sun.tools.javac.processing.JavacProcessingEnvironment.discoverAndRunProcs(JavacProcessingEnvironment.java:722)
at com.sun.tools.javac.processing.JavacProcessingEnvironment.access$1700(JavacProcessingEnvironment.java:97)
at com.sun.tools.javac.processing.JavacProcessingEnvironment$Round.run(JavacProcessingEnvironment.java:1029)
at com.sun.tools.javac.processing.JavacProcessingEnvironment.doProcessing(JavacProcessingEnvironment.java:1163)
at com.sun.tools.javac.main.JavaCompiler.processAnnotations(JavaCompiler.java:1108)
at com.sun.tools.javac.main.JavaCompiler.compile(JavaCompiler.java:824)
at com.sun.tools.javac.main.Main.compile(Main.java:439)
... 79 more
Build from Android Studio's "Run" command is successfull every time.
Everything is fine when I switch android-apt to ver. 1.4.
P.S. Lib looks helpful - great job
Hi,
We think about new feature. We want to make able to put presenter to some scope. Until scope will be closed these presenter instances will be injected. And allow delegate to close scope. And then presenters of scope will be destroyed.
We don't think about interface currently. Only about feature.
Welcome any suggestions.
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}" )
}
}`
This looks very similar to the mosby library by hannes.. Could you please tell me what advantages i would've if i upgrade to moxy?
"wtih" on the title of the page.
Copypaste MvpActivity to MvpAppCompatActivity in each project is ugly. Should provide module, that depends on app compat and provide MvpAppCompatActivity.
I have fragment with view pager with fragments. Each of them contains presenter. When this fragment is replaced with another one, only fragment's presenter that contains view pager is destroyed, but nested fragment's presenters not.
How to use this awesome library on recycleview adapter?
Здравствуйте!
При повороте экрана приложение вылетает без каких либо сообщений в лог.
LoginView
public interface LoginView extends MvpView {
void showLoginScreen();
void showRegisterScreen();
}
LoginPresenter
@InjectViewState
public class LoginPresenter extends MvpPresenter<LoginView> {
public LoginPresenter() { }
public void changeScreen(int screen) {
if (screen==0){
getViewState().showLoginScreen();
}else{
getViewState().showRegisterScreen();
}
}
}
ActivityLogin
public class ActivityLogin extends MvpAppCompatActivity implements LoginView {
@InjectPresenter
LoginPresenter pLoginPresenter;
@Bind(R.id.tvBottomMessage_login) TextView tvBottomMessage_login;
@Bind(R.id.tvBottomMessage_register) TextView tvBottomMessage_register;
@Bind(R.id.rlLogin) View myViewLog;
@Bind(R.id.rlRegister) View myViewReg;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
ButterKnife.bind(this);
tvBottomMessage_login.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
pLoginPresenter.changeScreen(1);
}
});
tvBottomMessage_register.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
pLoginPresenter.changeScreen(0);
}
});
}
@Override
public void showLoginScreen() {
int finalRadius2 = Math.max(myViewLog.getWidth(), myViewLog.getHeight());
Animator anim = ViewAnimationUtils.createCircularReveal(myViewLog, myViewLog.getWidth() / 2, myViewLog.getHeight(), 0, finalRadius2);
myViewReg.setZ(0);
myViewLog.setZ(1);
anim.start();
}
@Override
public void showRegisterScreen() {
int finalRadius2 = Math.max(myViewReg.getWidth(), myViewReg.getHeight());
Animator anim = ViewAnimationUtils.createCircularReveal(myViewReg, myViewReg.getWidth() / 2, myViewReg.getHeight(), 0, finalRadius2);
myViewReg.setZ(1);
myViewLog.setZ(0);
anim.start();
}
}
Не могу понять, как сохранить текущий вид, для его последующего отображения после поворота экрана.
Здравствуйте!
ЕСЛИ НЕ СЛОЖНО, то
можете привести совсем простой пример с использованием архитектуры Moxy?
Как например, в одной активити две кнопки и слой RelativeLayout. При нажатии на кнопки, в слой загружается один из двух фрагментов.
Интересует реализация задачи с позиции Моху и сохранении жизненного цикла.
СПАСИБО!
Возникает проблема с пересозданием презентера после пересоздания активити если фрагмент этого презентера был в бекстеке.
Например имеем 2 фрагмента A и B с презентерами. Сначала показываем A потом реплейсим на B. Далее сворачиваем приложение. Активити уничтожается (для воспроизведения ставлю в настройках флаг “Do not keep activities”). При открытии приложения откроется фрагмент B, где презентер фрагмента B не пересоздался, а при нажатии бек откроется фрагмент A и презентер A - пересоздастся.
Фиксится указанием type = PresenterType.GLOBAL, но в таком случае презентер будет 1 для всех фрагментов этого типа.
Hello, how about JavaDoc for public methods in library :-)
Thank you for you work, it's a cool library/framework
Is Moxy normally work with Kotlin?
I have
@InjectViewState
class MainPresenter : MvpPresenter<MainView>() {
private var mSubscriptions: CompositeSubscription? = null
lateinit var mNetworkManager: NetworkManager
lateinit var mDbManager: DatabaseManager
lateinit var mRxFactory: RxSchedulersFactory
init {
mSubscriptions = CompositeSubscription()
App.appComponent.inject(this)
}
class MainActivity : MvpAppCompatActivity(), MainView{
@InjectPresenter
lateinit var mPresenter: MainPresenter
open class MvpAppCompatActivity : AppCompatActivity() {
lateinit var mMvpDelegate: MvpDelegate<out MvpAppCompatActivity>
init {
mMvpDelegate = MvpDelegate<MvpAppCompatActivity>(this)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
mMvpDelegate.onCreate()
}
override fun onStart() {
super.onStart()
mMvpDelegate.onStart()
}
override fun onSaveInstanceState(outState: Bundle?) {
super.onSaveInstanceState(outState)
mMvpDelegate.onSaveInstanceState(outState)
}
override fun onStop() {
super.onStop()
mMvpDelegate.onStop()
}
override fun onDestroy() {
super.onDestroy()
mMvpDelegate.onDestroy()
}
}
compile 'com.arello-mobile:moxy:0.4.3'
compile 'com.arello-mobile:moxy-android:0.4.3'
kapt 'com.arello-mobile:moxy-compiler:0.4.3'
and presenter in activity is null( what can be wrong?
I try use jack, java8 and annotationProcessor. But I get error
java.lang.StringIndexOutOfBoundsException: String index out of range: -1
at java.lang.String.substring(String.java:1931)
at com.arellomobile.mvp.compiler.Util.getFullClassName(Util.java:105)
at com.arellomobile.mvp.compiler.Util.getFullClassName(Util.java:97)
at com.arellomobile.mvp.compiler.PresenterInjectorRules.checkEnvironment(PresenterInjectorRules.java:70)
at com.arellomobile.mvp.compiler.PresenterInjectorRules.checkAnnotation(PresenterInjectorRules.java:44)
at com.arellomobile.mvp.compiler.MvpCompiler.checkInjectors(MvpCompiler.java:115)
at com.arellomobile.mvp.compiler.MvpCompiler.throwableProcess(MvpCompiler.java:96)
at com.arellomobile.mvp.compiler.MvpCompiler.process(MvpCompiler.java:84)
To reproduce modify build.gradle of sample-github like this
apply plugin: 'com.android.application'
android {
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
compileSdkVersion 25
buildToolsVersion "25.0.0"
defaultConfig {
applicationId "com.arellomobile.mvp.sample.github"
minSdkVersion 14
targetSdkVersion 25
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
jackOptions {
enabled true
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
lintOptions {
abortOnError false
}
}
def support = '25.0.0'
def retrofit = '2.1.0'
def dagger = '2.7'
def butterKnife = "8.4.0"
dependencies {
testCompile "junit:junit:4.12"
compile "com.android.support:appcompat-v7:$support"
compile "com.android.support:design:$support"
compile "com.j256.ormlite:ormlite-core:4.48"
compile "com.j256.ormlite:ormlite-android:4.48"
compile "com.google.code.gson:gson:2.5"
compile "com.jakewharton:butterknife:$butterKnife"
compile "com.squareup.retrofit2:retrofit:$retrofit"
compile "com.squareup.retrofit2:converter-gson:$retrofit"
compile "com.squareup.retrofit2:adapter-rxjava:$retrofit"
compile "com.squareup.picasso:picasso:2.5.2"
compile "com.squareup:otto:1.3.8"
compile "io.reactivex:rxjava:1.1.0"
compile "io.reactivex:rxandroid:1.1.0"
compile "com.google.dagger:dagger:$dagger"
provided "org.glassfish:javax.annotation:10.0-b28"
annotationProcessor "com.jakewharton:butterknife-compiler:$butterKnife"
annotationProcessor "com.google.dagger:dagger-compiler:$dagger"
testCompile "junit:junit:4.12"
testCompile "org.mockito:mockito-all:1.10.19"
testCompile "org.hamcrest:hamcrest-all:1.3"
testCompile "org.robolectric:robolectric:3.1-rc1"
compile 'com.arello-mobile:moxy:1.2.0'
annotationProcessor 'com.arello-mobile:moxy-compiler:1.2.0'
}
Is it possible to not set the tag value (leave it "" as default) but have a single global Presenter? @InjectPresenter(type=PresenterType.GLOBAL)
vs @InjectPresenter(type=PresenterType.GLOBAL,tag="tag")
if I actually need single Presenter of such type around the application.
Можете вести ченджлог по версиям? А то что-то обновляется, а что именно непонятно.
Hi, I understand how to use moxy in activities and fragments, but how can I use moxy in android dialogs? Can you provide an example code, please?
В шаблонах, еще старые подставляет классы вместо
MvpAppCompatActivity /MvpAppCompatFragment
Здравствуйте!
Очень хочется инжектить модели к пресентерам через BasePresenter, унаследовав его от MvpPresenter. (По аналогии с BaseActivity/BaseFragment). А из самих презентеров вызывать уже готовые модели.
Возможно ли это в Moxy?
Let's take a simple login screen. We have LoginView
@StateStrategyType(value = AddToEndStrategy::class)
interface LoginView : MvpView {
fun showProgress()
}
LoginActivity:
@InjectPresenter(type = PresenterType.LOCAL)
@JvmField
var mLoginPresenter: LoginPresenter? = null
// basic boilerplate ...
override fun showProgress() {
contentContainer.visibility = View.GONE
progressLoader.visibility = View.VISIBLE
progressLoader.show()
}
and a presenter:
@InjectViewState
open class LoginPresenter : MvpPresenter<LoginView>() {
fun login() {
viewState.showProgress()
}
}
If I call mLoginPresenter.login()
when I press login button my progressbar appears (ViewCommands are created for ViewState), but when I rotate the screen, it's shows login form. If I inspect it, it seems that the presenter does not survive state change and contains no ViewCommands afterwards to restore the state as a new instance is injected:
if (mViewCommands.isEmpty())
{
return;
}
is always positive.
Tried Notelin
app example, has the same problem - presenter does not survive. Is this behavior expected or am I not getting something?
I'am trying to find out proper way of injecting dependencies into presenter. Since passing dependencies in constructor is not an option we need to use some other mechanism. If we'll take a look at MoxySample, for example at SignInPresenter
public class SignInPresenter extends MvpPresenter<SignInView> {
@Inject
Context mContext;
@Inject
GithubService mGithubService;
public SignInPresenter() {
GithubApp.getAppComponent().inject(this);
}
//...
we will see that injection is happening in constructor of presenter. But this line devaluates the whole point of DI process, since we are introducing unnecessary dependency from GithubApp. And also this prevents presenter from being tested properly.
Another place to call component's inject method would be from activity/fragment onCreate method but this would cause reinjecting dependencies each time activity or fragment is recreated, including orientation change, which is also not good. So can you suggest preferred way of passing dependencies?
Здравствуйте!
Сделал всё как по вашему примеру. Написал LoginActivity, LoginPresenter, LoginView. Приложение запускается и крашится из-за того , что LoginPresenter, объявленный в активити, остается null.
Пожалуйста, подскажите в чем может быть проблема. Вот пример кода.
public class LoginActivity extends MvpActivity implements LoginView {
@InjectPresenter
LoginPresenter mLoginPresenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
Button mSignInButton = (Button) findViewById(R.id.sign_in_button);
mSignInButton.setOnClickListener(new OnClickListener()
{
@Override
public void onClick(View v) {
attemptLogin();
}
});
mErrorDialog = new AlertDialog.Builder(this)
.setTitle(R.string.app_name)
.setOnCancelListener(new OnCancelListener() {
@Override
public void onCancel(DialogInterface dialogInterface) {
mLoginPresenter.onErrorCancel();
}
}).create();
mLoginFormView = findViewById(R.id.login_form);
mProgressView = findViewById(R.id.login_progress);
}
private void attemptLogin() {
mLoginPresenter.login(mUsernameView.getText().toString(), mPasswordView.getText().toString(),this);
}
@InjectViewState
public class LoginPresenter extends MvpPresenter<LoginView> {
public void login(String username, String password, Context context) {
//какой-то код
}
}
Имеется активити с проигрыванием видео-потока с возможностью выбора архива видео. Проигрывание видео начинается в onCreate через вызов презентера, потом условно выбираю проигрывание архива, поворачиваю экран, продолжает играть онлайн, а не архив.
онлайн видео при создании:
в активити в onCreate вызывается метод getCamera, в котором получаем ссылку на stream-поток.
protected void onCreate(final Bundle savedInstanceState) {
videoPlayPresenter.getCamera(cameraId);
}
public void getCamera(Long camId){
String cookie = "JSESSIONID=".concat(AuthUtils.getSessionId()).concat("; XSRF- TOKEN=").concat(AuthUtils.getToken()).concat("; remember- me=").concat(AuthUtils.getRememberMe());
final Observable<BackendData> observable = RxUtils.wrapRetrofitCall(service.getCamera(cookie, AuthUtils.getToken(), camId, false));
RxUtils.wrapAsync(observable)
.subscribe(
backendData -> {
ObjectMapper mapper = new ObjectMapper();
CameraSmallDTO cameraSmallDTO = mapper.convertValue(backendData.getData(), CameraSmallDTO.class);
getViewState().getCamera(cameraSmallDTO);
},
throwable -> showError()
);
}
Если все хорошо, вызывается метод в getCamera из активити и в нем вызывается метод play из презентера для проигрывания видео.
@Override
public void getCamera(CameraSmallDTO camera) {
cameraSmallDTO = camera;
rtmpLink = cameraSmallDTO.getInfo().getUrl();
devCode = cameraSmallDTO.getKey();
videoPlayPresenter.play(rtmpLink, false, null, null);
}
Когда я хочу проиграть архив, я выбираю время и в активити вызываю метод play из презентера, в нем запрашивается новая ссылка на stream-поток, если это архив или продолжает играть онлайн.
public void play(String path, boolean flagArchive, Long camId, Date date){
if (camId != null && date != null){
DateFormat df = new SimpleDateFormat("dd.MM.yyyy HH:mm");
String dateStart = df.format(date);
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
calendar.add(Calendar.MINUTE, 10);
String dateStop = df.format(calendar.getTime());
String cookie = "JSESSIONID=".concat(AuthUtils.getSessionId()).concat("; XSRF-TOKEN=").concat(AuthUtils.getToken()).concat("; remember-me=").concat(AuthUtils.getRememberMe());
Observable<BackendData> observable = RxUtils.wrapRetrofitCall(service.getStreamArchive(cookie, AuthUtils.getToken(), camId, dateStart, dateStop, true));
RxUtils.wrapAsync(observable)
.subscribe(response ->
getViewState().play(response.getData().toString(), true),
throwable -> getViewState().play(path, false)
);
} else getViewState().play(path, flagArchive);
}
Если я выбрал играть архив, и повернул экран - начинает ссылка на онлайн, а не архив онлайн
Any suggestion on how to test a project using this library?
Привет, мне очень понравилась ваша библиотека, просто потрясная реализация мвп) всё очень удобно и красиво) Единственное я бы хотел спросить как правильно поступить, что бы не городить велосипеды. У меня есть ViewPager с 3мя одинаковыми фрагментами, но они отображают разную информацию. При создании этих фрагментов, они все инжектятся к одному и тому же презентору) тот естественно запоминает состояние последнего добавленного фрагмента и после чего все 3 фрагмента начинают показывать одну и ту же информацию) Можно как то создавать для каждого фрагмента, свой отдельный презентер? или же есть какие то другие варианты?
I encountered a problem when writing custom tags provider on Kotlin, and decided to check whether it works on Java, so I wrote a test Activity:
interface TestView extends MvpView {
}
public class TestActivity extends MvpAppCompatActivity implements TestView {
@InjectPresenter(type = PresenterType.GLOBAL)
TestPresenter presenter;
@ProvidePresenter(type = PresenterType.GLOBAL)
TestPresenter providePresenter() {
return new TestPresenter();
}
@ProvidePresenterTag(presenterClass = TestPresenter.class, type = PresenterType.GLOBAL)
String provideTag() {
return "test";
}
class TestPresenter extends MvpPresenter<TestView> {
}
}
But I still get the same error when building:
Error:22:34:35.548 [ERROR] [system.err] java.lang.NullPointerException
22:34:35.549 [ERROR] [system.err] at com.arellomobile.mvp.compiler.PresenterBinderClassGenerator.bindTagProvidersToFields(PresenterBinderClassGenerator.java:160)
22:34:35.549 [ERROR] [system.err] at com.arellomobile.mvp.compiler.PresenterBinderClassGenerator.generate(PresenterBinderClassGenerator.java:104)
22:34:35.549 [ERROR] [system.err] at com.arellomobile.mvp.compiler.PresenterBinderClassGenerator.generate(PresenterBinderClassGenerator.java:51)
22:34:35.549 [ERROR] [system.err] at com.arellomobile.mvp.compiler.MvpCompiler.generateCode(MvpCompiler.java:142)
22:34:35.549 [ERROR] [system.err] at com.arellomobile.mvp.compiler.MvpCompiler.processInjectors(MvpCompiler.java:130)
22:34:35.549 [ERROR] [system.err] at com.arellomobile.mvp.compiler.MvpCompiler.throwableProcess(MvpCompiler.java:100)
22:34:35.549 [ERROR] [system.err] at com.arellomobile.mvp.compiler.MvpCompiler.process(MvpCompiler.java:84)
22:34:35.549 [ERROR] [system.err] at org.jetbrains.kotlin.annotation.AbstractAnnotationProcessingExtension.doRound(AnnotationProcessingExtension.kt:312)
22:34:35.549 [ERROR] [system.err] at org.jetbrains.kotlin.annotation.AbstractAnnotationProcessingExtension.process(AnnotationProcessingExtension.kt:252)
22:34:35.549 [ERROR] [system.err] at org.jetbrains.kotlin.annotation.AbstractAnnotationProcessingExtension.doAnnotationProcessing(AnnotationProcessingExtension.kt:239)
22:34:35.549 [ERROR] [system.err] at org.jetbrains.kotlin.annotation.AbstractAnnotationProcessingExtension.analysisCompleted(AnnotationProcessingExtension.kt:131)
22:34:35.549 [ERROR] [system.err] at org.jetbrains.kotlin.resolve.jvm.TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegration(TopDownAnalyzerFacadeForJVM.java:160)
22:34:35.550 [ERROR] [system.err] at org.jetbrains.kotlin.resolve.jvm.TopDownAnalyzerFacadeForJVM.analyzeFilesWithJavaIntegrationWithCustomContext(TopDownAnalyzerFacadeForJVM.java:79)
22:34:35.550 [ERROR] [system.err] at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler$analyze$1.analyze(KotlinToJVMBytecodeCompiler.kt:362)
22:34:35.550 [ERROR] [system.err] at org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport.analyzeAndReport(AnalyzerWithCompilerReport.kt:126)
22:34:35.550 [ERROR] [system.err] at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.analyze(KotlinToJVMBytecodeCompiler.kt:355)
22:34:35.550 [ERROR] [system.err] at org.jetbrains.kotlin.cli.jvm.compiler.KotlinToJVMBytecodeCompiler.compileModules(KotlinToJVMBytecodeCompiler.kt:130)
22:34:35.550 [ERROR] [system.err] at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:183)
22:34:35.550 [ERROR] [system.err] at org.jetbrains.kotlin.cli.jvm.K2JVMCompiler.doExecute(K2JVMCompiler.kt:52)
22:34:35.550 [ERROR] [system.err] at org.jetbrains.kotlin.cli.common.CLICompiler.exec(CLICompiler.java:199)
22:34:35.550 [ERROR] [system.err] at org.jetbrains.kotlin.gradle.tasks.KotlinCompile.compileNotIncremental(Tasks.kt:594)
22:34:35.550 [ERROR] [system.err] at org.jetbrains.kotlin.gradle.tasks.KotlinCompile.callCompiler(Tasks.kt:419)
22:34:35.550 [ERROR] [system.err] at org.jetbrains.kotlin.gradle.tasks.KotlinCompile.callCompiler(Tasks.kt:151)
22:34:35.550 [ERROR] [system.err] at org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile.execute(Tasks.kt:117)
22:34:35.550 [ERROR] [system.err] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
22:34:35.550 [ERROR] [system.err] at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
22:34:35.551 [ERROR] [system.err] at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
22:34:35.551 [ERROR] [system.err] at java.lang.reflect.Method.invoke(Method.java:498)
22:34:35.551 [ERROR] [system.err] at org.gradle.internal.reflect.JavaMethod.invoke(JavaMethod.java:75)
22:34:35.551 [ERROR] [system.err] at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$IncrementalTaskAction.doExecute(AnnotationProcessingTaskFactory.java:245)
22:34:35.551 [ERROR] [system.err] at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:221)
22:34:35.551 [ERROR] [system.err] at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$IncrementalTaskAction.execute(AnnotationProcessingTaskFactory.java:232)
22:34:35.551 [ERROR] [system.err] at org.gradle.api.internal.project.taskfactory.AnnotationProcessingTaskFactory$StandardTaskAction.execute(AnnotationProcessingTaskFactory.java:210)
22:34:35.551 [ERROR] [system.err] at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeAction(ExecuteActionsTaskExecuter.java:80)
22:34:35.551 [ERROR] [system.err] at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.executeActions(ExecuteActionsTaskExecuter.java:61)
22:34:35.551 [ERROR] [system.err] at org.gradle.api.internal.tasks.execution.ExecuteActionsTaskExecuter.execute(ExecuteActionsTaskExecuter.java:46)
22:34:35.551 [ERROR] [system.err] at org.gradle.api.internal.tasks.execution.PostExecutionAnalysisTaskExecuter.execute(PostExecutionAnalysisTaskExecuter.java:35)
22:34:35.551 [ERROR] [system.err] at org.gradle.api.internal.tasks.execution.SkipUpToDateTaskExecuter.execute(SkipUpToDateTaskExecuter.java:66)
22:34:35.551 [ERROR] [system.err] at org.gradle.api.internal.tasks.execution.ValidatingTaskExecuter.execute(ValidatingTaskExecuter.java:58)
22:34:35.551 [ERROR] [system.err] at org.gradle.api.internal.tasks.execution.SkipEmptySourceFilesTaskExecuter.execute(SkipEmptySourceFilesTaskExecuter.java:52)
22:34:35.552 [ERROR] [system.err] at org.gradle.api.internal.tasks.execution.SkipTaskWithNoActionsExecuter.execute(SkipTaskWithNoActionsExecuter.java:52)
22:34:35.552 [ERROR] [system.err] at org.gradle.api.internal.tasks.execution.SkipOnlyIfTaskExecuter.execute(SkipOnlyIfTaskExecuter.java:53)
22:34:35.552 [ERROR] [system.err] at org.gradle.api.internal.tasks.execution.ExecuteAtMostOnceTaskExecuter.execute(ExecuteAtMostOnceTaskExecuter.java:43)
22:34:35.552 [ERROR] [system.err] at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:203)
22:34:35.552 [ERROR] [system.err] at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter$EventFiringTaskWorker.execute(DefaultTaskGraphExecuter.java:185)
22:34:35.552 [ERROR] [system.err] at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.processTask(AbstractTaskPlanExecutor.java:66)
22:34:35.552 [ERROR] [system.err] at org.gradle.execution.taskgraph.AbstractTaskPlanExecutor$TaskExecutorWorker.run(AbstractTaskPlanExecutor.java:50)
22:34:35.552 [ERROR] [system.err] at org.gradle.execution.taskgraph.DefaultTaskPlanExecutor.process(DefaultTaskPlanExecutor.java:25)
22:34:35.552 [ERROR] [system.err] at org.gradle.execution.taskgraph.DefaultTaskGraphExecuter.execute(DefaultTaskGraphExecuter.java:110)
22:34:35.552 [ERROR] [system.err] at org.gradle.execution.SelectedTaskExecutionAction.execute(SelectedTaskExecutionAction.java:37)
22:34:35.552 [ERROR] [system.err] at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:37)
22:34:35.552 [ERROR] [system.err] at org.gradle.execution.DefaultBuildExecuter.access$000(DefaultBuildExecuter.java:23)
22:34:35.552 [ERROR] [system.err] at org.gradle.execution.DefaultBuildExecuter$1.proceed(DefaultBuildExecuter.java:43)
22:34:35.552 [ERROR] [system.err] at org.gradle.execution.DryRunBuildExecutionAction.execute(DryRunBuildExecutionAction.java:32)
22:34:35.552 [ERROR] [system.err] at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:37)
22:34:35.553 [ERROR] [system.err] at org.gradle.execution.DefaultBuildExecuter.execute(DefaultBuildExecuter.java:30)
22:34:35.553 [ERROR] [system.err] at org.gradle.initialization.DefaultGradleLauncher$4.run(DefaultGradleLauncher.java:153)
22:34:35.553 [ERROR] [system.err] at org.gradle.internal.Factories$1.create(Factories.java:22)
22:34:35.553 [ERROR] [system.err] at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:91)
22:34:35.553 [ERROR] [system.err] at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:53)
22:34:35.553 [ERROR] [system.err] at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:150)
22:34:35.553 [ERROR] [system.err] at org.gradle.initialization.DefaultGradleLauncher.access$200(DefaultGradleLauncher.java:32)
22:34:35.553 [ERROR] [system.err] at org.gradle.initialization.DefaultGradleLauncher$1.create(DefaultGradleLauncher.java:98)
22:34:35.553 [ERROR] [system.err] at org.gradle.initialization.DefaultGradleLauncher$1.create(DefaultGradleLauncher.java:92)
22:34:35.553 [ERROR] [system.err] at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:91)
22:34:35.553 [ERROR] [system.err] at org.gradle.internal.progress.DefaultBuildOperationExecutor.run(DefaultBuildOperationExecutor.java:63)
22:34:35.553 [ERROR] [system.err] at org.gradle.initialization.DefaultGradleLauncher.doBuild(DefaultGradleLauncher.java:92)
22:34:35.553 [ERROR] [system.err] at org.gradle.initialization.DefaultGradleLauncher.run(DefaultGradleLauncher.java:83)
22:34:35.553 [ERROR] [system.err] at org.gradle.launcher.exec.InProcessBuildActionExecuter$DefaultBuildController.run(InProcessBuildActionExecuter.java:99)
22:34:35.553 [ERROR] [system.err] at org.gradle.tooling.internal.provider.runner.BuildModelActionRunner.run(BuildModelActionRunner.java:46)
22:34:35.554 [ERROR] [system.err] at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
22:34:35.554 [ERROR] [system.err] at org.gradle.tooling.internal.provider.runner.SubscribableBuildActionRunner.run(SubscribableBuildActionRunner.java:58)
22:34:35.554 [ERROR] [system.err] at org.gradle.launcher.exec.ChainingBuildActionRunner.run(ChainingBuildActionRunner.java:35)
22:34:35.554 [ERROR] [system.err] at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:48)
22:34:35.554 [ERROR] [system.err] at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:30)
22:34:35.554 [ERROR] [system.err] at org.gradle.launcher.exec.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:81)
22:34:35.554 [ERROR] [system.err] at org.gradle.launcher.exec.ContinuousBuildActionExecuter.execute(ContinuousBuildActionExecuter.java:46)
22:34:35.554 [ERROR] [system.err] at org.gradle.launcher.daemon.server.exec.ExecuteBuild.doBuild(ExecuteBuild.java:52)
22:34:35.554 [ERROR] [system.err] at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
22:34:35.554 [ERROR] [system.err] at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
22:34:35.554 [ERROR] [system.err] at org.gradle.launcher.daemon.server.exec.WatchForDisconnection.execute(WatchForDisconnection.java:37)
22:34:35.554 [ERROR] [system.err] at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
22:34:35.554 [ERROR] [system.err] at org.gradle.launcher.daemon.server.exec.ResetDeprecationLogger.execute(ResetDeprecationLogger.java:26)
22:34:35.554 [ERROR] [system.err] at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
22:34:35.554 [ERROR] [system.err] at org.gradle.launcher.daemon.server.exec.RequestStopIfSingleUsedDaemon.execute(RequestStopIfSingleUsedDaemon.java:34)
22:34:35.555 [ERROR] [system.err] at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
22:34:35.555 [ERROR] [system.err] at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:74)
22:34:35.555 [ERROR] [system.err] at org.gradle.launcher.daemon.server.exec.ForwardClientInput$2.call(ForwardClientInput.java:72)
22:34:35.555 [ERROR] [system.err] at org.gradle.util.Swapper.swap(Swapper.java:38)
22:34:35.555 [ERROR] [system.err] at org.gradle.launcher.daemon.server.exec.ForwardClientInput.execute(ForwardClientInput.java:72)
22:34:35.555 [ERROR] [system.err] at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
22:34:35.555 [ERROR] [system.err] at org.gradle.launcher.daemon.server.health.DaemonHealthTracker.execute(DaemonHealthTracker.java:47)
22:34:35.555 [ERROR] [system.err] at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
22:34:35.555 [ERROR] [system.err] at org.gradle.launcher.daemon.server.exec.LogToClient.doBuild(LogToClient.java:60)
22:34:35.555 [ERROR] [system.err] at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
22:34:35.555 [ERROR] [system.err] at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
22:34:35.555 [ERROR] [system.err] at org.gradle.launcher.daemon.server.exec.EstablishBuildEnvironment.doBuild(EstablishBuildEnvironment.java:72)
22:34:35.555 [ERROR] [system.err] at org.gradle.launcher.daemon.server.exec.BuildCommandOnly.execute(BuildCommandOnly.java:36)
22:34:35.555 [ERROR] [system.err] at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
22:34:35.555 [ERROR] [system.err] at org.gradle.launcher.daemon.server.health.HintGCAfterBuild.execute(HintGCAfterBuild.java:41)
22:34:35.556 [ERROR] [system.err] at org.gradle.launcher.daemon.server.api.DaemonCommandExecution.proceed(DaemonCommandExecution.java:120)
22:34:35.556 [ERROR] [system.err] at org.gradle.launcher.daemon.server.exec.StartBuildOrRespondWithBusy$1.run(StartBuildOrRespondWithBusy.java:50)
22:34:35.556 [ERROR] [system.err] at org.gradle.launcher.daemon.server.DaemonStateCoordinator$1.run(DaemonStateCoordinator.java:237)
22:34:35.556 [ERROR] [system.err] at org.gradle.internal.concurrent.ExecutorPolicy$CatchAndRecordFailures.onExecute(ExecutorPolicy.java:54)
22:34:35.556 [ERROR] [system.err] at org.gradle.internal.concurrent.StoppableExecutorImpl$1.run(StoppableExecutorImpl.java:40)
22:34:35.556 [ERROR] [system.err] at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
22:34:35.556 [ERROR] [system.err] at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
22:34:35.556 [ERROR] [system.err] at java.lang.Thread.run(Thread.java:745)
22:34:35.556 [ERROR] [system.err] Moxy compilation failed; see the compiler error output for details (java.lang.NullPointerException)
22:34:35.637 [ERROR] [org.jetbrains.kotlin.gradle.tasks.KotlinCompile_Decorated] e: C:\Users\vandrikeev\Projects\test\app\src\main\java\ru\andrikeev\android\test\application\App.kt: (1, 1): Some error(s) occurred while processing annotations. Please see the error messages above.
22:34:35.637 [ERROR] [org.jetbrains.kotlin.gradle.tasks.KotlinCompile_Decorated] e: C:\Users\vandrikeev\Projects\test\app\src\main\java\ru\andrikeev\android\test\application\App.kt: (10, 52): Unresolved reference: DaggerAppComponent
22:34:35.637 [ERROR] [org.jetbrains.kotlin.gradle.tasks.KotlinCompile_Decorated] e: C:\Users\vandrikeev\Projects\test\app\src\main\java\ru\andrikeev\android\test\application\App.kt: (24, 24): Unresolved reference: DaggerAppComponent
22:34:35.641 [ERROR] [org.gradle.BuildExceptionReporter]
22:34:35.641 [ERROR] [org.gradle.BuildExceptionReporter] FAILURE: Build failed with an exception.
22:34:35.641 [ERROR] [org.gradle.BuildExceptionReporter]
22:34:35.641 [ERROR] [org.gradle.BuildExceptionReporter] * What went wrong:
22:34:35.641 [ERROR] [org.gradle.BuildExceptionReporter] Execution failed for task ':app:compileDebugKotlin'.
22:34:35.641 [ERROR] [org.gradle.BuildExceptionReporter] > Compilation error. See log for more details
22:34:35.641 [ERROR] [org.gradle.BuildExceptionReporter]
22:34:35.641 [ERROR] [org.gradle.BuildExceptionReporter] * Try:
22:34:35.641 [ERROR] [org.gradle.BuildExceptionReporter] Run with --stacktrace option to get the stack trace.
It seems to me that the problem with Kotlin annotations processing, but i'm not sure and have no idea how to fix it.
Обновился с версии 0.5.2 -> 0.5.4 ViewState перестало сохранять свое состояние.
Например: Есть метод который показывает диалоговое окно @StateStrategyType(AddToEndSingleStrategy.class)
void showLoadingDialog();
при перевороте экрана, диалог не показывается, а на 0.5.2. - показывается
Hello. Is there a best practice for Moxy to save view state of input fields?
For example, a scheme below causes looping.
//LoginView
void onCreate(){
editTextLogin.afterTextChanged((text) -> loginPresenter.onLoginChanged(text));
}
void showLogin(String login){
editTextLogin.setText(login);
}
//LoginPresenter
void onLoginChanged(String newLogin){
this.login = newLogin;
getViewState().showLogin(newLogin);
}
I have an error, when trying to build project.
The problem is with generated ViewState's
I have View:
interface LceView<in M : Any> : MvpView {
fun showLoading(pullToRefresh: Boolean = false)
fun showContent(model: M)
fun showError(e: Throwable, pullToRefresh: Boolean = false)
}
But generated LceViewState generated with [ ] around Model template:
public class LceView$$State<M> extends MvpViewState<LceView> implements LceView<[M]> {
private ViewCommands<LceView> mViewCommands = new ViewCommands<>();
@Override
public void restoreState(LceView view) {
if (mViewCommands.isEmpty()) {
return;
}
mViewCommands.reapply(view);
}
@Override
public void showLoading(boolean pullToRefresh) {
ShowLoadingCommand showLoadingCommand = new ShowLoadingCommand(pullToRefresh);
mViewCommands.beforeApply(showLoadingCommand);
if (mViews == null || mViews.isEmpty()) {
return;
}
for(LceView view : mViews) {
view.showLoading(pullToRefresh);
}
mViewCommands.afterApply(showLoadingCommand);
}
@Override
public void showContent(M model) {
ShowContentCommand showContentCommand = new ShowContentCommand(model);
mViewCommands.beforeApply(showContentCommand);
if (mViews == null || mViews.isEmpty()) {
return;
}
for(LceView view : mViews) {
view.showContent(model);
}
mViewCommands.afterApply(showContentCommand);
}
@Override
public void showError(java.lang.Throwable e, boolean pullToRefresh) {
ShowErrorCommand showErrorCommand = new ShowErrorCommand(e, pullToRefresh);
mViewCommands.beforeApply(showErrorCommand);
if (mViews == null || mViews.isEmpty()) {
return;
}
for(LceView view : mViews) {
view.showError(e, pullToRefresh);
}
mViewCommands.afterApply(showErrorCommand);
}
private class ShowLoadingCommand extends ViewCommand<LceView> {
public final boolean pullToRefresh;
ShowLoadingCommand(boolean pullToRefresh) {
super("showLoading", com.arellomobile.mvp.viewstate.strategy.AddToEndStrategy.class);
this.pullToRefresh = pullToRefresh;
}
@Override
public void apply(LceView mvpView) {
mvpView.showLoading(pullToRefresh);
}
}
private class ShowContentCommand extends ViewCommand<LceView> {
public final M model;
ShowContentCommand(M model) {
super("showContent", com.arellomobile.mvp.viewstate.strategy.AddToEndStrategy.class);
this.model = model;
}
@Override
public void apply(LceView mvpView) {
mvpView.showContent(model);
}
}
private class ShowErrorCommand extends ViewCommand<LceView> {
public final java.lang.Throwable e;
public final boolean pullToRefresh;
ShowErrorCommand(java.lang.Throwable e, boolean pullToRefresh) {
super("showError", com.arellomobile.mvp.viewstate.strategy.AddToEndStrategy.class);
this.e = e;
this.pullToRefresh = pullToRefresh;
}
@Override
public void apply(LceView mvpView) {
mvpView.showError(e, pullToRefresh);
}
}
}
p.s. I tried use invariant for M, it didn't help
Allow user to use custom PresenterStore in MvpFacade
Trying to use the @InjectPresenter in the Views and @InjectViewState preceding the presenter classes but my presenter classes also need to inject modules of their own which I'm doing via the constructor but I get this error
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.jackthreads.android/com.jackthreads.android.activities.PageActivity}: java.lang.IllegalStateException: Unable to instantiate class com.jackthreads.android.presenters.PagePresenter: make sure class name exists, is public, and has an empty constructor that is public
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2661)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2726)
at android.app.ActivityThread.access$900(ActivityThread.java:172)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1421)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:145)
at android.app.ActivityThread.main(ActivityThread.java:5835)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1399)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194)
Caused by: java.lang.IllegalStateException: Unable to instantiate class com.jackthreads.android.presenters.PagePresenter: make sure class name exists, is public, and has an empty constructor that is public
at com.arellomobile.mvp.DefaultPresenterFactory.createPresenter(DefaultPresenterFactory.java:30)
at com.arellomobile.mvp.DefaultPresenterFactory.createPresenter(DefaultPresenterFactory.java:11)
at com.arellomobile.mvp.MvpProcessor.getMvpPresenter(MvpProcessor.java:125)
at com.arellomobile.mvp.MvpProcessor.getMvpPresenters(MvpProcessor.java:177)
at com.arellomobile.mvp.MvpDelegate.onCreate(MvpDelegate.java:110)
at com.jackthreads.android.activities.MvpAppCompatActivity.onCreate(MvpAppCompatActivity.java:15)
Searching Moxy and Dagger 2 brings up nothing and it seems like they're messing each other up.
Code generation makes wrong code if some method of MvpView contains parameter named "command". Code generation should be fixed.
readme.md
References [RU] Moxy — реализация MVP под Android с щепоткой магии
Ведет на пример, который уже указан выше, а не на статью на habrahabr (?).
java.lang.NoSuchMethodError: No virtual method getActivity()Landroid/app/Activity; in class Lcom/arellomobile/mvp/MvpAppCompatFragment; or its super classes (declaration of 'com.arellomobile.mvp.MvpAppCompatFragment' appears in ...)
at com.arellomobile.mvp.MvpAppCompatFragment.onDestroy(MvpAppCompatFragment.java:40)
at android.support.v4.app.Fragment.performDestroy(Fragment.java:2322)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1240)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1290)
at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1272)
at android.support.v4.app.FragmentManagerImpl.dispatchDestroy(FragmentManager.java:2186)
at android.support.v4.app.FragmentController.dispatchDestroy(FragmentController.java:271)
at android.support.v4.app.FragmentActivity.onDestroy(FragmentActivity.java:388)
at android.support.v7.app.AppCompatActivity.onDestroy(AppCompatActivity.java:209)
at com.arellomobile.mvp.MvpAppCompatActivity.onDestroy(MvpAppCompatActivity.java:26)
at android.app.Activity.performDestroy(Activity.java:6169)
at android.app.Instrumentation.callActivityOnDestroy(Instrumentation.java:1141)
at android.app.ActivityThread.performDestroyActivity(ActivityThread.java:3693)
at android.app.ActivityThread.handleDestroyActivity(ActivityThread.java:3724)
at android.app.ActivityThread.access$1400(ActivityThread.java:151)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1357)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5254)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
Let's examine this use-case: presenter adds group of markers to map, removes some of them afterwards, some - not. This process may repeate multitude of times, then orientation changes, and ViewState is reapplied to newly attached View. From user perspective it would be lengthy process of repeating all actions user had done, while he just needs markers which "survived" removal.
To solve this issue it would be great to add one more StateStrategy
- TraceStrategy
and ClearStrategy
(counterpart)
For example, let's have a method:
public class MapView implements MvpView {
/*
* Some other code
*/
private int counter = 0;
@StateStrategy(value = TraceStrategy.class, tag = "addMarker")
int addMarker(double lat, double lon) {
// ...
return counter++;
}
}
In result of this ViewCommand
on top of ViewCommand
stack new ViewCommand
should be added with tag = "addMarker0". Running this command again will result in ViewCommand
with tag = "addMarker1" and so on. Number is value returned by method (more generally - toString()
of returned Object
).
Now counterpart for addMarker
will be
public class MapView implements MvpView {
/*
* Some other code
*/
private int counter = 1; // Affected by addMarker()
@StateStrategy(value = ClearStrategy.class, tag = "addMarker")
int removeMarker(int id) {
// ...
return --counter;
}
}
This ViewCommand
appends to tag returned value than searches ViewCommand
with tag whose value is, for instance, "addMarker0", removes it and does not put itself in stack.
Drawbacks of this approach are:
P.S.
If there is no return value required, for example, just one marker can be added, than TraceStrategy
and ClearStrategy
should also take care of this.
P.P.S
Issue instead of PR because I think there is discussion part in this issue.
Можно по-русски, да?
Здрасьте.
Как-то при повороте экрана не очень сохраняется state
как на эмуляторе (API-24), так и на зверьке (API-17).
Все на видео.
Причем в ланшафтном режиме кнопка "далее" тоже не переводит к следующему полю.
В чем может быть дело?
С уважением, ВВК
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.