I guess this is a lame question, I can't even make up a proper subject! Here is what I'm trying to do under Android:
public void onCreate(Bundle savedInstance) {
...
AskFilename ask = new AskFilename();
...
}
Here, AskFilename class will present a user interface to let the user enter a filename. However, the ask object will be out of scope once the onCreate() method returns. So this means there will be no reference to ask any more (assuming inside AskFilename class, I did not assign its this pointer to any other variable), and so GC will, sooner or later, "collect" it. When this happens, if the user hasn't OK'ed the dialog box, the code in AskFilename is already unavailable and therefore the system will crash. Is my understanding correct?
(I can't think of a way to experiement with this idea, because I don't know how to make GC do its job. It seems that GC kicks in only when it wants to! Is there a way to make it do its job?)
If the above is correct, then what is the proper way to new a UI-related object? I know I can make evrything inside AskFilename static, or I can make ask a static vairable and assign it to null when it's done. But is there any other way? Or, the idea itself is bad in the first place?
(Does it make any difference if AskFilename is an "inner" class of the Activity? Like MyActivite.AskFilename.)
Thank you in advance.
Firstly, you can just put the declaration AskFilename ask; outside of the method declaration, i.e. as a member of your class. Then you initialise it with ask = new AskFilename(); in your onCreate method.
However, the thing to know is that your constructor probably won't look like that. Every Android UI component contains a callback (a reference) to the thing containing it. You typically do this by passing a Context to the constructor of a UI component- inside an Activity, the context is usually just the Activity itself, so you just use the this keyword. e.g:
TextView tv = new TextView(this);
However you construct your AskFilename dialog, I expect you will need to pass the Context down to its components. So your constructor will probably need to take a Context argument:
ask = new AskFilename(this);
Additionally, your Activity will hold references (implicitly) to all of its UI components, and dialogs it shows with onCreateDialog() So your object won't get picked up by the GC.
It gets these references either when you call setContextView or make the dialog.
Related
What is the proper way to call view's method:
findViewById(R.id.btn_Foo).setVisibility(View.GONE);
vs
Button fooBtn = (Button) findViewById(R.id.btn_Foo);
fooBtn.setVisibility(View.GONE);
As I understand correctly, as a general Java code efficiency rule, one should use variables. But in this case, what if the view method called only once - does it mean that calling setVisibility without defining a variable is more effcient?
does it mean that calling setVisibility without defining a variable is more effcient?
Performance-wise, the efficiency of the two approaches are almost, if not completely, the same, if that's what you mean by "efficient".
If "efficient" means the time it takes to write the code, then of course the first approach is more efficient.
But in this case, what if the view method called only once
As a general rule, when you want to use the foo button later in the code, you want to make it a variable. If you just want to use it once, it's fine to not declare a variable. However, not needing to use an object twice now does not mean you won't need to use it again next month. It is very possible that next month, you found a bug in your code or you want to add a new feature and now you need to use foo button twice. If you haven't declared fooButton as a variable a month ago, you would have to declare it now.
So unless you are 200% sure that foo button will never be used again in the same scope, make it a variable. It is a View after all, and you tend to refer Views very often.
I've looked around but never found a straightforward answer to this question. I'm wondering what would happen if I use a pattern that requires me to pass a Context to static methods to do things on the backend. For instance:
public static Observable<CreateThing> createNewThing(String thingName, Context context) { // Passing Context in
return RestNetworker.handleResponse(ServiceGenerator.createService(Service.class).createThing(thingName))
.doOnNext(response -> DatabaseHelper.getInstance(context).createThing(new Thing(response.getThingId(), thingName))); // context used to get instance of DatabaseHelper
}
This method makes an API call and then writes the object to the database locally after a success response. However, I need to pass a Context to create the instance of the database helper. I could alternatively pass the database helper itself, but then I'd be creating the instance (rather getting it, since it's singleton) in the Activity code and I'd rather not do that either.
My question really is: If, say, a user exits the Activity while the API call is in progress, will this Context instance get GC'd and result in an NPE when the response comes back? I've done this kind of thing before and never noticed that issue, but it really seems that there should be some consequence of doing this. I know that other developers must do some things off the UI thread that require a Context, so this should be a relatively easy question to answer.
Thanks guys! Please let me know if you need any more information to provide better context. Heh.
The rule is that you do not pass an instance of the Activity to some object that may keep a reference to it outside of the lifecycle of the Activity. This will cause a memory leak, as the GC will not be able to free the memory allocated to the Activity and the entire view tree contained within. In those instances you pass getApplicationContext().
In cases where the context will only be referenced for the duration of the method call, passing the Activity as this is fine.
In your case, it seems like DatabaseHelper may store a reference to the context, so I would use getApplicationContext() Note that you would not get NPE because the reference was GC if you passed an Activity, that doesn't make sense - if the DatabaseHelper was storing a strong reference, this could not occur (at least on the reference to the Activity itself).
In Android/Java, if I have a button, I can add a click listener two ways -
1)
Button button = findViewById(R.id.my_button);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
-- or --
2)
Button button = findViewById(R.id.my_button);
button.setOnClickListener(this);
I sometimes prefer option #2, mainly because of brevity, but am curious about the performance considerations of essentially passing the entire class/context to the Listener...
Does anyone have any thoughts/experience in regards to this ?
I think both methods are valid
All depends on what you want to do. For example, if you have many buttons on a screen and you choose to use the first option, for each button you'll need a new object to handle the click. In contrast to the second option, with the same object (activity) as a listener, you'll consume fewer resources because it would be creating fewer objects (Java).
On the other hand, remember that the view holds a reference to context.
The latter approach is obviously more efficient: All it does is passing a reference to this, an already existing object, to setOnClickListener, which will then be used to call onClick.
The first approach is slightly less efficient as it creates a new object, an instance of an anonymous inner class. The creation of a new object and the existence of an additional class is the main difference.
You might also produce some overhead using the first approach when dealing with variable transactions between the surrounding class and the anonymous inner class. Most issues, e.g. threading related problems, affect both approaches.
Summing up, there is no real performance difference. If you are going to create a lot of buttons, you should consider sharing a single instance of a View.OnClickListener.
I usually prefer anonymous inner classes (up to a limited size), because it separates the code that actually belongs to the surrounding class from the code related to the listener.
The actual contents of your listener implementation will affect the performance way more than the call to setOnClickListener. From the perspective of setOnClickListener, both calls are equal as they both pass an instance of a class implementing View.OnClickListener, whether reused or created.
If one has no intention of using a parameter in C++, one simply omits the name of the variable but keeps the type in the function declaration. Doing so is a light-weight method to signal to the compiler that one intends not to use a given parameter.
Is this possible to replicate in Java?
The scenario is this: I would like not to flood my code with #SuppressWarnings("unused") for every single button listener (because button listeners most often ignore the View v they receive), and yet I would like to be warned in general about the silly mistake of, say, not initializing a member variable by a parameter.
I can't think of anything like the C++ option but you could extend/implement your button listener and add a new method without the parameter and have that method called in the original event method. This way you will only have to suppress warnings once.
public void someEvent(Parameter p) {
someEvent();
}
public void someEvent() {
}
In addition to creating an adapter like #Farzad suggested, you might want to also check your compiler settings in your IDE. For example, I use Eclipse and there are error/warning compiler settings under Window->Preferences->Java Compiler->Errors/Warnings. Within that dialog you can set UnnecessaryCode->Value of parameter is not used->Ignore in overriding and implementing methods.
Having that option checked automatically ignores those unused params when they are from a method that you are implementing/overriding such as in your listener case. I generally find that to be sufficient without needing to create an adapter.
I understand that Android Activities have specific lifecycles and that onCreate should be overridden and used for initialization, but what exactly happens in the constructor? Are there any cases when you could/should override the Activity constructor as well, or should you never touch it?
I'm assuming that the constructor should never be used because references to Activities aren't cleaned up entirely (thus hampering the garbage collector) and that onDestroy is there for that purpose. Is this correct?
I can't think of any good reason to do anything in the constructor. You never construct an activity directly, so you can't use it to pass in parameters. Generally, just do things in onCreate.
A good reason for putting things in the constructor as Gili's comment had stated is the use of final fields.
However, if you initialize things in the constructor, then the lifespan of the object will be a little bit longer, though I don't think by much because the onCreate would be called shortly thereafter.
Although it's against my ideal, I do avoid the constructor for initialization of the activity members and rely on onResume() and onPause() for resources that my app is dealing with.
For onCreate() I usually use it to do view mapping to local variables. Though android-annotations already does that for me so I rarely have an onCreate() method for my Activity. I still use it in Service though.
However, if you look at the members you may be initializing
they would have a "close" method that you have to invoke at the proper time (onResume or onPause)
they would be part of the view which means it needs to be initialized then onCreate needs to be called
they are constants which don't need to be put in the constructor anyway, just a static final would do. This includes Paint and Path constants which can be initialized by a static block
I am now on a case that needs to override the constructor. In fact, I have some activities that have the same structure. So instead of creating many activities, I'll create one "Master" activity and the others will inherit this one. So I need to override the constructor of the child activity to be able to initialize some variables that will be used in the oncreate methods.
In two words, the constructor makes you simulate a "masteractivity" that can be reused by inheritance!
You need to override the Constructor when your activity will have custom params or you want to track calls from classes that inherited from.