3

I'm having problems getting an alert in my android app with proper text. I'm using the same code for sending Get request to the servers and it works fine, but in this instance I'm using Post method and while the data I send is stored in the database and Logcat shows that a proper/expected string comes back, the app just crashes when it gets to onPostExecute part instead of displaying alert.

Am I missing something, is there some other way to handle responses from Post method?

Here is my code:

package com.example.aplikacija;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.AsyncTask;
import android.text.Html;
import android.util.Log;

public class REST_VpisOcene extends AsyncTask<Void, Void, String> {

String restURL =     "*REST IP removed*";

private Activity activity;
private String predmet;
private String ocena;
private String IDucenca;
private String IDprofesorja;

public REST_VpisOcene(String predmet, String ocena, String IDucenca, String IDprofesorja,
        Activity activity) {
    this.predmet = predmet;
    this.ocena = ocena;
    this.IDucenca = IDucenca;
    this.IDprofesorja = IDprofesorja;
    this.activity = activity;
}

protected String getASCIIContentFromEntity(HttpEntity entity)
        throws IllegalStateException, IOException {
    InputStream in = entity.getContent();
    StringBuffer out = new StringBuffer();
    int n = 1;
    while (n > 0) {
        byte[] b = new byte[4096];
        n = in.read(b);
        if (n > 0)
            out.append(new String(b, 0, n));
    }
    return out.toString();
}

@Override
protected String doInBackground(Void... params) {

    String sporocilo = "";
    HttpClient httpclient = new DefaultHttpClient();
    HttpContext localContext = new BasicHttpContext();
    HttpPost httppost = new HttpPost(restURL);
    httppost.addHeader("Accept", "text/html");
    try {
        List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(2);
        nameValuePairs
                .add(new BasicNameValuePair("predmet", predmet));
        nameValuePairs.add(new BasicNameValuePair("ocena", ocena));
        nameValuePairs.add(new BasicNameValuePair("IDucenca", IDucenca));
        nameValuePairs.add(new BasicNameValuePair("IDprofesorja", IDprofesorja));
        httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));

        HttpResponse response = httpclient.execute(httppost, localContext);
        HttpEntity entity = response.getEntity(); 
        sporocilo = getASCIIContentFromEntity(entity); 
    } catch (ClientProtocolException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    Log.i("odgovor vpisa", sporocilo);
    return sporocilo;

}

protected void onPostExecute(String results) {
    if (results.equals("0")) {



        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
        builder.setMessage("Pri vpisu je prišlo do napake!")
                .setCancelable(false)
                .setNegativeButton("OK",
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog,
                                    int id) {
                                dialog.cancel();
                            }
                        });
        AlertDialog alert = builder.create();
        alert.show();
    } else if (results.equals("1")) {

        AlertDialog.Builder builder = new AlertDialog.Builder(activity);
        builder.setMessage("Vpisano!")
                .setCancelable(false)
                .setNegativeButton("OK",
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog,
                                    int id) {
                                dialog.cancel();
                            }
                        });
        AlertDialog alert = builder.create();
        alert.show();
    }
}
}

And my Logcat:

02-08 14:56:11.856: I/odgovor vpisa(6424): 1
02-08 14:56:11.859: D/AndroidRuntime(6424): Shutting down VM
02-08 14:56:11.860: E/AndroidRuntime(6424): FATAL EXCEPTION: main
02-08 14:56:11.860: E/AndroidRuntime(6424): Process: com.example.aplikacija,     PID: 6424
02-08 14:56:11.860: E/AndroidRuntime(6424): java.lang.NullPointerException:   Attempt to invoke virtual method 'android.content.res.Resources$Theme   android.content.Context.getTheme()' on a null object reference
02-08 14:56:11.860: E/AndroidRuntime(6424):     at   android.app.AlertDialog.resolveDialogTheme(AlertDialog.java:154)
02-08 14:56:11.860: E/AndroidRuntime(6424):     at android.app.AlertDialog$Builder.<init>(AlertDialog.java:379)
02-08 14:56:11.860: E/AndroidRuntime(6424):     at com.example.aplikacija.REST_VpisOcene.onPostExecute(REST_VpisOcene.java:121)
02-08 14:56:11.860: E/AndroidRuntime(6424):     at com.example.aplikacija.REST_VpisOcene.onPostExecute(REST_VpisOcene.java:1)
02-08 14:56:11.860: E/AndroidRuntime(6424):     at android.os.AsyncTask.finish(AsyncTask.java:632)
02-08 14:56:11.860: E/AndroidRuntime(6424):     at android.os.AsyncTask.access$600(AsyncTask.java:177)
02-08 14:56:11.860: E/AndroidRuntime(6424):     at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:645)
02-08 14:56:11.860: E/AndroidRuntime(6424):     at android.os.Handler.dispatchMessage(Handler.java:102)
02-08 14:56:11.860: E/AndroidRuntime(6424):     at android.os.Looper.loop(Looper.java:135)
02-08 14:56:11.860: E/AndroidRuntime(6424):     at android.app.ActivityThread.main(ActivityThread.java:5221)
02-08 14:56:11.860: E/AndroidRuntime(6424):     at java.lang.reflect.Method.invoke(Native Method)
02-08 14:56:11.860: E/AndroidRuntime(6424):     at java.lang.reflect.Method.invoke(Method.java:372)
02-08 14:56:11.860: E/AndroidRuntime(6424):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
02-08 14:56:11.860: E/AndroidRuntime(6424):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)

It fails on the line 121, which is the

AlertDialog.Builder builder = new AlertDialog.Builder(activity);

in the second if clause, meaning it gets through the

results.equals("1")

check, before it fails.

Thank you.

bacje16
  • 93
  • 1
  • 2
  • 6

3 Answers3

10

The problem is that it is not guaranteed that activity is present at the moment that onPostExecute() is called.

onPostExecute() is the method that is called after the processing of a background thread is finished, regardless of the lifecycle of Activity.

The solution is to check whether activity is present at that time and then execute the intended logic.

You can see this for a more elaborate answer (different situation but both related to the core issue that you have here). There's also a blog post that defines this subject in details which is available here.

Community
  • 1
  • 1
mblcdr
  • 762
  • 9
  • 18
3

One year later, but if someone else has this problem maybe this solution can help.

When the activity is going to show the dialog or whatever action which needs the activity context, it's important to check before if the activity is visible or not.

To accomplish this, you'll need a class that extends from Application:

public class App extends Application {

    private static Context mContext;

    @Override
    public void onCreate() {
        super.onCreate();
        mContext = this;
    }

    public static Context getContext(){
        return mContext;
    }

    public static boolean isActivityVisible() {
        return activityVisible;
    }

    public static void activityResumed() {
        activityVisible = true;
    }

    public static void activityPaused() {
        activityVisible = false;
    }

    private static boolean activityVisible;
}

In your MainActivity class, you need to register the current state of the app when some of these actions is done:

@Override
protected void onResume() {
    super.onResume();
    App.activityResumed();
}

@Override
protected void onPause() {
    super.onPause();
    App.activityPaused();
}

And finally, before doing some action like show the dialog, just check if the app is visible:

if (App.isActivityVisible()) {
    // We can show the dialog
} else {
    // Better not show the dialog to avoid a crash
}

Have a nice day! :)

j_gonfer
  • 1,547
  • 21
  • 21
0

change private Activity context; to private Context context

and

public REST_VpisOcene(String predmet, String ocena, String IDucenca, String IDprofesorja,
        Context context) {
    this.predmet = predmet;
    this.ocena = ocena;
    this.IDucenca = IDucenca;
    this.IDprofesorja = IDprofesorja;
    this.context= context;
}

or use getApplicationContext() instead of context and also see this Question

Community
  • 1
  • 1
Zar E Ahmer
  • 33,936
  • 20
  • 234
  • 300