goodbye progress dialog mess on android

17
Good-bye progress dialog mess tsuyoyo (@tsuyogoro) Mercari, Inc.

Upload: tsuyoshi-yoshioka

Post on 11-Apr-2017

287 views

Category:

Engineering


3 download

TRANSCRIPT

Good-bye progress dialog mess

tsuyoyo (@tsuyogoro)Mercari, Inc.

About me

tsuyoyo (@tsuyogoro)

Android engineer

Mercari, Inc

About this talk

● Progress dialog

● Technically○ Show/Dismiss by BehaviorSubject (RxJava 1.x)○ ViewModel lifecycle management with Dagger2

● Preview app○ https://github.com/tsuyoyo/shibuya_apk_13

Major troubles by progress dialog...

● Dismiss at orientation change

● Remains on screen

● Suddenly crashes in the background(since 3.0/HoneyComb)

java.lang.IllegalStateException:

Can not perform this action after onSaveInstanceState

My experiences

● Tough to fix bugs

● Fix would make code dirty

● Galaxy S7

How can we beat them?

● android:configChanges="orientation"

● No care (e.g. call API again)

● Try to manage state○ Activity#onSaveInstanceState○ Activity#onRetainCustomNonConfigurationInstance

1. Something independent on Activity lifecycle

2. Always view can revive

3. Dialog? (not DialogFragment)

My idea

time

Calling API

ViewModel

View

Implementation idea (1) : BehaviorSubject

onNext(true);

BehaviorSubject<Boolean>

Observer B

onNext(false);

Observer C

Observer A

My idea

time

Calling API

ViewModel

View

onNext(in progress)

onNext(complete)

Implementation idea (2) : Lifecycle of ViewModel

● Use Dagger2, provided by component

● Scope?○ longer than Activity & shorter than Application

● Custom scope!!○ Referred : Dependency injection with Dagger 2 - Custom scopes

http://frogermcs.github.io/dependency-injection-with-dagger-2-custom-scopes/

Custom scope

● Looks just annotation, no effect

● Application class holds the component, releases it at end of screen

@Scope@Retention(RetentionPolicy.RUNTIME)@interface ViewModelScope {}

Custom scopepublic class MyApplication extends Application {

private MyComponent component;

public MyComponent getMyComponent() { if (component == null) { component = DaggerMyComponent.builder().build(); } return component; }

public void releaseMyComponent() { component = null; }

}

Custom scopepublic class MainActivity extends AppCompatActivity {

@Inject MyViewModel myViewModel;

@Override protected void onCreate(Bundle savedInstanceState) {

… ((MyApplication) getApplication()).getMyComponent().inject(this); bindViewModel(); }

@Override public void finish() { super.finish(); ((MyApplication) getApplication()).releaseMyComponent(); }

Summary

● Simple way to beat messy caused by ProgressDialog

● BehaviorSubject & CustomScope

● For detail○ https://github.com/tsuyoyo/shibuya_apk_13

Implementation idea (1) : BehaviorSubjectprivate MyFakeApi api;private BehaviorSubject<Boolean> isLoading = BehaviorSubject.create(false);...public Observable<Boolean> isLoading() { return isLoading.asObservable(); }… api.call(). .doOnSubscribe( () -> isLoading.onNext(true) ) .doOnUnsubscribe( () -> isLoading.onNext(false) ) .subscribe( /** do something */ )...

private void bindViewModel() {…myViewModel.isLoading() .observeOn(AndroidSchedulers.mainThread()) .subscribe(isLoading -> /** show/dismiss progress dialog */)

ViewModel

View