Just getting started with Android development and Java. So, here's the code I'm working with:
package com.example.helloandroid;
import android.app.Activity;
import android.os.Bundle;
public class HelloAndroidActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}
What is the purpose of declaring the onCreate() method here:
public void onCreate(Bundle savedInstanceState) {
Then using super to call the onCreate() method here:
super.onCreate(savedInstanceState);
Doesn't this mean that you are calling the onCreate() method from the Activity class rather than the HelloAndroidActivity class? If so, what is the point of declaring a method with the same name in the HelloAndroidActivity class?
Thanks for any clarification.
In your example, HelloAndroidActivity is a class that inherits from Activity. You are then overriding the base class (Activity)'s onCreate method. Overriding occurs when you define a method in a derived class with the same signature as an existing method in the base class. This means that when I call onCreate on an instance of HelloAndroidActivity, I will execute the HelloAndroidActivity version, and not the base class (Activity)'s version.
The instruction super.OnCreate(savedInstanceState) in the overridden version is explicitly calling the base class's version of the method. What this means is you want HelloAndroidActivity.onCreate to first execute the base class's implementation, then run some more code.
Take the following examples to illustrate this behavior (assume the method Output just outputs something to the screen):
1.
class A
{
public void DoSomething()
{
Output("A");
}
}
In this case, calling A.DoSomething() will output "A".
2.
Assume we still have the class A defined as above, and the following:
class B extends A
{
}
In this case, calling B.DoSomething() will also output "A".
3.
Assume we still have the class A defined as above, and the following instead:
class B extends A
{
#Override
public void DoSomething()
{
Output("B");
}
}
Now, calling B.DoSomething() will output "B".
4.
Assume we still have the class A defined as above, and now this instead:
class B extends A
{
#Override
public void DoSomething()
{
super.DoSomething();
Output("B");
}
}
Now, calling B.DoSomething() will output "A" and then "B".
You are creating a class that inherits from Activity; but you have to define its behaviour, so you tell your class, when created, to call base class to complete all the things that must be done (super.onCreate()), then you set your layout to show your screen/app (setContentView()).
One thing more: take a look at #Override defined right before public void onCreate(Bundle savedInstanceState): override means that you're extending base method to let your derived class do all the work of the base one, including (after) your logic.
Question: What is the purpose of declaring the onCreate() method here?
Answer: The oncreate() method is analogous to main(String args[]) in ususal JAVA. The oncreate activity is called when your Activity starts. So all the initialisations should be done in this method.
You write: public class HelloAndroidActivity extends Activity
This means that you are creating a class - "HelloAndroidClass" that inherits from class = "Activity".
You write: super.onCreate(savedInstanceState);
Java uses the keyword "super" to call constructors from parent class. You are using the concept of overriding here. When you run your code, the oncreate method of base class "HelloAndroidActivity" is executed and not that of parent class - "Activity class".
So you code will first run the base class implementation of oncreate() method(super.oncreate(...)) and then the implementation of derived class.
Question: What is the point of declaring a method with the same name in the HelloAndroidActivity class?
Answer: The super keyword is being used to initialize the objects. The point in redeclaring the same method and using overiding is that you are saved from rewriting the code of base class.
onCreate is sort of your main(String[] args) function in normal Java. It is where you setup your code.
From documentation for onCreate method:
Derived classes must call through to the super class's implementation of this method. If they do not, an exception will be thrown.
See more here for activity methods, lifecycle etc.
Related
This question already has answers here:
How do I share common functions and data across many activities in a single android application
(4 answers)
Closed 2 years ago.
I call a function in onCreate function of an Activity to refactor my code. I wonder where to declare this function that is potentially used in every Activity of my app.
What I have done (it works fine) is to create a function class with a companion object where all my global functions are declared. But my question is: Is it a good way to do like that?
I call a function in onCreate function of an activity to factor my
code. I wonder where to declare this function that is potentially used
in every activity of my app.
I would create a BaseActivity and let all your Activities inherit from it.
abstract class BaseActivity : AppCompatActivity() {
private fun init() {
// your code
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
init()
}
}
In case your init function does not depend on anything which comes from the subclass, you can just invoke it in onCreate each time (as shown above), otherwise make it protected and call it from the subclass (with parameters).
What I have done (it works fine) is to create a Function class with a
companion object where all my global functions are declared. But my
question is : is it a good way to do like that ?
It depends on if you need global shared state or not. In the first case using an object or a companion object would not be a bad idea.
If you don't need global state, or what to pass in whatever state to the utility function itself, a top level function would be sufficient.
Utils.kt
fun someUtilityFunction(foo: Int) {
// ...
}
You can create some BaseActivity or YourAppNameActivity and call your function inside its onCreate. Then, every activity that extends BaseActivity as usually will call super.onCreate() and therefore the code you need
As long you do not have shared (mutable) state (as it can lead to side effects, there is nothing wrong in placing common code into companion object.
You can have a BaseActivity you extend your Activities from, but I would try to avoid inheritance in favor of composition.
If your method is touching the activity's view then BaseActivity approach would be fine. But if it doesn't move it to some singleton ActivityHelper class.
Like said, BaseActivity approach (inheritance) comes with a cost. You should be able to make good design choices by not putting everything inside it which will eventually makes it more coupled.
Follow composition pattern only if you find your code is interfering with its lifecycle. There are a few registerLifecycle callbacks for activity or fragment that can help you.
It's a good practice to move all that common code to a parent class and make each activiy heredate that parent class, by the way creating a companion object its a good option only if you want to create a singleton, a singleton it's needed when you want to instance that object only once.
For example a function in baseActivity (parent class) to create an intent filter or add code to onCreate function
public class BaseActivity extends Activity {
public static final String FINISH_ALL_ACTIVITIES = "somecode";
public final IntentFilter INTENT_FILTER = createIntentFilter();
private boolean _started;
private IntentFilter createIntentFilter() {
IntentFilter filter = new IntentFilter();
filter.addAction(FINISH_ALL_ACTIVITIES_ACTIVITY);
return filter;
}
// region Blindaje de eventos ciclo de vida
#Override
protected void onCreate(Bundle savedInstanceState) {
// inside your activity (if you did not enable transitions in your theme)
getWindow().requestFeature(Window.FEATURE_CONTENT_TRANSITIONS);
super.onCreate(savedInstanceState);
try {
doOnPostCreate(savedInstanceState);
} catch (Throwable t) {
doOnErrorNoControlado(t);
}
}
I am studying a Dagger 2 from many sources such as this one: http://fernandocejas.com/2015/04/11/tasting-dagger-2-on-android/
but I still haven't found an answer to my question.
I work on quite complex application with tens of fragments and several activities in which I want to use DI (dagger 2). For all of those fragments and activities I have one BaseActivity and one BaseFragment. However, as far as I read and tried, in order to use #Inject in my let's say MainActivity, I have to specify it in Component interface and also invoke getApplicationComponent().inject(this) in onCreate method. When I do this for BaseActivity only, #Inject annotated fields in MainActivity is never injected. And what is even worse, I do not find out about that until that specific part of code is executed and NPE is thrown.
So far it is a deal breaker for me, because this can be source of many crashes. I would need to specify tens of fragments and activities in Component interface and not forget to call inject in each onCreate method.
I would be very glad to hear any solution to this since I would really like to use DI..
code example:
#Singleton
#Component(modules = ApplicationModule.class)
public interface ApplicationComponent {
void inject(BaseActivity baseActivity);
Analytics analytics();
}
public class BaseActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.getApplicationComponent().inject(this);
}
}
public class MainActivity extends BaseActivity {
#Inject
Analytics analytics;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
analytics.log("event1"); // THROWS NPE!
}
}
You can not inject properties in your subclass by injecting the super (since dagger2 works at compile time and there is no way to dynamically check subclasses for annotated properties.)
You can move analytics up to the super, then it will be injected there. To inject annotated fields in your subclass you will have to call the injection there again.
You can make an abstract method in your baseclass e.g. inject(App app)where you just handle the injection. That way you can't 'miss' it.
As stated in the official documentation:
While a members-injection method for a type will accept instances of its subtypes, only Inject-annotated members of the parameter type and its supertypes will be injected; members of subtypes will not.
move the
#Inject
Analytics analytics;
to your BaseActivity class, the Analytics object is initialized in the superclass and is inherited by sub-classes automatically, therefor u wouldn't get null any more.
public class MainActivity extends BaseActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
analytics.log("event1");
} }
In the docs, it says I should make the new class like this:
class MyView extends GLSurfaceView {
public MyView(Context context) {
super(context);
setRenderer(renderer);
}
}
Now I tried to re-do that in Scala:
class BaseGameActivity extends Activity {
object glview extends GLSurfaceView(this) {
setRenderer(renderer)
setEGLContextClientVersion(2)
}
}
However, the App crashes now with the exception "java.lang.IllegalStateException: setRenderer already called for this instance". I suspect this has to do with the way Scala calls the super-constructor.
I've tried to find out how to override the constructor in the way the docs describe, but couldn't find it. I'd appreciate any hint.
It seems to me that your are propagating the call to a different constructor from the base class. You are passing a reference to this instead of a reference to the Context object. It might be that this other constructor is calling setRenderer.
Could you try to create an inner class MyGLView like this:
class MyGLView(ctx: Context) extends GLSurfaceView(ctx) {
setRenderer(renderer)
}
And see what happens?
The problem is that object does not allow arguments to its constructor. Top-level objects must be initializable without any arguments (nobody calls their ctors). In your case you have an inner object, which can reference the members of the surrounding class instance. If you really need an inner object in your Activity class, you could do:
object glview extends GLSurfaceView(ctx) {
setRenderer(renderer)
}
where ctx is a member of the surrounding class.
In java likewise in scala constructors are not inherited.
So you can not override thing, you didnt inherit. And you should use one of existing constructors for base class. If all of them are calling setRenderer(renderer) it will be called during constructing super object and you obviously should not call it second time in a subtype constructor ( wheither it class, object or mixing-in trait ).
I have defined a function in MainActivity now I want to access the function from another class in my app. I have created an object of the MainActivity and with that object I have called the function. Although there is no error, it's not executing. Every time I try to execute, the app crashes.
Activity A should have a variable
static ActivityA activityA;
In onCreate state:
activityA = this;
and add this method:
public static ActivityA getInstance(){
return activityA;
}
In activity B, call
ActivityA.getInstance().myFunction(); //call myFunction using activityA
You cannot just create objects of Activities by using:
MyActivity activity = new MyActivity();
as you would with normal Java classes. All Activities in Android must go through the Activity lifecycle so that they have a valid context attached to them.
By treating an Activity as a normal Java class, you end up with a null context. As most methods in an Activity are called on its Context, you will get a null pointer exception, which is why your app crashes.
Instead, move all such methods which need to be called from other classes into a Utility class which accepts a valid context in its constructor, and then use that context in the methods to do the work.
Make the variable public and then create object in adapter like this:
public int i; // Variable in Activity class
((ActivityName) context).i // accessing in adapter
I have an Activity which mainly handles the UI, and I do most of the rest from another class (not a service). One of the things I do from that class is playing audio. What I need to do is tell my Activity when the audio finished playing (OnCompletionListener).
public class MyClass implements OnCompletionListener {
private MyActivity activity = new MyActivity();
public MyClass(){
}
...........
...........
...........
#Override
public void onCompletion(MediaPlayer mp) {
activity.onComplete();
}
}
This is wrong because "Cannot make a static reference to the non-static method onComplete() from the type MyActivity.
I'm pretty sure I'm using Java wrong, but I cant figure out how to call onComplete from the class. (changing onComplete to static isn't posible).
EDIT:
added a constructor to MyActivity:
public MyActivity(){
}
and created an instance of MyActivity, activity (see the edited code above), passed it to the method, but when I do activity.onComplete(); it stops unexpectedly. (I dont know why my logcat isnt working, I'll post back when I get it to work)
Just pass an instance of MyActivity to MyClass and call a method on it. It's arguable approach but best I can suggest having information that you provided.