0

I have an app that has a big red voting button on it. Now, I always require that they have a public IP address in order to enable the Vote button.

I learned that I needed to do my fetching of internet things via an AsyncTask, so I made a new class extend it called DetermineIP. This process works, I'm able to get an IP because I have a webpage I built that just provides the IP.

I now am working on handling when they have no connectivity. So, I built an alert box such that it has a Retry button on it. The goal is to allow the user to fix their connectivity issues and then hit Retry until they get their IP.

I cannot seem to add the click handler, I think, because it's being called from the AsyncTask. I get: Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()

I full on admit to being a noob and am really just looking to find a way to make this happen.

public void fetchIP()
{
    // UPDATE LABELS
    Resources res = getResources();

    TextView textStatus = (TextView) findViewById(R.id.statusMessage);
    textStatus.setText(res.getString(R.string.status_determining_ip_address));

    enableVoteButton(false);

    String stringURL = res.getString(R.string.ip_url);
    URL urlIP = null;
    try {
        urlIP = new URL(stringURL);
    } catch (MalformedURLException e) {
        e.printStackTrace();
    }

    // start AsyncTask to fetch IP in the background
    getIP = new DetermineIP();
    getIP.setParent(this);
    getIP.execute(urlIP);
    m_working = true;

    // show a dialog box with message that we're determining the IP
    status_dialog = new Dialog(MainActivity.this);
    status_dialog.setCancelable(false);
    status_dialog.setContentView(R.layout.activity_ip);
    TextView textDialogStatus = (TextView) status_dialog.findViewById(R.id.textView);
    textDialogStatus.setText(R.string.status_determining_ip_address);
    status_dialog.show();
}

// If we were able to determine the IP address by fetching from a
// public web server then everything's good. Enable everything, and
// move along from there. Called from DetermineIP.onPostExecute.
public void setIP(String theIP)
{
    m_ip = theIP;

    TextView textStatus = (TextView) findViewById(R.id.statusMessage);
    textStatus.setText(m_ip);
    enableVoteButton(true);
    m_working = false;
    status_dialog.dismiss();
}

// If we were unable to determine an IP address, for whatever reason,
// show a retry alert box, when they hit retry, then start the process
// over again, maybe the user needs to solve a connectivity issue before
// retrying. Called from DetermineIP.onPostExecute.
public void setNoIP()
{
    Resources res = getResources();

    TextView textStatus = (TextView) findViewById(R.id.statusMessage);
    textStatus.setText(res.getString(R.string.status_unable_to_determine_ip_address));
    enableVoteButton(false);
    m_working = false;

    status_dialog.dismiss();
    RetryDialog();
}

// this is the dialog that informs the user that no IP was determined.
// clicking Retry will start the process of finding the IP again.
private void RetryDialog()
{
    Resources res = getResources();

    AlertDialog.Builder builder1 = new AlertDialog.Builder(MainActivity.this);
    builder1.setMessage(res.getString(R.string.status_unable_to_determine_ip_address));
    builder1.setCancelable(false);

    builder1.setPositiveButton(
            "Retry",
            new DialogInterface.OnClickListener() {
                public void onClick(DialogInterface dialog, int id) {
                    dialog.cancel();
                    fetchIP();
                }
            });

    AlertDialog alert11 = builder1.create();
    alert11.show();

}

In DetermineIP.onPostExecute

protected void onPostExecute(String result) {
    if(result.isEmpty()) ((MainActivity) m_parent).setNoIP();
    else ((MainActivity) m_parent).setIP(result);
}
the_gesslar
  • 379
  • 3
  • 13

2 Answers2

1

Any updates to the UI from an AsyncTask can be done in the following way -

protected void onPostExecute(Object result) {

            activity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    //UI related code
                }
            });
        }
a_m
  • 341
  • 5
  • 16
  • I added what I have for onPostExecute. I assume, I can just put ((MainActivity) m_parent).setNoIP(); in the "UI related code" – the_gesslar Feb 07 '16 at 20:03
  • If{((MainActivity) m_parent).setNoIP();} updates the UI in anyway, then yes. – a_m Feb 07 '16 at 20:07
  • Here's another way - [link](http://stackoverflow.com/questions/3875184/cant-create-handler-inside-thread-that-has-not-called-looper-prepare) – a_m Feb 07 '16 at 20:09
  • So, this all worked. The re-enabling of the Vote button, the updating of the TextViews, when being called back from onPostExecute. It's only the AlertDialog requiring a handler that isn't working and crashing my app. Also, I tried putting the above code in with my setNoIp() method, and it still crashed with the same error. – the_gesslar Feb 07 '16 at 20:13
  • @the_gesslar Can you confirm you are doing this - activity.runOnUiThread(new Runnable)...? I don't see that in your update. – a_m Feb 07 '16 at 20:34
  • You have solved my issue! You are the best. Thank you. :) – the_gesslar Feb 07 '16 at 20:44
0

The error your getting highly suggest your doing work UI updates of the main UI thread. If you want to update the view you should do it on the UI thread. AsyncTask has a callback where you can update the UI if you want:

 @Override 
        protected void onPostExecute(Object result) {
        } 

and there is one for onPreExecute

Android's golden rule --> do heavy work on another thread (like do doInBackground of AsyncTask) and update UI on main thread.

So anything UI related just call it from the main thread not from asyncTask doInBackground

j2emanue
  • 60,549
  • 65
  • 286
  • 456
  • I have updated my code to show my **onPostExecute**. It all works with updating my TextViews and enabling my buttons Only it won't let me add the click handler for my AlertDialog box. – the_gesslar Feb 07 '16 at 20:15