Android Attempt to read from field on a null object reference - android

I have an Activity with some Fragments used in a ViewPager, sometimes user sends me some crash report that i don't understand.
I can not produce this crash and most of the user have no problem at all.
The crash Log says:
java.lang.NullPointerException: Attempt to read from field 'com.mehdok.views.treeview.TreeNode$TreeNodeClickListener com.mehdok.mafatih.MainActivity.nodeClickListener2' on a null object reference
The nodeClickListener2 is in my main activity:
public TreeNode.TreeNodeClickListener nodeClickListener2 = new TreeNode.TreeNodeClickListener()
{
#Override
public void onClick(TreeNode node, Object value)
{
TreeViewHolderNoBorder.TreeViewItem item = (TreeViewHolderNoBorder.TreeViewItem) value;
if(node.isLeaf() && !item.nodeNavUri.equals(""))
{
openNodePage2(item);
}
}
};
And in fragmets i use it like this:
tView.setDefaultNodeClickListener(((MainActivity) getActivity()).nodeClickListener2);
What can i do to prevent this crash?
tnx in advance.

Where do you access your activity field from your fragment? You should do it starting from onAttach() up until onDetach().
If you try to access it too soon like in your constructor or in your fragment's onCreate(), this would explain the crash. Same if you try to access it after the fragment is detached from the Activity.

That is possible, sometimes Activity will be recycled, when you call getActivity() in Fragment, it will return null. so before you call getActivity() you can write code as below:
if (isAdded()) {
tView.setDefaultNodeClickListener(((MainActivity) getActivity()).nodeClickListener2);
...
}

Related

How to get LifecycleOwner in a Fragment?

I need to get the LifecycleOwner to pass it in my FirestoreRecyclerViewOption but Fragment doesn't implement Lifecycle.
So, how to get that?
My Fragment implements LifecycleOnwer as shown in the following code example,
public class ListRestFragment extends Fragment implements LifecycleOwner
after in the onCreateMethod,
lifecycleRegistry = new LifecycleRegistry(this);
lifecycleRegistry.setCurrentState(Lifecycle.State.CREATED);
and to finish
#Override
public void onStart() {
super.onStart();
lifecycleRegistry.setCurrentState(Lifecycle.State.STARTED);
}
#NonNull
#Override
public Lifecycle getLifecycle() {
return lifecycleRegistry;
}
I follow this example
but it doesn't work
Attempt to invoke virtual method 'androidx.lifecycle.Lifecycle$State androidx.lifecycle.Lifecycle.getCurrentState()' on a null object reference
I need it to edit My FirestoreRecyclerViewOption and setLifeCycleOwner because it is always null and I have an NullPointer everytime.
In fragments you can use getViewLifecycleOwner() method to get the lifeCycleOwner.
Update: Actually it is better to use getViewLifeCycleOwner if you are using views in your observers. Because the view might not exist when the LiveData gets updated and you want to change the view(e.g. changing visibility of a view) which causes crashes.
The fragment itself is the LifecycleOwner you are looking for. You can use keyword "this" as a reference to the fragment.
Read this: "Lifecycle
is a class that holds the information about the lifecycle state of a component (like an activity or a fragment) and allows other objects to observe this state."
And:
"LifecycleOwner is a single method interface that denotes that the class has a Lifecycle."

What is the best place to call getContext()?

I was reading fragment documentation and found this:
Caution: If you need a Context object within your Fragment, you can call getContext(). However, be careful to call getContext() only when the fragment is attached to an activity. When the fragment isn't attached yet or was detached during the end of its lifecycle, getContext() returns null
So my question is what is the best place to call getContext() inside the fragment. Like i can call it in onCreateView, or onCreate() or onAttach() on any other place.
I am asking this because recently I got a crash of null pointer using getContext in my fragment. So I thought I should create a global Context object and access it inside the fragment. But then I came across this text from official documentation so I am a bit confused what would be the best place to initialize this Context object.
It all depends what you need that Context for. Sometimes it's just fine to call getApplicationContext(), in other cases it may be needed to use what you are given in onAttach() or call getActivity() if you are in Fragment code. Some are also providing own Application subclass, exposing static method like getAppContext().
In any case, AVOID saving the context as it may lead to memory leak. Get it dynamically when needed only.
As a lot of wrong answers are given, I'll provide what's the best way to handle context inside fragments.
The best solution is checking if the context has a value whenever you need it.
You can do it by wrapping the code in which you access the fragment in 2 ways:
if (getContext() != null) { /* code here */ }
or, as stated in the documentation there's this method:
isAdded()
which: "Return true if the fragment is currently added to its activity." -reference
Again: please AVOID saving the context in a local fragment's variable.
You can do something like this in your fragment.
#Override
public void onAttach(Activity activity) {
// TODO Auto-generated method stub
super.onAttach(activity);
// After this point the context is initialized.
context=activity;
}
NOTE: I don't really get it why it is so not liked this answer.
First af all, depending on the version of android(which was not mentioned), of course the OnAttach is deprecated, it has to be checked.
Next:
I think that if you need cobntext somewhere, you can make a private or protected variable in Fragment, so the context is destroyed when it is garbage collected.
protected MainActivity activity;
Make sure you hold this variable dearly and its reference is not passed to other classes.
This should do the job.
You can implement your logic like this :
private Context mContext;
#Override
public void onAttach(Context context) {
super.onAttach(context);
mContext = context;
}
#Override
public void onDetach() {
mContext = null;
super.onDetach();
}
When you required to use context,
if(mContext != null) {
//Add your logic here
}

Get parent activity in DialogFragment subclass before show()

I am working on an android application with many dialogs, all of which extend a custom class called "DialogFragmentBase" which extends the library's "DialogFragment". All activities use the show() method overridden in DialogFragmentBase.
I want to prevent showing the dialogs if the parent activity is backgrounded (as in receiving a phone call) since that results in the illegalStatEexception, but at the same time I don't want to guard every show() call in the application with:
if(getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED))
So I wanted to do something like this in the DialogFragmentBase:
#Override
public void show(FragmentManager manager, String tag){
List<Fragment> fragments = manager.getFragments();
if(fragments != null && fragments.size() > 0){
FragmentActivity activity = fragments.get(fragments.size()-1).getActivity();
if(activity != null && activity.getLifecycle().getCurrentState().isAtLeast(Lifecycle.State.RESUMED)){
super.show(manager, tag);
}
}
}
So my question is: Is accessing the previous fragment like that considered a bad practice? It does work...but I remember reading somewhere that fragments shouldn't intercommunicate. If it is indeed a bad practice, what would be a better solution that can be implemented in the DialogFragmentBase (to avoid adding guards everywhere).
Note: I tried the onSaveInstanceState solution described here, but since the DialogFragment hasn't been shown yet, the onSaveInstanceState isn't called for it at that point. Also getActivity() returns null since onAttach hasn't been called yet at that point.
Thanks!
The support library FragmentManager has an isStateSaved() method. Depending on exactly what your requirements are, you could leverage this to check if it is "safe" to show your dialogs:
#Override
public void show(FragmentManager manager, String tag) {
if (!manager.isStateSaved()) {
super.show(manager, tag);
}
}
Note that the above implementation is relatively similar to using commitAllowingStateLoss(), in that you'll silently fail to show your dialog in certain cases. But perhaps that is fine for your requirements.
Perhaps you could create a new method in your dialog base class:
public void showIfResumed(FragmentActivity activity, String tag) {
if (/* your check here, e.g. activity.getLifecycle()... */) {
show(activity.getSupportFragmentManager(), tag);
}
}
And then, in your activities, rather than calling show(getSupportFragmentManager(), TAG), you could call showIfResumed(this, TAG). You'll still have to change every call to show() to a call to showIfResumed(), but this would reduce the code duplication considerably.

Fragment loses Activity while networking (android)

I initiate most of my networking calls from Fragments and then use callbacks to tell the Fragment whether or not the networking task succeeded or failed and to update ui accordingly.
On rare occassions (.25% of sessions) my program is crashing with a null-pointer exception due to getActivity() returning null when the code in my callback runs. I know that I can use a null check on getActivity() to prevent this from happening, however what's the best practice for handling this issue?
The null check seems to be little more than a crash prevention tool as the program still needs the data from the networking task.
The code looks something like the following:
private void queryServer() {
// networking task should query server for user id, if successful store it
// in user preferences to be accessed by fragment in callback
new networkingTask(new VolleyCallback() {
#Override
public void onSuccess() {
// code below needs null check on getActivity - but what else?
mUserId = new UserPreferences(getActivity()).getUserId();
}
#Override
public void onFail() {
// booooo
}
});
}
As I stated in my comment above, what is likely happening is the Activity/Fragment pair are being stopped or destroyed by the system. This will happen for a variety of reasons, such as a screen orientation change. Because your handler is a method on the fragment object, you are working with a "dead" fragment by the time the call returns. There are several patterns for dealing with this. In short you need to make your handler aware of the current fragment, and you can accomplish this by using lifecycle methods.
Below is an example of a pattern you could use. I tried to make the example as minimal as possible.
import android.app.Activity;
import android.app.Fragment;
public class MyFragment extends Fragment {
// This is static so that it will not go out of scope when the original
// fragment is destroy. This allows it to be access from all MyFragment
// instances.
static MyResponseProcessor processor = new MyResponseProcessor();
// This will be the class that handles your network call.
public static class MyResponseProcessor {
// This instance variable is alway a reference to the currently displayed fragment.
private Fragment activeFragement;
public void setActiveFragement(Fragment activeFragement) {
this.activeFragement = activeFragement;
}
// This method, which is for demonstration purposes, shows how you would handle a network response.
public void handleResponse(SomeResponseObject) {
if (activeFragement != null) {
// Now you can get the activity
Activity activity = activeFragement.getActivity();
} else {
// Yes it is possible that there is no active fragment.
// If the user has stayed on the same screen, then the
// fragment of interest will likely be re-created, and
// this window of time with no fragment will be brief.
//
// Note that this null-check is very different than the
// null-check you describe. In your case the reference is
// guaranteed to be null forever. In this case, the reference
// will eventually become non-null.
}
}
}
#Override
public void onStart() {
super.onStart();
// At this point in the fragment lifecycle, the fragment is both running and is attached to an Activity.
// Thus "getActivity" calls are safe from this point onward.
processor.setActiveFragement(this);
}
#Override
public void onStop() {
super.onStop();
// At this point in the fragment lifecycle, the fragment has been stopped and is about to lose its connection to the activity.
// So after this point, calls to "getActivity" are probably not safe.
// DISCLAIMER - I have not tested this. You might want to do this in a
// different method such as "onDestroyView()"
processor.setActiveFragement(null);
}
}

Dynamically change ViewpagerIndicator Fragment Content Android

I am working on an application using viewpagerindicator.
In my main activity that has the viewpagerindicator, I spin off a thread that does some computation and updates a an instance variable mString of the activity. I want to update a fragment in the viewpagerindicator with the mString. However, I can't seem to figure out the best way to reach the fragment.
Does anyone know of any good samples that do something similar to this?
Create a callback object in your Fragment, register it with your FragmentActivity. If mString is already set in FragmentActivity then you can return it immediately via the callback, otherwise, when the computation thread finishes, it can return the string via the callback. The callback method should do whatever the Fragment needs to do with the string, e.g. set the text of a TextView.
E.g. create an interface called DynamicDataResponseHandler as follows:
public interface DynamicDataResponseHandler {
public void onUpdate(Object data);
}
Then in your Fragment, implement that interface as follows:
private class MyStringDataResponseHandler implements DynamicDataResponseHandler {
#Override
public void onUpdate(Object object) {
mYourTextView.setText((String)object);
}
}
Your Fragment can then instantiate a MyStringDataResponseHandler object in its onCreate, pass that to the FragmentActivity via a method in the FragmentActivity like:
private MyStringDataResponseHandler mMyStringDataResponseHandler;
public void registerMyStringDataResponseHandler (DynamicDataResponseHandler callback) {
mMyStringDataResponseHandler = callback;
if(mString != null) {
mMyStringDataResponseHandler.onUpdate(mString);
}
}
And wherever in your Handler you obtain the value for mString, do something like this:
if(mMyStringDataResponseHandler != null) {
mMyStringDataResponseHandler.onUpdate(mString);
}
Do some reading on the concept of Callbacks to get a better understanding of what I'm doing above and other ways you can use them.
You want to update the UI of a Fragment in ViewPager after it is started, do i make it clear?
Ok, in this situation
You should add a public method in your custom Fragment.
Find the Fragment in your Activity.
Invoke the method after your calculation is done.
The question is same with this one.

Categories

Resources