goodbye progress dialog mess on android

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

Upload: tsuyoshi-yoshioka

Post on 21-Apr-2017

319 views

Category:

Engineering


0 download

TRANSCRIPT

Page 1: Goodbye progress dialog mess on Android

Good-bye progress dialog mess

tsuyoyo (@tsuyogoro)Mercari, Inc.

Page 2: Goodbye progress dialog mess on Android

About me

tsuyoyo (@tsuyogoro)

Android engineer

Mercari, Inc

Page 3: Goodbye progress dialog mess on Android

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

Page 4: Goodbye progress dialog mess on Android

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

Page 5: Goodbye progress dialog mess on Android

My experiences

● Tough to fix bugs

● Fix would make code dirty

● Galaxy S7

Page 6: Goodbye progress dialog mess on Android

How can we beat them?

● android:configChanges="orientation"

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

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

Page 7: Goodbye progress dialog mess on Android

1. Something independent on Activity lifecycle

2. Always view can revive

3. Dialog? (not DialogFragment)

Page 8: Goodbye progress dialog mess on Android

My idea

time

Calling API

ViewModel

View

Page 9: Goodbye progress dialog mess on Android

Implementation idea (1) : BehaviorSubject

onNext(true);

BehaviorSubject<Boolean>

Observer B

onNext(false);

Observer C

Observer A

Page 10: Goodbye progress dialog mess on Android

My idea

time

Calling API

ViewModel

View

onNext(in progress)

onNext(complete)

Page 11: Goodbye progress dialog mess on Android

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/

Page 12: Goodbye progress dialog mess on Android

Custom scope

● Looks just annotation, no effect

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

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

Page 13: Goodbye progress dialog mess on Android

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; }

}

Page 14: Goodbye progress dialog mess on Android

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(); }

Page 15: Goodbye progress dialog mess on Android

Summary

● Simple way to beat messy caused by ProgressDialog

● BehaviorSubject & CustomScope

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

Page 16: Goodbye progress dialog mess on Android
Page 17: Goodbye progress dialog mess on Android

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