Implementing a sidebar nav using android architecture components - android

With the new architecture components of android you can't use the default auto generated class navigation drawer class provided by android... why? because it extends from AppCompatActivity to provide the use of support.v7 lib for widgets like toolbar etc. When using now the new architectures component Lifecycleactivity instead of extending AppCompatActivity you can't implement the default navigation drawer class - can anyone give me a workaround or an example how to do this?

From the Lifecycle documentation:
Note: Since the Architecture Components are in alpha stage, Fragment and AppCompatActivity classes cannot implement it (because we cannot add a dependency from a stable component to an unstable API). Until Lifecycle is stable, LifecycleActivity and LifecycleFragment classes are provided for convenience. After the Lifecycles project is released, support library fragments and activities will implement the LifecycleOwner interface; LifecycleActivity and LifecycleFragment will be deprecated at that time.
They go on to provide instructions for implementing a LifecycleOwner, which allows you avoid using LifecycleActivity:
public class MyActivity extends AppCompatActivity
implements LifecycleRegistryOwner {
LifecycleRegistry lifecycleRegistry = new LifecycleRegistry(this);
#Override
public LifecycleRegistry getLifecycle() {
return lifecycleRegistry;
}
}

Related

#ContributesAndroidInjector on a activity that extends CordovaActivity

According to Dagger's doc I can use ContributesAndroidInjector on a concrete Android framework type. I will not be able to extend DaggerActivity as I have a hybrid app and in my case and I am using my activity by extending CordovaActivity. What should be the approach in these scenarios?
Should I fall back to pre 2.10 way of registering the Activity to be injected by Dagger as below on an activity's onCreate().
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
((App)getApplication())
.getAppComponent()
.inject(this);
}
By doing this I have to rewrite my Application class to return appComponent which again defeats the purpose of DI.
Can you please guide me in the right path providing some inputs to handle this scenario.

Getting ViewModel for SettingsActivity (MVVM, Android P)

If you choose template with Settings creating a project in Androdi Studio 3.4, you will see example app with SettingsActivity extending AppCompatPreferenceActivity extending PreferenceActivity extending ListActivity extending android.app.Activity, but not the FragmentActivity which is necessary for creating a ViewModel for SettingsActivityby means of
SettingsViewModel viewModel
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
viewModel = ViewModelProviders.of(this, viewModelFactory).get(SettingsViewModel.class);
}
because of ViewModelProviders.of() may accept only the FragmentActivity as a first argument.
Is it possible to create a ViewModel for AppCompatPreferenceActivity or it is the next reincarnation of hell with preferences from Google?!
This template has been completely redone in Android Studio 3.5 to match the Settings documentation:
The recommended way to integrate user configurable settings into your application is to use the AndroidX Preference Library. This library manages the user interface and interacts with storage so that you define only the individual settings that the user can configure. The library comes with a Material theme that provides a consistent user experience across devices and OS versions.
The AndroidX Preferences Library does not require you to use PreferenceActivity at all - you'll note that it uses AppCompatActivity directly, putting preferences into a PreferenceFragmentCompat. As AppCompatActivity extends FragmentActivity, you will be able to use ViewModel and other AndroidX APIs without issue.

Stuck attempting to implement the official Dagger strategy to avoid cumbersome code

In my efforts to follow the good and official advice for injecting and avoiding cumbersome code (which I had) from the authors themselves, I ran into a wall when trying to use the support library.
According to the article:
AppCompat users should continue to implement AndroidInjector.Factory<? extends Activity> and not <? extends AppCompatActivity> (or FragmentActivity).
I'm sticking to an MVP architecture where views are always Fragments and I don't want to involve my Activity in any DI business, but I wonder if it's necessary for this to work but so far I haven't been able to. If I skip the whole support thing, the app crashes at runtime because the instance of the fragment is support (in case it's not obvious). Then I went into the task of trying to try to implement HasSupportFragmentInjector instead of HasFragmentInjector with a whole bunch of changes due to compile errors my mind has forgotten for the sake of my mental health. After a while I come to a point of thinking how can a non-support Activity host a support fragment. Ah! Those tricky wildcards. But no matter how I've tried to follow the advice, I can't come up with a way without an EmptyModule that I also would need to setup in the Activity so it would be visible to the fragment by dagger and its (really, for me still, magic). Why I haven't tried it? I might as well have, but I'm tired of hopeless changes and I need help at this point.
AppModule.kt
#Singleton
#dagger.Module
class AppModule(val application: Application) {
#Provides #Singleton fun application(): Application = application
...
}
AppComponent.java
#ApplicationScope
#Singleton
#Component(modules = {
AndroidSupportInjectionModule.class,
...
FooFragmentModule.class,
})
public interface AppComponent {
Application app();
...
void inject(MyApp app);
}
MyApp.java
public class MyApp extends Application implements HasActivityInjector {
private AppComponent component;
public AppComponent someWayToReturnAppComponent() {
...
}
#Inject DispatchingAndroidInjector<Activity> dispatchingActivityInjector;
#Override
public void onCreate() {
component = DaggerAppComponent.builder()
.appModule(new AppModule(this))
// more app-scoped modules
.build();
component.inject(this);
}
#Override
public AndroidInjector<Activity> activityInjector() {
return dispatchingActivityInjector;
}
}
MainActivity.java
public abstract class MainActivity extends AppCompatActivity implements HasSupportFragmentInjector {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayout()); // inflate the fragment via XML here
}
#Inject DispatchingAndroidInjector<Fragment> dispatchingFragmentInjector;
#Override
public AndroidInjector<Fragment> fragmentInjector() {
return dispatchingFragmentInjector;
}
}
FooFragmentComponent.java
#Subcomponent
public interface FooFragmentComponent extends AndroidInjector<FooFragment> {
#Subcomponent.Builder
abstract class Builder extends AndroidInjector.Builder<FooFragment> {}
}
FooFragmentModule.kt
#dagger.Module(subcomponents = {FooFragmentComponent.class})
public abstract class FooFragmentModule {
#Binds
#IntoMap
#FragmentKey(FooFragment.class)
abstract AndroidInjector.Factory<? extends Fragment> bindFragmentInjectorFactory(FooFragmentComponent.Builder builder);
#ActivityScope
abstract FooFragment contributeFooFragmentInjector();
#Provides
static FooPresenter presenter() {
return new FooPresenter();
}
}
FooFragment
public class FooFragment extends Fragment implements SomeView {
#Inject FooPresenter presenter;
}
OK. At this point, and going back to
AppCompat users should continue to implement AndroidInjector.Factory<? extends Activity>
I've had no need (and willingly opposing) to use it, only for the fragment. Do I really need to setup a module and component for it or am I missing something?
EDIT
After following EpicPandaForce's advice of using AndroidSupportInjectionModule, Dagger now complains that
FragmentKey methods should bind dagger.android.AndroidInjector.Factory<? extends android.app.Fragment>, not dagger.android.AndroidInjector.Factory<? extends android.support.v4.app.Fragment>.
As #EpicPandaForce mentioned in the comments, you need to use AndroidSupportInjectionModule for support Fragments. You'll also need to use the FragmentKey in dagger.android.support, not the one in dagger.android. That should get you past the problem in your edit.
To your broader point, support Fragments do not extend base Fragments (which are deprecated anyway in API 28 and beyond). This paints them in contrast to AppCompatActivity and its superclass, the support library's FragmentActivity, which both extend the framework Activity as introduced in Android API level 1. Thus, whether you're using support Fragments or built-in Fragments, you might not have a parent AppCompatActivity, but you'll always have an Activity of some sort. This is important because Android reserves the right to instantiate your Fragment using its necessary public no-arg constructor, which means that the Fragment can only self-inject using things that it can find inside onAttach (i.e. its parent fragments, its Activity, or its Application).
dagger.android is unconcerned whether your Activity is an AppCompatActivity because it does not use the Activity other than looking for its own injector. You can see that in the AndroidSupportInjection.findHasFragmentInjector private method, which checks (in order) the hierarchy of parent fragments, then the Activity, then the Application. Consequently, even though practically speaking Support Fragments will only function properly on support Activities, dagger.android can bind its keys based on the superclass Activity because there's no reason to differentiate them and set up two separate maps (Activity vs AppCompatActivity). Even if there were a separation like that, you could bind AppCompatActivity injectors into your Activity map, and everything would get terribly confusing.
You should also take from that search order that if you do not have Activity-scoped bindings, you do not need to create an Activity-scoped component; you can have your Application implement HasSupportFragmentInjector, install your FooFragmentModule directly into AppComponent, and remove HasSupportFragmentInjector from your MainActivity. This is atypical only because most apps have some sense of Activity state or controllers that should be injectable (even just injecting the Activity instance itself, or its Context or Resources). If you only have your #ActivityScope annotation because you're trying to make this work, you can skip that step entirely and only use an Application component and several Fragment subcomponents. However, I think it is very likely that you will eventually need #ActivityScope, so creating a Component for it early-on is pretty reasonable.

Adding functionality to the activity (inheritance, decoration, strategy ... )

I cannot decide what approach should I use in the next situtation.
One activity from my app need to have different functionality, here is the leak of multiple inheritence comes into play.
What I need to get ?
There are several parts that my activity has to have.
Navigation drawer. I am using MaterialDrawer library. It requires activity to implement on click callbacks (or use composition instead), but also it use activity as constructor argument,so I think it will be better to put this into separate class inherited from Activity or any base class provided by Android Framework . Thanks to library developer it doesn't require any stuff to be done in on create method ( setContentLayout for instance)
My activity(one of several) will have only Toolbar and FrameLayout for holding fragment . Or it is better to separate toolbar and single fragment ?
This in turn requires some stuff to be done in onCreate : setContentLayout with basic layout , add fragment to the container set activity actionbar .....
Maybe in future I will use another libraries that requires to add something in activity lifecycle methods.
All these points in order to follow Single Responsibility principle have to be separate classes inherited from some base Activity.
For example we will have something like this.
public class SingleFragmentActivity<T extends Fragment> extends AppCompatActivity {
}
public class SingleFragmentToolbarActivity<T extends Fragment> extends AppCompatActivity {
}
public class NavigationDrawerActivity extends AppCompatActivity {
}
....
As you can see each functionality is put into the separate class, but what if I need to have SingleFramgentActivity with NavigationDrawer ?
In this case I have to inherit one of these classes from another, for example
public class NavigationDrawer extends SingleFragmentActivity {
}
If to do so, I have no ability to use navigation drawer separately from SingleFragmentActivity.
What is the best practice to follow in this case, how to build class hierarchy to make it flexible and use Open-Close principle, to make changes in application without any pain. (Use strategy, decorator ..... ?)
I would be grateful everyone for help.

How to extend two activities in same class?

I'm new to android programming how to extend two activity . In my case I'm using ActionBarActivity
im already extends the a class for some functionalities how shall i extend two activities my class
any example code will be more useful for me
This is not much of a Android problem (as Activity is class as any other), it's the way Java works.
Java doesn't support multiple inheritance, so classes can only extend one other class.
class A extends B{
}
Even in this case:
class A {
}
class A extends another class - Object - but it is automatically implied without having to specify it.
If you want to ensure some functionality from several sources you will have to use interfaces and the implements keyword:
class A extends B implements C,D,E {
}

Categories

Resources