I have an abstract Activity that serves as a basis for other activities:
Since I am settings the content view in the derived Activities and I have common UI elements in all activities, I would like to execute code in the derived Activities after the content view has been set.
How can can I do this in the abstract class without putting the method call in every derived Activity?
abstract public class BaseActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public void methodToBeCalledAfterOnCreateOfDerivedActivity(){
//method that does work on common UI elements, so setContentView() needs to have been called
}
}
public class myActivity extends BaseActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//how can I call this method automatically at the end of this onCreate without explicitly putting the method here:
methodToBeCalledAfterOnCreateOfDerivedActivity();
}
}
The sequence of calls when an Activity is created the first time or the view needs to be recreated is:
onCreate()
onCreateView()
onViewCreated()
onViewStateRestored()
onStart()
onResume()
So, if you only need your method to be called when the view is created, you could do it in onViewCreated(). If you need it to run whenever your activity is restarted, you would do it in onStart().
onStart() is invoked after onCreate(). You can probably put your post-onCreate() functionality there. Use a flag set in the abstract class onCreate() to distinguish between onStart() invocations following onCreate() and onStop()-onRestart().
Related
I am wondering when #ViewById-annotated views are injected in AndroidAnnotations. Basically, I want to know if it is safe to access one of these views during onResume? I assume they are injected during onCreate but would like confirmation.
Thank you.
The easiest way to figure out exactly when injection happens is to inspect the code that AndroidAnnotations generates. For your examples, I made a simple Activity and Fragment as below:
#EActivity(R.layout.activity_main)
public class MainActivity extends AppCompatActivity {
#ViewById(R.id.textView)
TextView textView;
#AfterViews
public void activityTestMethod() {
}
}
#EFragment(R.layout.fragment_main)
public class MainFragment extends Fragment {
#ViewById(R.id.imageView)
ImageView imageView;
#AfterViews
public void fragmentTestMethod() {
}
}
and then ran ./gradlew app:assembleDebug to force AndroidAnnotations to generate the corresponding classes MainActivity_ and MainFragment_. Let's look at MainActivity_ first (irrelevant code omitted):
public final class MainActivity_
extends MainActivity
implements HasViews, OnViewChangedListener
{
#Override
public void onCreate(Bundle savedInstanceState) {
OnViewChangedNotifier previousNotifier = OnViewChangedNotifier.replaceNotifier(onViewChangedNotifier_);
init_(savedInstanceState);
super.onCreate(savedInstanceState);
OnViewChangedNotifier.replaceNotifier(previousNotifier);
setContentView(R.layout.activity_main);
}
private void init_(Bundle savedInstanceState) {
OnViewChangedNotifier.registerOnViewChangedListener(this);
}
#Override
public void setContentView(int layoutResID) {
super.setContentView(layoutResID);
onViewChangedNotifier_.notifyViewChanged(this);
}
#Override
public void onViewChanged(HasViews hasViews) {
this.textView = hasViews.internalFindViewById(R.id.textView);
activityTestMethod();
}
}
The sequence of events that results in our views being bound and our #AfterViews methods being called is as follows:
In onCreate, the MainActivity_ instance is registered as an OnViewChangedNotifier.
onCreate calls setContentView.
setContentView calls notifyViewChanged, which triggers a (synchronous) call to onViewChanged.
onViewChanged binds all fields annotated with #ViewById, then calls all methods annotated with #AfterViews.
Therefore, #ViewById-annotated views are bound and available for use after onCreate has been called, and #AfterViews-annotated methods will be executed at the end of onCreate and before any other Activity lifecycle method.
The story is similar for MainFragment_:
public final class MainFragment_
extends com.stkent.aatest.MainFragment
implements HasViews, OnViewChangedListener
{
#Override
public void onCreate(Bundle savedInstanceState) {
OnViewChangedNotifier previousNotifier = OnViewChangedNotifier.replaceNotifier(onViewChangedNotifier_);
init_(savedInstanceState);
super.onCreate(savedInstanceState);
OnViewChangedNotifier.replaceNotifier(previousNotifier);
}
private void init_(Bundle savedInstanceState) {
OnViewChangedNotifier.registerOnViewChangedListener(this);
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
onViewChangedNotifier_.notifyViewChanged(this);
}
#Override
public void onViewChanged(HasViews hasViews) {
this.imageView = hasViews.internalFindViewById(R.id.imageView);
fragmentTestMethod();
}
}
The sequence of events that results in our views being bound and our #AfterViews methods being called is as follows:
In onCreate, the MainFragment_ instance is registered as an OnViewChangedNotifier.
onViewCreated calls notifyViewChanged, which triggers a (synchronous) call to onViewChanged.
onViewChanged binds all fields annotated with #ViewById, then calls all methods annotated with #AfterViews.
Therefore, #ViewById-annotated views are bound and available for use after onViewCreated has been called, and #AfterViews-annotated methods will be executed at the end of onViewCreated and before any other Fragment lifecycle method.
In both our examples, all view binding is performed in a lifecycle method that occurs much earlier than onResume, so you are safe to access them there :)
I was wondering, during activity re-creation, or fragment re-creation or service re-creation, is there a possibility, that the same instance of class being re-used?
For example
//public class HomeFragment extends Activity {
//public class HomeFragment extends Service {
public class HomeFragment extends Fragment {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Can instrumentSearchMonitor has possibility to become null right here, due to onDestroy?
instrumentSearchMonitor.doSomething();
}
#Override
public void onDestroy() {
super.onDestroy();
instrumentSearchMonitor = null;
}
private InstrumentSearchMonitor instrumentSearchMonitor = new InstrumentSearchMonitor();
}
For the above case, is there a possibility that onCreate will encounter a null object, due to nullify action in onDestroy?
My testing is, after onDestroy is being called, the next call of onCreate will happen on the different class instance.
I was wondering, is there any possibility, that the next call of onCreate, will happen on the same class instance?
Once onDestroy() has been called, the fragment is going to be completely removed and can not be reused.
This can be seen in the Fragment lifecycle:
https://i.stack.imgur.com/fRxIQ.png
In the image you can seee that onDestroyView() can be called, and then it goes back to onCreateView(), but once onDestroy() is called, you're safe to null/delete whatever you want in that class instance.
Put your code above onDestroy
#Override
public void onDestroy() {
instrumentSearchMonitor = null;
super.onDestroy();
}
I need to execute a method before initiating the layout in an activity. If I call the method I need to execute inside onCreate(), would it be executed before the layout is set?
The reason is because I need the method to return a piece of information that is displayed in the layout before initiating it. Would love some feedback on this.
You can do whatever you like before setContentView like so:
public class TestActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
int i = 0;
setContentView(R.layout.main);
}
}
As long as you do not interact with views that have not been inflated yet
For example this is an error:
public class TestActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// ERROR, CAN'T TOUCH UI ELEMENTS
ImageView img = (ImageView)findViewById(R.id.img);
setContentView(R.layout.main);
}
}
Default activity created with Android Studio contains following code
#Override public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Here is code, that executed before layout inflated
setContentView(R.layout.example_activity); //This line inflates layout
}
BTW, you can even remove setContentView and inflate layout programmaticaly.
Do it in onCreate(), preferably before calling setContentView().
However, if the data you want to receive comes from the network, then it will be obtained on a separate Thread (as no network calls can be done on the main Thread). In this situation the layout will almost certainly display before the data is obtained.
A solution would be to obtain the piece of data before you start the Activity, pass it in the Intent as extra and then retrieve in onCreate() using getIntent().getStringExtra()
You are probably inflating your layout in Activity.onCreate() with setContentView(), so you need to put your function call in that method before the call to setContentView().
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
yourFunctionCallHere();
setContentView(R.layout.act_main);
}
I'm designing an architecture where the app needs to execute certain set of operations everytime it goes to background (onPause) and a set of operations everytime it comes back to foreground (onResume), irrespective of the activity (for all the activities). Is there a way with which I can achieve this, without having to call those methods in every activity class' onPause and onResume overrides?
Make your own class that extends Activity and add your desired behavior to its onPause and onResume methods.
Then you extend that class on your activities.
public class BaseActivity extends Activity {
#Override
protected void onPause() {
// ...
}
#Override
protected void onResume() {
// ...
}
}
public class Activity1 extends BaseActivity {
// ...
}
You could extends your Activities by a BaseActivity which extends Activity, and create the two methods onPause / onResume in it.
See this answer for more information.
Ok I am a complete newb when it comes to java classes. I have a public method that dynamically displays some Linearlayouts with some stuff in them. For instance this method (public void methodA)is in ClassA.java, then I want to call methodA from inside ClassB.java. Both of the classes extend Activity and the methodA is being called in the OnCreate method.
ClassA.java
public class ClassA extends Activity{
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
methodA();
}
public void methodA() {
//Do Stuff
/* This uses:
* Package Manager
* Buttons using(this)
* Linear Layouts using(this)
* TextViews using(this)
* findViewById()
* startActivity
*/
}
}
ClassB.java
public class ClassB extends Activity{
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
methodA(); //How do I do this
}
}
It is clear to me that the method is specific to the first activity, which means that it shouldn't be called in the second one. You can either reimplement the method in the second activity or, if these activities are similar (don't do this if they aren't!), you have two options:
Inherit the second activity from the first one.
Merge these two activities into one and use different intents to launch them and act accordingly.
The second method is easier to maintain, so I would prefer it over the first one in simpler cases.
Craete instance of class A in class B and then you can invoke MethodA from class B
public class ClassB extends Activity{
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//MethodA(); //How do I do this
ClassA a=new ClassA ();
a.MethodA();
}
}