0

I have a Fragment. In this Fragment I run a http request on an json-rpc. To handle the result I have something like this in my Callback.

FragmentClass.this.getActivity().runOnUiThread(new Runnable() {
    @Override
    public void run() {
        // Do something
    } 
});

The problem is, sometimes i get a NullPointerException on the first line... My first intend was, that the fragment got detached to fast maybe because the user selects an other fragment while the request runs and so the

FragmentClass.this.getActivity();

has no activity and returns null. I enclose the whole thing with an if like this:

// New if:
if (FragmentClass.this.getActivity() != null) {

    FragmentClass.this.getActivity().runOnUiThread(new Runnable() {
        @Override
        public void run() {
            // Do something
        } 
    });

}

But... Nothing... Now I get an NullPointerException on the if statement. it seems that

FragmentClass.this

is null.

How is that possible. I thought an instance will be hold until no code part needs it and the gc collects it...

Here is the stacktrace that logcat gives me. I have changed the package-name and the classnames. Line 192 is the line of the if statement.

09-18 10:49:36.915    3860-3860/de.unkown.app E/AndroidRuntime﹕ FATAL EXCEPTION: main
    java.lang.NullPointerException
            at de.unkown.app.camera.#FragmentClass$6.onError(FragmentClass.java:192)
            at de.unkown.app.webservice.JsonRpcService$10.onError(JsonRpcService.java:497)
            at    de.unkown.app.webservice.JsonRpcService$DefaultErrorListener.onErrorResponse(JsonRpcService.java:107)
                at com.android.volley.Request.deliverError(Request.java:577)
            at com.android.volley.ExecutorDelivery$ResponseDeliveryRunnable.run(ExecutorDelivery.java:101)
            at android.os.Handler.handleCallback(Handler.java:725)
            at android.os.Handler.dispatchMessage(Handler.java:92)
            at android.os.Looper.loop(Looper.java:137)
            at android.app.ActivityThread.main(ActivityThread.java:5041)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:511)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
            at dalvik.system.NativeStart.main(Native Method)

Thank you for your help!

Artur

Artur Hellmann
  • 315
  • 4
  • 21
  • Where is the stack trace ? – Suresh Atta Sep 18 '15 at 09:35
  • Try `getActivity()` instead of `FragmentClass.this.getActivity()` – Phantômaxx Sep 18 '15 at 09:41
  • Why not just use getActivity()? – AC-OpenSource Sep 18 '15 at 09:42
  • But doesn´t only getActivity() do the same as FragmentClass.this.getActivity()? I mean the first one runs the method of the scope, the second one says in which scope I want to run the getActivity(). But i will try it. – Artur Hellmann Sep 18 '15 at 09:48
  • In Java it should be impossible to observe `FragmentClass.this` being null. Not sure if dalvik is doing s.t. nasty here. To figure out if some very subtle initialization bug hits you, we'd need to know the exact context of your code snippet: could it be possible, that this snippet is executed on an object that hasn't been fully initialized yet? OuterClass.this is implemented as a synthetic final field, which is invisibly assigned as the first thing in a constructor - a tricky combination of super constructor and dynamic dispatch *could* perhaps expose this field uninitialized. – Stephan Herrmann Sep 18 '15 at 22:29
  • In Java byte code the synthetic field implementing `OuterClass.this` is assigned even before the super constructor is called. Hard to imagine any leak. – Stephan Herrmann Sep 18 '15 at 22:36
  • There is indeed the possibility to have `FragmentClass.this` being null: when reflection is used. And by using a deserialization library you might not even notice that reflection is used - until it tries to restore an inner class without restoring the reference to the outer class (see question [GSON does not deserialize reference to outer class](https://stackoverflow.com/q/19449761/905686)). Could it be that you are referencing the outer class in an object that has been deserialized from json when handling the json-rpc result? – user905686 Dec 01 '17 at 17:41

3 Answers3

0

create a global variable Context context ;

than initialize the variable in on Create method:

context = get Activity();

than use it as:

context. runOnUiThread (new Runnable() {
    @Override
    public void run() {
        // Do something
    } 
});

hopefully this will help you.

Lucky Rana
  • 1,030
  • 1
  • 12
  • 20
  • First of all creating a global variable Context context is a bad idea. It can lead to memory leaks and run time errors especially when you have multiple fragments within a view pager. Secondly, for context always use ```getContext()``` If you are using AsyncTask and want to use context within the AsyncTask's methods, then pass context as a final method parameter variable to the method enclosing the AsyncTask, and use within the AsyncTask's overridden methods. If you use getContext() within AsyncTask's methods, it can lead to NullPointerException – Vadiraj Purohit Aug 23 '16 at 10:47
  • context.runOnUiThread does not even compile. It requires getActivity. So below code is safe to use ```if (isAdded()) getActivity().runOnUiThread (new Runnable() { @Override public void run() { // Do something } });``` – Vadiraj Purohit Aug 23 '16 at 10:55
0

getActivity() returns null in onCreate and onCreateView methods.
Use getActivity() inside onViewCreated. It is good to surround code using getActivity with a check - if (isAdded()) { }.

In your case you are getting null because, by the time you call FragmentClass.this.getActivity(), your fragment is no longer visible to the user, essentially onStop was already called.

To further add to my answer -
Suppose you are calling a method doSomething() on a fragment in which you are performing an AsyncTask. Then pass YourFragmentClass.this as a method parameter to doSomething(YourFragmentClass thiz) and use this object inside your doInBackground() and onPostExecute() methods instead of using YourFragmentClass.this, because YourFragmentClass.this returns null, because by the time AsynTask runs, your fragment would have moved to onPause or onStop.

Vadiraj Purohit
  • 898
  • 8
  • 20
-1

Ok,

i changed in all asynchronous blocks the

FragmentClass.this.getActivity()

to

getActivity()

This seams to help. Please don´t ask me why... I thought this should be the same...

Artur Hellmann
  • 315
  • 4
  • 21