Giter Site home page Giter Site logo

jakewharton / u2020 Goto Github PK

View Code? Open in Web Editor NEW
5.7K 326.0 932.0 9.17 MB

A sample Android app which showcases advanced usage of Dagger among other open source libraries.

Home Page: https://www.youtube.com/watch?v=0XHx9jtxIxU

License: Apache License 2.0

Shell 0.09% Java 99.91%

u2020's Introduction

U+2020

A sample Android app which showcases advanced usage of Dagger among other open source libraries.

Watch the corresponding talk or view the slides.

The ObjectGraph is created in the U2020App's onCreate method. The Modules class provides a single method, list, which returns the list of module instances to use.

In order to add functionality in the 'debug' version of the app, this class is only present in the release/ and debug/ build type folders. The 'release' version only includes the U2020Module while the 'debug' version includes both U2020Module and DebugU2020Module, the latter of which is only present in the debug/ build type folder and is an override module.

Through the use of Dagger overrides, the 'debug' version of the app adds a slew of debugging features to the app which are presented in the Debug Drawer™. The drawer is opened by a bezel swipe from the right of the screen. From here you can change and view all of the developer options of the application.

The drawer is provided by the simple interface ViewContainer. This is an indirection that the single activity uses to fetch its container into which it can place its content. The default implementation returns the Android-provided content view. The 'debug' version overrides this with DebugViewContainer which is responsible for creating the drawer, adding it to the activity, and returning its content view group. It also injects all of the developer objects and binds them to controls in the drawer.

The most notable feature the 'debug' version exposes is the concept of endpoints. Using the spinner at the top of the drawer, you can change the endpoint to which the app communicates. We also expose a false endpoint named "Mock Mode" which simulates an in-memory server inside the app. This "Mock Mode" eases manual testing and also provides a static set of data to write instrumentation tests against.

"Mock Mode" can be queried when modules are configuring their dependencies which is what allows simulating the remote server in-memory.

@Singleton class MockFoo() {
  @Inject MockFoo() {}
  // ...
}
@Provides @Singleton Foo provideFoo(@IsMockMode boolean isMockMode, MockFoo mockFoo) {
  return isMockMode ? return mockFoo : new RealFoo();
}

See DebugDataModule and DebugApiModule to see this in action in the real app.

The mock implementations of these types are some of those injected into the DebugViewContainer for binding in the drawer. This allows us to do things like control their fake network behavior and alter their behavior.

In order to keep the shared state which represents the server-side data we use a ServerDatabase singleton. At present this is only done with a combination of in-memory collections and images in the debug/assets/. In a more complex app you could even use a full database. This class is injected into each mock service which uses its methods to query and mutate state (e.g., MockGalleryService).

Debug drawer

Libraries

To Do

  • Something with animations to showcase animation control.
  • Network errors probably crash the app.
  • Add another part of the app other than 'trending' so we can demo child graphs.

License

Copyright 2014 Jake Wharton

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.

u2020's People

Contributors

aried3r avatar carlrobert avatar chris-horner avatar danielkutik avatar esmasui avatar f2prateek avatar felipecsl avatar friederbluemle avatar guillaumedelente avatar httpdispatch avatar jakewharton avatar jaynewstrom avatar kamoljan avatar kisty avatar krschultz avatar mattprecious avatar michaelevans avatar nathanielwolf avatar nightlynexus avatar pyricau avatar rafaeltoledo avatar runningcode avatar seanponeil avatar sebastienrouif avatar something15525 avatar steffandroid avatar tasomaniac avatar turbo87 avatar vovkab avatar xfumihiro avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

u2020's Issues

I can't build the app

@JakeWharton:

I just tried building the project and failed.

Running gradle:

10:05:52.806 [ERROR] [org.gradle.BuildExceptionReporter] FAILURE: Build failed with an exception.
10:05:52.807 [ERROR] [org.gradle.BuildExceptionReporter] 
10:05:52.807 [ERROR] [org.gradle.BuildExceptionReporter] * Where:
10:05:52.807 [ERROR] [org.gradle.BuildExceptionReporter] Build file '/Users/csessa/Documents/u2020/build.gradle' line: 17
10:05:52.808 [ERROR] [org.gradle.BuildExceptionReporter] 
10:05:52.808 [ERROR] [org.gradle.BuildExceptionReporter] * What went wrong:
10:05:52.809 [ERROR] [org.gradle.BuildExceptionReporter] A problem occurred evaluating root project 'u2020'.
10:05:52.809 [ERROR] [org.gradle.BuildExceptionReporter] > Could not create plugin of type 'AppPlugin'.
10:05:52.812 [ERROR] [org.gradle.BuildExceptionReporter] 
10:05:52.812 [ERROR] [org.gradle.BuildExceptionReporter] * Exception is:
10:05:52.813 [ERROR] [org.gradle.BuildExceptionReporter] org.gradle.api.GradleScriptException: A problem occurred evaluating root project 'u2020'.
10:05:52.814 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.groovy.scripts.internal.DefaultScriptRunnerFactory$ScriptRunnerImpl.run(DefaultScriptRunnerFactory.java:54)
10:05:52.814 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.configuration.DefaultScriptPluginFactory$ScriptPluginImpl.apply(DefaultScriptPluginFactory.java:132)
10:05:52.815 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.configuration.project.BuildScriptProcessor.execute(BuildScriptProcessor.java:38)
10:05:52.815 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.configuration.project.BuildScriptProcessor.execute(BuildScriptProcessor.java:25)
10:05:52.816 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.configuration.project.ConfigureActionsProjectEvaluator.evaluate(ConfigureActionsProjectEvaluator.java:34)
10:05:52.816 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.configuration.project.LifecycleProjectEvaluator.evaluate(LifecycleProjectEvaluator.java:55)
10:05:52.817 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.api.internal.project.AbstractProject.evaluate(AbstractProject.java:507)
10:05:52.818 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.api.internal.project.AbstractProject.evaluate(AbstractProject.java:82)
10:05:52.818 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.configuration.DefaultBuildConfigurer.configure(DefaultBuildConfigurer.java:31)
10:05:52.819 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.initialization.DefaultGradleLauncher.doBuildStages(DefaultGradleLauncher.java:142)
10:05:52.819 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.initialization.DefaultGradleLauncher.doBuild(DefaultGradleLauncher.java:113)
10:05:52.820 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.initialization.DefaultGradleLauncher.run(DefaultGradleLauncher.java:81)
10:05:52.821 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.launcher.exec.InProcessBuildActionExecuter$DefaultBuildController.run(InProcessBuildActionExecuter.java:64)
10:05:52.821 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.launcher.cli.ExecuteBuildAction.run(ExecuteBuildAction.java:33)
10:05:52.822 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.launcher.cli.ExecuteBuildAction.run(ExecuteBuildAction.java:24)
10:05:52.822 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:35)
10:05:52.823 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.launcher.exec.InProcessBuildActionExecuter.execute(InProcessBuildActionExecuter.java:26)
10:05:52.823 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.launcher.cli.RunBuildAction.run(RunBuildAction.java:50)
10:05:52.824 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.api.internal.Actions$RunnableActionAdapter.execute(Actions.java:171)
10:05:52.825 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.launcher.cli.CommandLineActionFactory$ParseAndBuildAction.execute(CommandLineActionFactory.java:201)
10:05:52.825 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.launcher.cli.CommandLineActionFactory$ParseAndBuildAction.execute(CommandLineActionFactory.java:174)
10:05:52.826 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.launcher.cli.CommandLineActionFactory$WithLogging.execute(CommandLineActionFactory.java:170)
10:05:52.827 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.launcher.cli.CommandLineActionFactory$WithLogging.execute(CommandLineActionFactory.java:139)
10:05:52.827 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.launcher.cli.ExceptionReportingAction.execute(ExceptionReportingAction.java:33)
10:05:52.828 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.launcher.cli.ExceptionReportingAction.execute(ExceptionReportingAction.java:22)
10:05:52.828 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.launcher.Main.doAction(Main.java:46)
10:05:52.829 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.launcher.bootstrap.EntryPoint.run(EntryPoint.java:45)
10:05:52.829 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.launcher.Main.main(Main.java:37)
10:05:52.830 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.launcher.bootstrap.ProcessBootstrap.runNoExit(ProcessBootstrap.java:50)
10:05:52.830 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.launcher.bootstrap.ProcessBootstrap.run(ProcessBootstrap.java:32)
10:05:52.831 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.launcher.GradleMain.main(GradleMain.java:23)
10:05:52.831 [ERROR] [org.gradle.BuildExceptionReporter] Caused by: org.gradle.api.plugins.PluginInstantiationException: Could not create plugin of type 'AppPlugin'.
10:05:52.832 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.api.internal.plugins.DefaultPluginRegistry.loadPlugin(DefaultPluginRegistry.java:61)
10:05:52.832 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.api.internal.plugins.DefaultPluginContainer.providePlugin(DefaultPluginContainer.java:103)
10:05:52.832 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.api.internal.plugins.DefaultPluginContainer.addPluginInternal(DefaultPluginContainer.java:68)
10:05:52.833 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.api.internal.plugins.DefaultPluginContainer.apply(DefaultPluginContainer.java:34)
10:05:52.834 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.api.internal.plugins.DefaultObjectConfigurationAction.applyPlugin(DefaultObjectConfigurationAction.java:101)
10:05:52.835 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.api.internal.plugins.DefaultObjectConfigurationAction.access$200(DefaultObjectConfigurationAction.java:32)
10:05:52.836 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.api.internal.plugins.DefaultObjectConfigurationAction$3.run(DefaultObjectConfigurationAction.java:72)
10:05:52.837 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.api.internal.plugins.DefaultObjectConfigurationAction.execute(DefaultObjectConfigurationAction.java:114)
10:05:52.838 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.api.internal.project.AbstractPluginAware.apply(AbstractPluginAware.java:39)
10:05:52.839 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.api.Project$apply.call(Unknown Source)
10:05:52.839 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.api.internal.project.ProjectScript.apply(ProjectScript.groovy:34)
10:05:52.840 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.api.Script$apply.callCurrent(Unknown Source)
10:05:52.841 [ERROR] [org.gradle.BuildExceptionReporter]    at build_500n45a0386fgftenmqsfsk4gs.run(/Users/csessa/Documents/u2020/build.gradle:17)
10:05:52.842 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.groovy.scripts.internal.DefaultScriptRunnerFactory$ScriptRunnerImpl.run(DefaultScriptRunnerFactory.java:52)
10:05:52.842 [ERROR] [org.gradle.BuildExceptionReporter]    ... 30 more
10:05:52.843 [ERROR] [org.gradle.BuildExceptionReporter] Caused by: java.lang.NoClassDefFoundError: org/gradle/api/artifacts/result/ResolvedComponentResult
10:05:52.844 [ERROR] [org.gradle.BuildExceptionReporter]    at com.android.build.gradle.AppPlugin.$getStaticMetaClass(AppPlugin.groovy)
10:05:52.845 [ERROR] [org.gradle.BuildExceptionReporter]    at com.android.build.gradle.BasePlugin.<init>(BasePlugin.groovy:1712)
10:05:52.846 [ERROR] [org.gradle.BuildExceptionReporter]    at com.android.build.gradle.AppPlugin.<init>(AppPlugin.groovy:73)
10:05:52.846 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.api.internal.DependencyInjectingInstantiator.newInstance(DependencyInjectingInstantiator.java:62)
10:05:52.847 [ERROR] [org.gradle.BuildExceptionReporter]    at org.gradle.api.internal.plugins.DefaultPluginRegistry.loadPlugin(DefaultPluginRegistry.java:59)
10:05:52.848 [ERROR] [org.gradle.BuildExceptionReporter]    ... 43 more
10:05:52.849 [ERROR] [org.gradle.BuildExceptionReporter] Caused by: java.lang.ClassNotFoundException: org.gradle.api.artifacts.result.ResolvedComponentResult
10:05:52.849 [ERROR] [org.gradle.BuildExceptionReporter]    ... 48 more

There is an android issue for this: https://code.google.com/p/android/issues/detail?id=65155

To go around this, I downgraded com.android.tools.build:gradle to 0.7.+

Now I get:

Caused by: org.gradle.api.internal.MissingMethodException: Could not find method provided() for arguments [com.squareup.dagger:dagger-compiler:1.2.0] on root project 'u2020'.

Following http://blog.codeaholics.org/2012/emulating-mavens-provided-scope-in-gradle/ I added:

configurations {
    provided
}

sourceSets {
    main.compileClasspath += configurations.provided
    test.compileClasspath += configurations.provided
    test.runtimeClasspath += configurations.provided
}

This makes the app build but I get this error when I run the app:

E/AndroidRuntime(10390): java.lang.RuntimeException: Unable to create application com.jakewharton.u2020.U2020App: java.lang.IllegalStateException: Module adapter for class com.jakewharton.u2020.U2020Module could not be loaded. Please ensure that code generation was run for this module.
E/AndroidRuntime(10390):    at android.app.ActivityThread.handleBindApplication(ActivityThread.java:4347)
E/AndroidRuntime(10390):    at android.app.ActivityThread.access$1500(ActivityThread.java:135)
E/AndroidRuntime(10390):    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256)
E/AndroidRuntime(10390):    at android.os.Handler.dispatchMessage(Handler.java:102)
E/AndroidRuntime(10390):    at android.os.Looper.loop(Looper.java:136)
E/AndroidRuntime(10390):    at android.app.ActivityThread.main(ActivityThread.java:5017)
E/AndroidRuntime(10390):    at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime(10390):    at java.lang.reflect.Method.invoke(Method.java:515)
E/AndroidRuntime(10390):    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
E/AndroidRuntime(10390):    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
E/AndroidRuntime(10390):    at dalvik.system.NativeStart.main(Native Method)
E/AndroidRuntime(10390): Caused by: java.lang.IllegalStateException: Module adapter for class com.jakewharton.u2020.U2020Module could not be loaded. Please ensure that code generation was run for this module.

Where should the provided come from rather than configurations {}?

I am using:

  • java version "1.7.0_51"
  • Gradle 1.9

Move SDK version details from AndroidManifest.xml to gradle

Personally I prefer to keep all these version numbers and so on outside of the AndroidManifest.xml and hence would suggest to move

src/main/AndroidManifest.xml(line 7):

<uses-sdk
      android:minSdkVersion="14"
      android:targetSdkVersion="19"/>

into build.gradle(line 60)

defaultConfig {
    ...
    minSdkVersion 14
    targetSdkVersion 19

What do you think?

Add search

This allows us to demonstrate a complex RxJava as-you-type pipeline and gives the nav drawer a reason to actually be in the app (besides making the keylines look right).

Debug drawer width needs increased

When compared to internal on my Nexus 4, the drawer is not as wide as it should/could be. I want the full width (minus 56dp) on my N4.

OOM Error

Playing around with this app I got fatal exeption.

Here is stacktrace:

Process: com.jakewharton.mu2020.dev, PID: 3946
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.jakewharton.mu2020.dev/com.jakewharton.u2020.ui.MainActivity}: android.view.InflateException: Binary XML file line #8: Error inflating class
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2305)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2363)
at android.app.ActivityThread.access$900(ActivityThread.java:161)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1265)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:157)
at android.app.ActivityThread.main(ActivityThread.java:5356)
at java.lang.reflect.Method.invokeNative(Native Method)
at java.lang.reflect.Method.invoke(Method.java:515)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1265)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1081)
at dalvik.system.NativeStart.main(Native Method)
Caused by: android.view.InflateException: Binary XML file line #8: Error inflating class
at android.view.LayoutInflater.createView(LayoutInflater.java:626)
at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:702)
at android.view.LayoutInflater.rInflate(LayoutInflater.java:761)
at android.view.LayoutInflater.inflate(LayoutInflater.java:498)
at android.view.LayoutInflater.inflate(LayoutInflater.java:398)
at android.view.LayoutInflater.inflate(LayoutInflater.java:354)
at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:359)
at android.app.Activity.setContentView(Activity.java:2010)
at com.jakewharton.u2020.ui.debug.DebugAppContainer.get(DebugAppContainer.java:178)
at com.jakewharton.u2020.ui.MainActivity.onCreate(MainActivity.java:21)
at android.app.Activity.performCreate(Activity.java:5426)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1105)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2269)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2363)
            at android.app.ActivityThread.access$900(ActivityThread.java:161)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1265)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:157)
            at android.app.ActivityThread.main(ActivityThread.java:5356)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:515)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1265)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1081)
            at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Constructor.constructNative(Native Method)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at android.view.LayoutInflater.createView(LayoutInflater.java:600)
            at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:702)
            at android.view.LayoutInflater.rInflate(LayoutInflater.java:761)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:498)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:398)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:354)
            at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:359)
            at android.app.Activity.setContentView(Activity.java:2010)
            at com.jakewharton.u2020.ui.debug.DebugAppContainer.get(DebugAppContainer.java:178)
            at com.jakewharton.u2020.ui.MainActivity.onCreate(MainActivity.java:21)
            at android.app.Activity.performCreate(Activity.java:5426)
            at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1105)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2269)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2363)
            at android.app.ActivityThread.access$900(ActivityThread.java:161)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1265)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:157)
            at android.app.ActivityThread.main(ActivityThread.java:5356)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:515)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1265)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1081)
            at dalvik.system.NativeStart.main(Native Method)
Caused by: java.lang.OutOfMemoryError
at android.graphics.Bitmap.nativeCreate(Native Method)
at android.graphics.Bitmap.createBitmap(Bitmap.java:903)
at android.graphics.Bitmap.createBitmap(Bitmap.java:880)
at android.graphics.Bitmap.createBitmap(Bitmap.java:847)
at com.jakewharton.madge.MadgeCanvas.setColor(MadgeCanvas.java:82)
at com.jakewharton.madge.MadgeCanvas.(MadgeCanvas.java:44)
at com.jakewharton.madge.MadgeFrameLayout.(MadgeFrameLayout.java:24)
            at java.lang.reflect.Constructor.constructNative(Native Method)
            at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
            at android.view.LayoutInflater.createView(LayoutInflater.java:600)
            at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:702)
            at android.view.LayoutInflater.rInflate(LayoutInflater.java:761)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:498)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:398)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:354)
            at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:359)
            at android.app.Activity.setContentView(Activity.java:2010)
            at com.jakewharton.u2020.ui.debug.DebugAppContainer.get(DebugAppContainer.java:178)
            at com.jakewharton.u2020.ui.MainActivity.onCreate(MainActivity.java:21)
            at android.app.Activity.performCreate(Activity.java:5426)
            at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1105)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2269)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2363)
            at android.app.ActivityThread.access$900(ActivityThread.java:161)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1265)
            at android.os.Handler.dispatchMessage(Handler.java:102)
            at android.os.Looper.loop(Looper.java:157)
            at android.app.ActivityThread.main(ActivityThread.java:5356)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:515)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1265)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1081)
            at dalvik.system.NativeStart.main(Native Method)

What did I do ?
Just switch frequently between Production and Mock Mode endpoints. after few switches it crashes.

I'm completely new to Dagger, could you please help me to figure out why does this happens and how to prevent it ?
Thanks.

Open drawer by clicking toolbar navigation icon

From TrendingView.java:

  toolbarView.setNavigationOnClickListener(new OnClickListener() {
      @Override public void onClick(View v) {
        // TODO bind to drawer with... injection?
      }
    });

How are you guys planning to implement this binding with MainActivity.drawerLayout?

Typically I'm doing this the following way:
ActivityConnector binds to Activity livecycle with attach/detach (e.g. called from onStart/onStop), holds reference to some object in Activity. Simply it looks like this:

public class ActivityConnector<T> {
  private WeakReference<T> ref;

  public void attach(T obj) {
    ref = new WeakReference<T>(obj);
  }

  public void detach() {
    ref = null;
  }

  public T get() {
    return ref == null ? null : ref.get();
  }
}

More robust implementation can be found here.

This approach can be used to bind drawerLayout:

public final class MainActivity extends Activity {
  @Inject ActivityConnector<DrawerLayout> drawerConnector;

  @InjectView(R.id.main_drawer_layout) DrawerLayout drawerLayout;

  @Override protected void onStart() {
    super.onStart();
    drawerConnector.attach(drawerLayout);
  }

  @Override protected void onStop() {
    super.onStop();
    drawerConnector.detach();
  }
}

in TrendingView.java:

@Inject ActivityConnector<DrawerLayout> drawerConnector;
@InjectView(R.id.trending_toolbar) Toolbar toolbarView;

@Override protected void onFinishInflate() {
   super.onFinishInflate();
   ButterKnife.inject(this);

   toolbarView.setNavigationIcon(R.drawable.menu_icon);
   toolbarView.setNavigationOnClickListener(new OnClickListener() {
     @Override public void onClick(View v) {
       DrawerLayout drawer = drawerConnector.get();
       if (drawer != null) {
         drawerLayout.openDrawer(Gravity.START);
       }
     }
   });
}

What do you think about that?

Drop Observables from GalleryService

Have the GalleryService class simply return the raw types, which are then wrapped into observables by the GalleryDatabase.

 @GET("/gallery/{section}/{sort}/{page}") //
 Gallery listGallery( //
      @Path("section") Section section, //
      @Path("sort") Sort sort, //
      @Path("page") int page);

Main advantage would be that the mock implementation of GalleryService wouldn't have to worry about dealing with producing the observables.

Any thoughts?

Add nav drawer

Mostly so that the keylines work... but we can probably add another screen to show something cool and let you switch between them.

Switch to SVGs

Either MrTelly or Victor for now, and the VectorDrawable support library backport in the future.

Debug drawer widgets should be updated onResume to keep in sync with SharedPreferences

If you go to a second activity (ensuring that the previous activity is not destroyed), and change a setting in the debug drawer (such as latency), then go back to the first activity, the UI widgets in the debug drawer get out of sync with the preferences that back them since the widgets are only initialized in onCreate().

I've worked around this in my application by removing the @singleton annotations from the DebugAppContainer class and the module that provides it, and adding a second method bind() so the interface for AppContainer looks like this:

ViewGroup get(Activity activity);
void bind(Activity activity);

Then I call bind() in onResume of my activity.

This adds a fair amount of complexity but is kind of necessary.

Please let me know if you're interested in a PR.

Provide examples for unit tests

I struggle to find a good reference for how Dagger is used to inject dependencies in unit tests, especially when fragments and activities are involved.

I believe we're at our 3rd round of rewriting this in our app (we finally moved away completely from the clunky and verbose approach where you inject into the test class using a test module), and would be interested to see what Square suggests here.

FWIW:
We went back to cutting out Dagger from unit tests and having @VisibleForTesting constructors on fragments, and then pass in mocks manually in unit tests. In the default ctor, the one Android would invoke, we then inject the object graph and have package visible fields with @Inject annotations. That introduces a weird split though between how dependencies are resolved (manually in tests, via Dagger in prod.)

Folder Structure

Question: This is the first time I've seen a three directory structure. Do classes in the same package in the debug folder not get built as a part of a release build (like how there's a Modules.java in both debug and release)? Is that a feature of gradle?

Not an issue, more of a question, but Github would let me tag it as a question. :\

Thanks!

Gradle build failed

Error:(45) A problem occurred evaluating root project 'u2020-master'.

Cannot run program "git" (in directory "D:\Android\u2020-master"): CreateProcess error=2, The system cannot find the file specified

occurs at this line:
def gitSha = 'git rev-parse --short HEAD'.execute([], project.rootDir).text.trim()

Add user authentication

This allows

  • Grabbing the user photo for the nav drawer.
  • Starring and unstarring repos from the app.
  • Concrete demonstration of contextual debug actions.

How to use dagger-compiler validation with current architecture of injection?

Hello @JakeWharton. I am trying to implement compile-time assertable Dependency Injection using Dagger.

Your injection architecture seems better than usage of Scoped Graphs when we use one objectGraph but adding required modules using objectGraph.plus(modules) from each place where we need an injection.

But, both of architectures (Your: with one Module which includes other modules and Scoped Graphs) are not supported by dagger-compiler..

For example, try to remove MainActivity.class from injects of UiModule and code will be compilable, but you'll got this at runtime:
java.lang.IllegalArgumentException: No inject registered for members/com.jakewharton.u2020.ui.MainActivity. You must explicitly add it to the 'injects' option in one of your modules.

Is there an option to use one ObjectGraph and have validation of injects declarations from dagger-compiler?

Also, as I understand, @cgruber can help with this :)

GalleryDatabase TODO

Can you please provide us with reusable component from comment: "pull underlying logic into a re-usable component for debouncing and caching last value"? I can somehow create it by myself but I'd really appreciate if you shown your way of doing that, because now I'm rebuilding our project due to Square-kind of architecture solutions and want to know how you work this kind of problem out.

Dagger 2 support

The differences between Dagger 1 and 2 are not trivial, so would be nice if this sample used Dagger 2 instead of Dagger 1.

Debug Drawer GridLayout Overflow

I just ran into the problem that my debug drawer layout was too wide, the value column was overflowing.

The fix is simple though: for all Views in the value column the width needs to be set to 0dp and the layout-gravity needs an additional fill_horizontal.

So e.g.

<Spinner
  android:id="@+id/debug_network_delay"
  android:layout_gravity="start|end|center_vertical" />

becomes

<Spinner
  android:id="@+id/debug_network_delay"
  android:layout_width="0dip"
  android:layout_gravity="fill_horizontal|start|end|center_vertical" />

See also this link: http://daniel-codes.blogspot.de/2012/01/gridlayout-view-clipping-issues.html

Update Readme

  • New GIF
  • Update mention of MockGalleryService
  • Ensure library list is up-to-date
  • Describe flavors

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.