Skip to content

Commit

Permalink
Sample app! (#97)
Browse files Browse the repository at this point in the history
* Stub a basic android sample scaffolding

* Stub a basic android sample scaffolding

* Add fleshed out mainactivity and kotlinactivity examples

* Add recipes for AutoDisposeActivities

* Fix missing symmetries in activity events

* Put kotlin at end of file name for better consistency later

* Add message to after-destroy exceptions for clarity

* Add base class details

* Add Fragment demo

* Add View demo

* Add AutoDisposeViewHolder demo

* Better nullability annotations handling

* Suppress a couple more

* More idiomatic kotlin in AutoDisposeView + lazy

* Cleaner When's

* Fix dependencies

* Fix capitalization

* More idiomatic unbindernotifier handling

* Document the corresponding event methods
  • Loading branch information
ZacSweers authored Oct 1, 2017
1 parent 5e28955 commit f9874af
Show file tree
Hide file tree
Showing 26 changed files with 1,405 additions and 0 deletions.
59 changes: 59 additions & 0 deletions sample/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright (c) 2017. Uber Technologies
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

buildscript {
repositories {
jcenter()
google()
}

dependencies {
classpath deps.build.gradlePlugins.android
classpath deps.build.gradlePlugins.kotlin
}
}

apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'

android {
compileSdkVersion deps.build.compileSdkVersion
buildToolsVersion deps.build.buildToolsVersion

defaultConfig {
minSdkVersion deps.build.minSdkVersion
targetSdkVersion deps.build.targetSdkVersion
}
compileOptions {
// TODO Go to 1.8 + D8 on AGP 3.x
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
}

dependencies {
provided deps.misc.javaxExtras
compile project(':autodispose')
compile project(':autodispose-android')
compile project(':autodispose-android-archcomponents')
compile project(':autodispose-kotlin')
compile 'com.android.support:appcompat-v7:26.1.0'
compile 'com.android.support.constraint:constraint-layout:1.1.0-beta1'
compile 'com.android.support:design:26.1.0'
}
55 changes: 55 additions & 0 deletions sample/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (c) 2017. Uber Technologies
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
~ You may obtain a copy of the License at
~
~ http://www.apache.org/licenses/LICENSE-2.0
~
~ Unless required by applicable law or agreed to in writing, software
~ distributed under the License is distributed on an "AS IS" BASIS,
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.uber.autodispose.sample">

<application
android:allowBackup="true"
android:hardwareAccelerated="true"
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher"
android:supportsRtl="true"
android:theme="@style/Theme.AppCompat.Light.NoActionBar"
android:fullBackupContent="@null"
tools:ignore="GoogleAppIndexingWarning">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:theme="@style/Theme.AppCompat.Light.NoActionBar">

<intent-filter>
<category android:name="android.intent.category.DEFAULT"/>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity
android:name=".KotlinActivity"
android:label="@string/app_name_kotlin"
android:theme="@style/Theme.AppCompat.Light.NoActionBar">

<intent-filter>
<category android:name="android.intent.category.DEFAULT"/>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* Copyright (c) 2017. Uber Technologies
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package android.support.v7.widget;

import android.view.View;

/**
* A bind-aware {@link RecyclerView.ViewHolder} implementation that knows when it's bound or
* unbound.
* <p>
* Disclaimer: This is in no way supported and THIS COULD BREAK AT ANY TIME. Left for research.
*/
public abstract class BindAwareViewHolder extends RecyclerView.ViewHolder {

public BindAwareViewHolder(View itemView) {
super(itemView);
}

protected void onBind() {

}

protected void onUnbind() {

}

@Override void setFlags(int flags, int mask) {
boolean wasBound = isBound();
super.setFlags(flags, mask);
notifyBinding(wasBound, isBound());
}

@Override void addFlags(int flags) {
boolean wasBound = isBound();
super.addFlags(flags);
notifyBinding(wasBound, isBound());
}

@Override void clearPayload() {
boolean wasBound = isBound();
super.clearPayload();
notifyBinding(wasBound, isBound());
}

@Override void resetInternal() {
boolean wasBound = isBound();
super.resetInternal();
notifyBinding(wasBound, isBound());
}

private void notifyBinding(boolean previousBound, boolean currentBound) {
if (previousBound && !currentBound) {
onUnbind();
} else if (!previousBound && currentBound) {
onBind();
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
* Copyright (c) 2017. Uber Technologies
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.uber.autodispose.recipes;

import android.app.Activity;
import android.os.Bundle;
import android.support.annotation.Nullable;
import com.uber.autodispose.LifecycleEndedException;
import com.uber.autodispose.LifecycleScopeProvider;
import io.reactivex.Observable;
import io.reactivex.functions.Function;
import io.reactivex.subjects.BehaviorSubject;

/**
* An {@link Activity} example implementation for making one implement {@link
* LifecycleScopeProvider}. One would normally use this as a base activity class to extend others
* from.
*/
public abstract class AutoDisposeActivity extends Activity
implements LifecycleScopeProvider<AutoDisposeActivity.ActivityEvent> {

public enum ActivityEvent {
CREATE, START, RESUME, PAUSE, STOP, DESTROY
}

/**
* This is a function of current event -> target disposal event. That is to say that if event A
* returns B, then any stream subscribed to during A will autodispose on B. In Android, we make
* symmetric boundary conditions. Create -> Destroy, Start -> Stop, etc. For anything after Resume
* we dispose on the next immediate destruction event. Subscribing after Destroy is an error.
*/
private static Function<ActivityEvent, ActivityEvent> CORRESPONDING_EVENTS =
new Function<ActivityEvent, ActivityEvent>() {
@Override public ActivityEvent apply(ActivityEvent activityEvent) throws Exception {
switch (activityEvent) {
case CREATE:
return ActivityEvent.DESTROY;
case START:
return ActivityEvent.STOP;
case RESUME:
return ActivityEvent.PAUSE;
case PAUSE:
return ActivityEvent.STOP;
case STOP:
return ActivityEvent.DESTROY;
default:
throw new LifecycleEndedException("Cannot bind to Activity lifecycle after destroy.");
}
}
};

private final BehaviorSubject<ActivityEvent> lifecycleEvents = BehaviorSubject.create();

@Override public Observable<ActivityEvent> lifecycle() {
return lifecycleEvents.hide();
}

@Override public Function<ActivityEvent, ActivityEvent> correspondingEvents() {
return CORRESPONDING_EVENTS;
}

@Nullable @Override public ActivityEvent peekLifecycle() {
return lifecycleEvents.getValue();
}

@Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
lifecycleEvents.onNext(ActivityEvent.CREATE);
}

@Override protected void onStart() {
super.onStart();
lifecycleEvents.onNext(ActivityEvent.START);
}

@Override protected void onResume() {
super.onResume();
lifecycleEvents.onNext(ActivityEvent.RESUME);
}

@Override protected void onPause() {
lifecycleEvents.onNext(ActivityEvent.PAUSE);
super.onPause();
}

@Override protected void onStop() {
lifecycleEvents.onNext(ActivityEvent.STOP);
super.onStop();
}

@Override protected void onDestroy() {
lifecycleEvents.onNext(ActivityEvent.DESTROY);
super.onDestroy();
}
}
Loading

0 comments on commit f9874af

Please sign in to comment.