Common tasks in Activities methods - how to organize them? - android

I have some common actions fired in onPause() and onResume() methods. (Like registering and unregistering BroadcatsReceivers)
Now I put them in abstract classes and extend Activity classes.
After creating some abstract classes with common actions I end up with situation when I can't extend Activity because of Java's lack of multiple inheritance.
How you deal with such things? Do you duplicate code or do something smarter?
I'm wondering if it's wider problem - not only concerning Android, but Java language.

Task A and Task B are two separate tasks. But to be used in just one class. So you can just have a single abstract class. The abstract may not be necessary if you feel that there are no functions that will have to be overridden in the child class.
If for some reason there may be a task D, which uses Task A alone, then you can do the following:
public abstract class ExtendedAbstractActivityA extends Activity
{
public void TaskA() {}
public void TaskB() {}
//Other abstract classes
}
You can call these tasks individually from your respective classes.

Related

What is an AbstractActivity in android?

What is an Abstract Activity in android? This question was asked at one of the interview. I tried searching about this at androidxref unfortunately not able to found.
Can any one help to answer this , Thanks!!
There is no such term in Android system called AbstractActivity.
Abstract activity is any activity which has been marked as abstract.
And like any other abstract java class, it cannot be instantiated and hence it will fail if passed as intent to startActivity() method. Also Android Studio will not allow you to declare such activity in the manifest file.
These abstract activities are mostly used by some android libraries to declare abstract methods and provides any method implementations useful for its task like login mechanism.
One of the advantage of this approach over an interface is that it can make use of activity callback methods.
As in comments the purpose of AbstractActivity is same as abstract class in java, which cannot be used directly(direct instance creation is not possible).
Using abstract activity you can define a group functionality for app activity screens.
For example,
LoginScreen: Abstract activity holding some functions defined
UserLoginScreen: specific ui/function for common user
AdminLoginScreen: specific ui/function for admin user

Dagger 2 - how to avoid code repetition for injecting dependencies that require activity context

The project I'm working on has a number of utility classes that require activity context.
I don't want to have to declare a new #Provides method for each activity that uses the dependency. i.e. I don't want this:
#Provides
static Navigator providesNavigator(ActivityOne activity) {
returns new Navigator(activity);
}
// ...and in another module
#Provides
static Navigator providesNavigator(ActivityTwo activity) {
returns new Navigator(activity);
}
So instead I declare these utilities in a single ActivityUtilitiesModule and pass our BaseActivity which all other activities extend. Now i don't have to declare my Navigator dependency x number of times.
#Provides
static Navigator(BaseActivity activity) {
return new Navigator(activity);
}
However, Dagger does not know how to satisfy the dependency for BaseActivity. This means for every Activity i need to create a provides method that will satisfy the BaseActivity dependency with the specific Activity being used. e.g.:
#Provides
static BaseActivity providesBaseActivity(ActivityOne activity) {
return activity;
}
This is better - I only need to repeat this one provider per activity, rather than repeating a provider for every utility class per activity, but it still feels like an unwelcome additional step in Dagger set up, and another thing that makes the code harder to understand.
Is there a pattern which allows me to avoid having to supply this BaseActivity provider per activity?
Please use Constructor Injection. Having provide* methods that only call the constructor are only noise and code to maintain. Add #Inject to the class constructor and possible scopes onto the class.
#SomePossibleScope
class Navigator {
#Inject
Navigator(Activity activity) { }
}
If you do this, you probably don't need your ActivityUtilitiesModule at all.
If your class depends on an Activity or BaseActivity then you need to provide it. And yes, you will have to tell Dagger about it in some way.
If you were to use an abstract class or interface you should make use of #Binds instead.
#Binds BaseActivity bindsBaseActivity(ActivityOne activity);
Compared to #Provides Dagger might optimize this code further, reducing the number of method calls and object creations, as well as a few less lines of code.
I don't know why your Utils depend on the Activity, but if they would only need a Context then you could also just provide the application context to them without a need to bind or provide your actual Activity.
I personally just bind the current Activity to the types it implements using the syntax above. And if you're using Constructor Injection properly that's more often than not the only lines of code that you'll find in my modules, making them very readable.

Android Dagger 2 with BaseActivity to reduce boilerplate

I'm having some troubles while I want to move some Dagger 2 boilerplate code in each activity to a BaseActivity.
BaseActivity extends AppCompatActivity
I have multiples activities, like:
ActivityA extends BaseActivity implements InterfaceA;
ActivityB extends BaseActivity implements InterfaceB;
...
In each activity I have a methods like this (where X is A, B, C, ... for each activity):
public void initActivity() {
ComponentX compX;
...
compX = appComponent.plus(new ModuleX(this)); // this == InterfaceX
...
compX.inject(this); // this == ActivityX
}
I was trying to reduce this code, moving it to the parent BaseActivity. But I'm having some problems to do it. I think that maybe with generics I could do it, but I don't know exactly how.
Here's the question: Which inject method are you calling, and can Java determine that at compile time?
As described in "A note about covariance", Dagger will generate code for any members-injection method you define, but only the static type you pass in.
#Component public interface YourComponent {
void injectBase(BaseActivity baseActivity);
void injectA(ActivityA activityA);
void injectB(ActivityB activityB);
void injectC(ActivityC activityC);
}
When calling injectA and passing an ActivityA instance, you'll get injection for the fields defined in ActivityA including the fields in BaseActivity. Same with ActivityB and ActivityC. However, if you call injectBase, Dagger will only inject the fields belonging to BaseActivity, even if the object you pass in happens to be an ActivityA, ActivityB, or ActivityC. Dagger generates code at compile time, so if you call injectBase, the injection will only happen for the fields on BaseActivity—because that's the code that was generated for BaseActivity's members injector, and those are the only fields Dagger knows how to inject for a BaseActivity parameter.
Naturally, because BaseActivity only knows that this is a subtype of BaseActivity, it can only call injectBase and not any specific subtypes. Importantly, this remains true even if all the names injectBase, injectA, and so forth, are all the same (like inject). The JVM will pick the narrowest overload it can determine at compile time, which will be inject(BaseActivity), which will inject BaseActivity's fields and nothing in subtypes. If you were to name them uniquely, you'd see which one you're calling, and why it's not injecting subtype fields.
Generics won't help here: You're looking for your Component to generate and call members injectors for ActivityA, ActivityB, and ActivityC. Generics will be erased, but furthermore the component can't take an arbitrary subclass of BaseActivity: Dagger can't generate code at compile time for types it might only encounter at runtime. You really need to prepare those types in Dagger at compile time.
One way around this is to allow the subtypes to inject themselves. The subtypes know that this is ActivityA (and so forth), and even though the code might look character-for-character the same, Java can identify the right type and compile it correctly.
// in BaseActivity
protected abstract void injectDependencies();
// in ActivityA
#Override protected void injectDependencies() { component.injectA(this); }
However, there's another recently-released option, using dagger.android, which uses Multibindings and (effectively) a Map<Class, MembersInjector> to dynamically inject the specific type you want. This works from a superclass, too, to the point that you can have your Activity extend DaggerActivity and everything will work just the way you'd like. (Consult the dagger.android.support package for your AppCompatActivity equivalent DaggerAppCompatActivity.)

Dagger 2: Scoping and handling release/cleanup of provided injection

Is it possible to scope this and provide a release method in the module or elsewhere to prevent memory leaks. Ex. I need to close a database connection in onDestroy() but it would be nice if this could be handled by the module itself.
Consider the following example* code.
*Read the error prone code at your own risk
Module
#dagger.Module
#lombok.NoArgsConstructor
public class PersistenceModule {
#Provides
#Singleton
DatabaseProvider providesDatabaseHelper(Context context) {
return new DatabaseProvider(context);
}
}
Activity
public class SomeActivity extends Activity{
#javax.inject.Inject DatabaseProvider provider;
//..onCreate omitted where injection happens.
#Override
protected void onDestroy() {
//Close database and cleanup.
provider.release();
provider = null;
super.onDestroy();
}
}
Your sample seems error-prone, as you are scoping your DatabaseProvider with a #Singleton scope, but use and clean it up in an activity.
A Module just helps creating objects—especially if there is no injectable constructor or it needs further initialization—and is not aware of further lifecycle events. It supplies its objects to a Component, which just holds and creates the object graph needed to inject your classes. In the end both are just plain old java objects and a scope on a component is nothing more than syntactic sugar helping with compile time validation.
In any case, you should handle your cleanup at the same scope that you provide your dependency. #Singleton scope should therefore be cleaned up in the application object that is also holding the application component. If you clean up a singleton scoped object in an activity, the next activity accessing it would be accessing an object in a closed state.
If every activity should have its own accessor and clean it up after being used, then you should switch to some activity based scope. Additional scopes are just annotations that you can create yourself.
The actual cleanup
All this said, I would not include "clean up" logic in my modules, because most people would not expect to find it there.
#Module
Annotates a class that contributes to the object graph.
Dagger is a dependency injection framework that provides dependencies for easier usage of interfaces and looser coupling of your classes. It is to reduce boiler plate code of object creation and what you do with the actual objects once you have them should not belong to the same code base creating them.
While it would still be possible to keep references to you modules, or make them implement some interface (still pojos!) and call them to clean up themselves in onDestroy it would probably lead to more confusion than just doing the cleanup where others would expect it.

android how to create my own Activity and extend it?

I need to create a base class that extends Activity which does some common tasks in my application and extend my activities from it,in the following form:
public BaseActivity extends Activity{....}
public SubActivity extends BaseActivity{...}
in SubActivity I need to give values to some variables and UI components defined in BaseActivity, I may need to define a different layout for SubActivity according to some flag value, also(in SubActivity ) I want to execute asyncTask that is defined in BaseActivity.
is this possible? if yes, is there any tutorial that may help?
thank you in advance
What exactly are you trying to achieve? Having two different activities with a common ui, except for some variables or parts of the layout?
In this case, I suggest having a base abstract activity, and two concrete inherited subclasses. You define all the common behaviour in the base activity, and have abstract methods for the differences, which you then override in your actual implementations.
For example, for two activities with different layout resources:
public abstract class BaseActivity extends Activity {
#Override
public void onCreate(bundle) {
super.onCreate(bundle);
setContentView(getLayoutResourceId());
}
protected abstract int getLayoutResourceId();
}
public class Activity1 extends BaseActivity {
#Override
public void onCreate(bundle) {
super.onCreate(bundle);
// do extra stuff on your resources, using findViewById on your layout_for_activity1
}
#Override
protected int getLayoutResourceId() {
return R.layout.layout_for_activity1;
}
}
You can have a lot more abstract methods, for every bit you want specific to your subclasses.
Doing that is, in my opinion, a lot better than having a concrete subclass to a concrete superclass: that can lead to many problems and is usually difficult to debug.
This question already has very good answers.
However. my answer is for those people who are looking for some working example.
Here is the full working -> CODE
We are not doing anything new here, it is just like any other inheritance scenario (You want some common behavior at multiple places but you want to write that behavior only once).
ADVANTAGE:
It does provide better code readability, maintainability and blah blah. But are not after these -ibility, They won't matter to you if your brain runs like a gazelle.
We are after the real power of inheritance “CONTROL”. (That’s what happens in real life too. Parent controlling child :) ) .
In my example, I have two Activities MainActivity and OtherActivity.
Both Activities has a different layout but I want both of them to start with some animation or some welcome message.
Our first task is to find out the common behavior.
here -> Start Activity with animation.
We have found the common “thing”, now we will write that behavior in BaseClass (AnimationActivity).
MainActivity and OtherActivity will inherit AnimationActivity.
So the code would look like `
BaseActivity
AnimationActivity {
startAnimation()
{
....
}
}
Child Activities
MainActivity extends AnimationActivity{
}
OtherActivity extends AnimationActivity{
}
This design approach provides a lot of Control and Flexibility (POWER OF MODIFIER).
1) CONTROL: Keep animation method inside onCreate()
When you decide that Activities should be started with Animation.
Keep your method inside onCreate(Bundle bundle) method. Now just by changing the modifier, you can control the child Activities.
If you keep modifier as
final: Child activities will start with parent Animation.
abstract: Child activities will have to give their own animation.
no modifier: Child activities can have their own animation by overriding animation method, Otherwise the child will have parent animation.
2)Flexibility: Don't keep animation method inside onCreate()
You can provide child activities flexibility by not keeping animation method inside onCreate(Bundle bundle).
Now activities can have the flexibility to have parent Animation or their own animation or no animation at all.
Hope it helps.
Happy learning.
`
Yes you can, you should just keep in mind the basic inheritance rules. You will inherit the inner AsyncTask activity and the properties defined in the BaseActivity if you make them protected instead of private. From what I see now I think you should make BaseActivity an abstract class, as only instances of subActivities will be really used.
You should just start and try it, it'll come and work easier than you think. If you stumble upon any problems, just ask.
I have found an easier way to #Guillaume's solution. Set ContentView only once in your BaseActivity and do not set it in the activities that extend it:
public abstract class BaseActivity extends Activity {
#Override
public void onCreate(bundle) {
super.onCreate(bundle);
setContentView(activity_main);
}
}
public class Activity1 extends BaseActivity {
#Override
public void onCreate(bundle) {
super.onCreate(bundle);
// setContentView(activity_activity1) // Do NOT call this.
}
}

Categories

Resources