Android WeakReference - android

I have an activity where i have to trigger from place to place a custom pop-up dialog which is also a singleton
From my activity i open the pop-up :
ScheduleDialog.getInstance().refreshContent(new WeakReference<Context>(this), new WeakReference<ScheduleDialog.interface>(this));
What is best ?
1) create 2 local references ( in ScheduleDialog ) like :
Context mContext = nContext.get();
2) keep both like weak reference and only when i need them use :
nContext.get();
This is related about leaks error/warnings
Thanks

If I see your code you create strong reference again after get weak reference value in Context nContext variable. So need to follow below process if you want to implement weak reference concept :-
define global class variable :-
private final WeakReference< Context > nContext;
set value in global variable through passing from another area
nContext = new WeakReference<Context>(nContext);
and then
if (nContext.get() != null)
// code
}
https://medium.com/google-developer-experts/weakreference-in-android-dd1e66b9be9d

You have to keep them as WeakReferences, otherwise the Garbage Collector will see there are strong references to the object and won't collect them, leading to the leak you mentioned.

Related

Nullable var with `?` vs. lateinit var

What is the best way to define global variables in a Kotlin/Android activity/fragment?
What are the different scenarios when you should use these 2 methods for defining a global variable:
var viewpager: CustomViewPager? = null
or
lateinit var viewpager: CustomViewPager
?
If I use the former, I won't have to check for null in my code. For example if I used lateinit for the following:
viewpager = activity?.findViewById<CustomViewPager>(R.id.viewpager) then I would have to check for null.
using lateinit, you are saying that you absolutely will make sure that an instance of that variable is created somewhere (otherwise, your application will throw an exception if a lateinit has not been initialized) and then that variable also will not be null throughout the rest of your project, compared to using null, it means that this object potentially could be null somewhere in your code for the rest of the project and you will have to deal with nullability throughout.
If you are positive that you are not going to make a variable null and you require an instance of it always, use lateinit
Ask yourself this question :
Am I 100% sure that I will be using an instance of this variable somewhere in this class ?
If the answer to that is Yes, you should probably be using lateinit, as lateinit forces you to create an instance of it.
If the answer is No, you should probably be using a nullable field instead.
Taken from here : https://www.kotlindevelopment.com/lateinit-kotlin/
The lateinit keyword stands for late initialization. Lateinit comes very handy when a non-null initializer cannot be supplied in the constructor, but the developer is certain that the variable will not be null when accessing it, thus avoiding null checks when referencing it later.
i would recommend using the first method, it's better cause it eliminates app crashes if the code is trying to access the viewPager while it was not initialized, you can also use this in order to access the viewPager in the first method to make sure your app won't crash
viewPager?.let{"it"
}
this will create an instance of the viewPager if it was already initialized and use it as a val instead of a var, the instance is called "it" and u can rename it as anything by doing this after the first {
viewPager?.let{viewPager ->
}
If you make sure that variable will never be null in any place of the code then use lateinit. Here you have to initialize it before using it (in your case you can initialize it inside onCreate(..). Make sure that the variable will never become null later ELSE a null pointer exception will be fired.
In this way, you can directly use the variable without checking it if it's null or not.
Also, you can detect if the variable has initialized or not using:
if (:: viewpager.isInitialized) { .... }
On the other hand, you should use the nullable option using ?
In this case, you should check the variable before using it if it's null or not.
you can use ?. for that. You also can combine that with let for example:
viewPager?.let {
....
}

difference between view reference to member variable and local variable

suppose I have an activity, and it contains a TextView. I can initialize the TextView either to a member variable or to a local variable. is there any memory wise difference between these to initialization ?
example :
Activity with local view reference:
public class MainActivity extends Activity{
#OVerride
public void onCreate(Bundle b){
TextView textView = (TextView)findViewById(R.id.my_text_view_id);
}
}
Activity with member view reference:
public class MainActivity extends Activity{
TextView mTextView;
#OVerride
public void onCreate(Bundle b){
mTextView = (TextView)findViewById(R.id.my_text_view_id);
}
}
You should always use the minimal scope. So when you declare a variable you should ask yourself:
"Will I need this variable later in a different function?"
Yes -> Use a member variable
No -> Use a local variable
Edit:
What also to consider is the cost of object creation:
If a function does get called repeatedly it is a good practice to instanatiate an object only once, store it as a member variable and reuse it instead of creating a new instance every time the function gets called.
So the 2nd important question is:
"Will this function get called a lot and do I really need a new instance of the object stored in the variable?"
Yes, often, and no, I can reuse the same object over -> use a member variable. This way the same memory is used and no garbage gets piled up. Use only for large Arrays or objects, it is not needed for simple int vars in loops.
Memory wise global variables are much more prone to memory leaks. The scope any variable depends on its scope. For local variable, the scope is closing braces of the respected method, and variable is automatically garbage collected after the execution of closing braces. Where as global variable will reside in memory until the any object of that class is in memory.
Generally, try to avoid using 'global' variables unless you have good
reason to do .
You can use Local or Global Variable depends upon your Requirement .
Mainly, local variables are that they work within a limited scope means they are declared when a function is called and after ending it the memory taken up by the variable is released.
Finally usage of global variables leads to wastage of memory .

Issue about weakreferences

I have one or two weakreferences in my program.
Just for example:
ClassX myClassX= new ClassX(); //Line 1
WeakReference<ClassX> myWeakClassX = new WeakReference<ClassX>(myClassX); //Line 2
if(myWeakClassX.get() != null) // Line 3
{
//do something with reference //Line 4
}
My question:
How is it ensured that when at line 3 myWeakClassX.get() has a valid reference to an Object, it is also valid at line 4? I can imagine that if you are really unlucky, the GC does his job exactly "between" line 3 and 4. Please bear with me, because i'm relatively new to Android/Java..
Thanks for any explanation.
In Java, first thing to understand is Garbage Collector reclaims memory from objects which are eligible for garbage collection
Question is how is the eligibility defined ?
eligibility is decided based upon which kind of references are pointing to that object.
Why we need Weak Reference ?
If you create a Strong reference to an object, the object cannot be garbage collected. Whereas, A weak reference, simply put, is a reference that isn't strong enough to force an object to remain in memory. Weak references allow you to leverage the garbage collector's ability to determine reachability for you, so you don't have to do it yourself.
Issue here
Weak reference isn't strong enough to prevent garbage collection, so you may find (if there are no strong references to the class) that myWeakClassX.get() suddenly starts returning null.
What is the other option ?
Soft Reference
You use a SoftReference when you want the referenced object to stay alive until the host process is running low on memory. The object will not be eligible for collection until the collector needs to free memory. Loosely stated, binding a SoftReference means, "Pin the object until you can't anymore."
This way myWeakClassX.get() will not be null.
Examples of where we can use ?
In any secondary threads where you create a reference to the activity.
WeakReference weakActivity;
//In AsyncTask onPostExecute Method
Activity activity = weakActivity.get();
if (activity != null) {
// do your stuff with activity here
}
If you can referring to an Activity context elsewhere, you can use Weak reference.
While handling bitmap resources in imageview in another thread
http://developer.android.com/training/displaying-bitmaps/process-bitmap.html
If you are creating any Hashmap or any widget to hold any data, you can use Weak reference. http://developer.android.com/reference/java/util/WeakHashMap.html
Usage is unlimited. It is up to the developer to utilize it at right places.
You are correct that during line 3 and 4 the get() operation can return null, as it is supposed to do. You can always copy the reference you get from get() operation into a variable (thus making it strong again) and use it within the if block safely. Because you still have a strong reference, the object will not be garbage collected.
A simple check for null can be:
if(myWeakClassX.get() != null)
{
ClassX myref = myWeakClassX.get();
if(myref != null) {
//use it
}
}
However in-case of activities, having a strong reference does not guarantee that the activity will not be destroyed and although you have a strong reference that is valid, the activity may throw exceptions when you try to use it as it is destroyed.
Example: If you are keep reference for an activity inside some AsyncTask, the activity might get destroyed (i.e orientation change) before AsyncTask runs. And although you will have a reference to it, you will get exceptions when you try to update UI.
That is where you can create a WeakRefernce to activity inside the AsyncTask and if the get() operation start returning null, you will know that the activity was destroyed by whatever reason and not try to use it.

Is it required to initialize context twice in Android ?

I have seen in many places android context is initialized twice ? Why is it required ?
For Example :
Context context;
context = null;
again they will initialize it to some values in onCreate, onReceive or in some other Method
context = myContext;
If anyway we have to initialize it to value, why then initializing it to null ?
Anything specific to Android ?
Thanks
compiler never assigns a default value to an uninitialized local variable.
If you cannot initialize your local variable where it is declared, make sure to assign it
a value before you attempt to use it. Accessing an uninitialized local variable will result
in a compile-time error.
Example:
someMethod(Context myContext){
Context context;
context = null; //Have to be done to avoid compile-time error
context = myContext;
}
Example 2:
private Context context;
someMethod(Context myContext){
context = myContext; //No initialization required, because context variable is not local
}
To Answer your question:
We are initializing variable to null to keep consistency intact
No, this is not Android specific, but rather Java specific
I would guess this is done of old habits only. Java should by default set field object references to null. I doubt Android handle this differently.
Setting them to null might even result in duplicate operations on byte code level. For further information refer to this page.

Instantiate variables in class instead of onCreate() wrong?

Is something wrong with this construct in Android?
class A extends Activity {
private Object myObject = new Object();
#Override
protected void onCreate(Bundle savedInstanceState) {
//myObject = new Object();
}
}
Because at some point(s) later I get (sometimes, not reproducible yet) exceptions because myObject is null. I don't know if it's because I have to initialize in onCreate.
Edit: Additional details:
The actual class of myObject is List<Object> (Where Object is a domain specific type)
At some point later in the activity I'm storing myObject as a static field of a "Parameter passer" class and starting other Activity (because I'm avoiding to implement Parcelable. If this is good or bad practice should not be discussed here, unless that's causing my error). In the other Activity I pick up myObject. There it's (sometimes) null.
Edit 2: I don't understand why this object becomes null if I'm storing a reference to it as static field of my parameter passer class (a standalone, dedicated class). That's how garbage collection works, right, it just removes when the objects are not referenced anymore. So since I have a static reference this object should not be removed. According to this thoughts, if they are correct, the problem should be somewhere else.
When you start a new activity your old one goes on the block for possible garbage collection (including any classes instantiated in it, including your parameter passer class), so your object is not necessarily going to be available (which is why you see an intermittent failure.).
I see two option:
1) Pass it along in the bundle with your intent that starts the new activity. As you were trying to avoid this, probably not your best choice.
2) Extend the Application class and store the object in there.
EDIT
I think the accepted answer to this SO Question might fix your issue (and explain what is actually happening).
No. That code is just fine. You can create objects in the constructor.
You may want to check a previous question about it Instance variable initialization in java and the section 3.2.4. Field Defaults and Initializers which basically states that the first case:
private Object myObject = new Object();
is identical to an initialization in the class constructor. (NOTICE onCreate is NOT the constructor).
So, myObject should never be null, except in the case the "new Object()" instruction failed, generating an exception.
Isn't this possible your code is changing the contents of myObject later on the code?

Categories

Resources