I have some trouble to build activities with AndroidAnnotations.
I have a parent Activity named TemplateActivity:
#EActivity(R.layout.activity_template)
#NoTitle
public class TemplateActivity extends Activity
{
// some views
// ...
#ViewById(R.id.main_framelayout)
FrameLayout mainFrameLayout;
#AfterViews
public void postInit()
{
Log.d("DEBUG", "postInit"); // never called, strange...
}
public void setMainView(int layoutResID)
{
mainFrameLayout.addView(LayoutInflater.from(this).inflate(layoutResID, null));
}
}
And in my second Activity, I want to fill mainFrameLayout with anoter layout xml like that :
#EActivity
public class ChildActivity extends TemplateActivity
{
#Override
public void postInit()
{
super.postInit();
setMainView(R.layout.activity_child_one);
}
}
When I want to startActivity, my ChildActivity is blank and postInit was never called.
Can anybody tell me what is wrong? Thanks for advance.
The annotation in your parent class will result in a class TemplateActivity_ with the specified layout. The child class will inherit the "normal" stuff from that parent class, but have its own AA subclass (ChildActivity_). So you should specify the layout to use there as well. Just take a look at the generated classes to see what is going on there.
AA works by generating a new subclass for your annotated classes (e.g. TemplateActivity_ extends TemplateActivity) that contains the code necessary to achieve the results of your annotations. For example, in this class the onCreate() method will instantiate the layout needed, methods annotated with #Background get overridden with another implementation that calls the original method in a background thread. AndroidAnnotations doesn't really do anything at runtime, everything can be seen in the classes it generates, just look into the .apt_generated folder (or wherever you generated the classes to). This can also be helpful if it doesn't quite do what you want, because you can then just take a look at what it does and do it yourself in the way you need it.
In your case, the inheritance hierarchy is like this:
TemplateActivity (with annotations)
L--> TemplateActivity_ (with generated code for the layout)
L--> ChildActivity (your other class, no generated code)
L--> ChildActivity_ (with code generated for the annotations in ChildActivity)
Afaik not all annotations are passed on to subclasses.
Use #EActivity(R.layout.activity_child_one) in the child class and make the parent class abstract. That is working for me.
I think you should make you TempleteActivity an abstract class.
Related
I want to change textView(in mainActivity)'s property like textSize, or textColor.
Then I tried to use it at setting activity.
View view = getLayoutInflater().inflate(R.layout.activity_main, null);
readTextView = view.findViewById(R.id.textView);
And It doesn't work.
Also, I tried to How to update a TextView of an activity from another class this answer. But isn't it can only change the text? If I need to change much property, I have to make a method in my activity.
Android access main activity variables from another class
I referenced this answer.
Declare public static the resource which you want to change.
Use like [Your Activity].[The Resource] at your setting Activity.
I really sorry to question like this... Sorry.
You must not using a public variable as a mechanism to update your View inside an activity because of the following:
You can't ensure that the activity is always exist. There is a probability that the activity is killed by system because of error or you're finishing the activity.
You're coupling your activity with another class. So, each time you're changing the activity there is probability that your change propagate to another class. This probably will introduce bugs to multiple classes.
You better strictly access the View from another class by sending only the view as a parameter. For example, if you have the following activity:
public class YourActivity extends AppCompatActivity {
private TextView mTvName;
...
}
to change the properties of mTvName, you need to create something like this:
public class TextChanger {
public static void maximizeTextSize(TextView tv) {
tv.setTextSize(30);
}
}
then you can use it in your Activity:
TextChanger.maximizeTextSize(mTvName);
If you want to update the TextView from another Activity, you can use startActivityForResult for starting the another Activity. Then you need to receive the result to change your TextView by overriding onActivityResult in your activity.
In case you need to update the TextView without any coupling with another class or Activity, you can use Event Bus mechanism. You can use EventBus library.
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.)
I have 3 activities with the same toolbar. I would like to avoid copying code on each activity. I know I can use <include> tags in every layout in order to reuse the same layout for the toolbar. Now I would like to share the event handlers for each button of the toolbar in all the activities. I am thinking of making a toolbarActivity which extends Activity class and the 3 activities extends toolbarActivity, so in onCreate method, when I call base.OnCreate, all the event handlers would be defined. But, SetContentLayout was not called yet, so base.OnCreate will not find the buttons. Remember the 3 activities have different layouts. Do you know the best way to reuse code in order to avoid copying all the event handlers in OnCreate method for every activity and allowing me to override some functionality?
Android is used on mobile devices so at development time their is no way to know the size and dimensions of the users device. On large devices many UI elements can fit. On smaller devices few UI elements can fit. Your question relates to this dilemma and therefore has many possible answers. Logically for code to work it must exist inside the source, ie you could cut and paste, a bad solution because you end up with many versions of this "same" toolbar or you could refer/reference one "external" toolbar. Fragments come to mind as does having a separate source file. UI source files can be thought of as pairs. Java for dynamic elements and xml for static. So in summary just reference an external fragment that has implemented your toolbar.
If you keep the naming conventions for the buttons and other things in each layout that are tied to the references in your activities then you should have no problem.
For example if you have a '#+id/login_button' in one layout then just use the same convention for the same type of button in the next one and youll be fine.
You could define a base activity which all your other activities extend, and make it implement a click listener (or whatever interface you are using to listen for button presses). You can check the Id of the clicked view and thus provide a callback to perform whatever logic you want.
public class BaseActivity extends Activity implements OnClickListener {
public void onCreate() {
myBtn.setOnClickListener(this);
}
public void onClick(View v) {
if (R.id.my_btn == v.getId()) {
onFoo();
}
}
protected void onFoo() {
// TODO handle foo
}
}
You can then override the method in your subclasses if you need to provide different behaviour.
public class DifferentActivity extends BaseActivity {
#Override protected void onFoo() {
super.onFoo()
// TODO handle foo differently
}
}
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.
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.
}
}