Bulsatar
Bulsatar

Reputation: 45

asynctask not completeing onUpdate Android Widget

Morning Everyone, Trying to get an onclick event on a widget to work, problem is that a background asynctask isn't completed before the onUpdate function which sets the pending intent. I have a little bit of familiarity with android but definitely still in the learning stage. The testing I did in an actual activity works well and correctly and watching when the logs come in it is definitely a timing issue. Any help would be appreciated!!

public class SingleClickWanIP extends AppWidgetProvider {
private static final String TAG = "waninfo";

private String myURL;
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
    // There may be multiple widgets active, so update all of them
    Log.d(TAG,"started update: " + myURL);
    WifiManager wifiManager = (WifiManager)  context.getSystemService(WIFI_SERVICE);
    WifiInfo wifiInfo = wifiManager.getConnectionInfo();
    String ssid = wifiInfo.getSSID();
    String homessid = "\"MyRouterName\"";

    if (ssid.equalsIgnoreCase(homessid)){
        myURL = "192.168.1.106";
    }
    Log.d(TAG,"finished ssd check: " + myURL);
    String newURL = "http://"+myURL+":120";
    Uri uri = Uri.parse(newURL);
    Intent intent = new Intent(Intent.ACTION_VIEW, uri);

    PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
    RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.single_click_wan_ip);
    Log.d(TAG,"finished intent and remote views: " + myURL);
    views.setOnClickPendingIntent(R.id.ibOrange, pendingIntent);
    Log.d(TAG,"finished on click pending: " + myURL);

    final int N = appWidgetIds.length;
    for (int i = 0; i < N; i++) {
        updateAppWidget(context, appWidgetManager, appWidgetIds[i]);
    }
    Log.d(TAG,"finished onUpdate: " + myURL);
}



@Override
public void onEnabled(Context context) {
    ProcessURL process = new ProcessURL();
    process.execute("https://www.dropbox.com/link to get external ip value/wanip.txt?raw=1");
    Log.d(TAG,"started process: " + myURL);

}

private class ProcessURL extends AsyncTask<String, Void, String> {

    @Override
    protected String doInBackground(String... params) {
        Log.d(TAG,"started background");
        return GET(params[0]);
    }

    @Override
    protected void onPostExecute(String result) {
        myURL = result;
        Log.d(TAG,"finished and set myURL variable: " + myURL);
    }



    private  String GET(String url){
        InputStream inputStream = null;
        String result = "";
        try {

            // create HttpClient
            HttpClient httpclient = new DefaultHttpClient();

            // make GET request to the given URL
            HttpResponse httpResponse = httpclient.execute(new HttpGet(url));

            // receive response as inputStream
            inputStream = httpResponse.getEntity().getContent();

            // convert inputstream to string
            if(inputStream != null)
                result = convertInputStreamToString(inputStream);
            else
                result = "Did not work!";

        } catch (Exception e) {
            Log.d(TAG, e.getLocalizedMessage());
        }

        return result;
    }

    private String convertInputStreamToString(InputStream inputStream) throws IOException {
        BufferedReader bufferedReader = new BufferedReader( new InputStreamReader(inputStream));
        String line = "";
        String result = "";
        while((line = bufferedReader.readLine()) != null)
            result += line;

        inputStream.close();
        return result;

    }
}

Little bit of background, I am cheap and don't want to pay for no-ip or something similar. But I want to share my server access with friends and family and without having to tell them "yeah, just type in xx.xx.xx.xxx:120 to get there". So server writes to my dropbox file the external ip, I have a shared link from dropbox that I use in this app to get the value, and then open up my server's site. viola


Edit

...and got it! fumbling around I found this post about the strange behavior of the widget spontaneously switching which fixed that spontaneous widget. Then the click wouldn't work because I had to wrap the code in onupdate with an if since it wouldn't do to create a pending uri intent with a null as the url address. So...copied the pending onclick intent to the onpostexecute process and now I am a bug in a rug.

Thanks for the leads, much appreciated!

contents of onpostexecute:

            WifiManager wifiManager = (WifiManager) gContext.getSystemService(WIFI_SERVICE);
            WifiInfo wifiInfo = wifiManager.getConnectionInfo();
            String ssid = wifiInfo.getSSID();
            String homessid = "\"MyRouterName\"";

            if (ssid.equalsIgnoreCase(homessid)) {
                result = "192.168.1.106";
            }
            Log.d(TAG, "finished ssd check: " + result);
            myURL = "http://" + result + ":8080";

            Uri uri = Uri.parse(myURL);
            Intent intent = new Intent(Intent.ACTION_VIEW, uri);

            PendingIntent pendingIntent = PendingIntent.getActivity(gContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
            RemoteViews views = new RemoteViews(gContext.getPackageName(), R.layout.single_click_wan_ip);
            Log.d(TAG, "finished intent and remote views: " + myURL);
            views.setOnClickPendingIntent(R.id.ibOrange, pendingIntent);
            Log.d(TAG, "finished on click pending: " + myURL);

            ComponentName thisWidget = new ComponentName(gContext, SingleClickWanIP.class);
            gappWidgetManager.updateAppWidget(thisWidget, views);

            Log.d(TAG,"finished and set myURL variable: " + myURL);

Upvotes: 0

Views: 269

Answers (2)

ra3o.ra3
ra3o.ra3

Reputation: 852

In your case it is much safer to update the widget from an IntentService rather than from an AsyncTask started from your app widget provider.

onEnabled and onUpdate are supposed to complete within (maximum) 10 seconds.

I strongly recommend you to use the following code:

SingleClickWanIP.java

public class SingleClickWanIP extends AppWidgetProvider
{
    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
    {
        context.startService(new Intent(context, ProcessURL.class));
    }

    @Override
    public void onEnabled(Context context)
    {
        context.startService(new Intent(context, ProcessURL.class));
    }
}

ProcessURL.java

public class ProcessURL extends IntentService
{
    private static final String TAG = "waninfo";
    private String myURL;

    public ProcessURL()
    {
        super("ProcessURL__service");
        setIntentRedelivery(true);
    }

    @Override
    protected void onHandleIntent(Intent intent__)
    {
        myURL = GET("https://www.dropbox.com/link to get external ip value/wanip.txt?raw=1");
        Log.d(TAG,"finished and set myURL variable: " + myURL);

        WifiManager wifiManager = (WifiManager)  getSystemService(Context.WIFI_SERVICE);
        WifiInfo wifiInfo = wifiManager.getConnectionInfo();
        String ssid = wifiInfo.getSSID();
        String homessid = "\"MyRouterName\"";

        if (ssid.equalsIgnoreCase(homessid))
        {
            myURL = "192.168.1.106";
        }
        Log.d(TAG,"finished ssd check: " + myURL);
        myURL = "http://"+myURL+":120";
        Uri uri = Uri.parse(myURL);
        Intent intent = new Intent(Intent.ACTION_VIEW, uri);

        PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
        RemoteViews views = new RemoteViews(getPackageName(), R.layout.single_click_wan_ip);
        Log.d(TAG,"finished intent and remote views: " + myURL);
        views.setOnClickPendingIntent(R.id.ibOrange, pendingIntent);
        Log.d(TAG,"finished on click pending: " + myURL);


        // Update all widgets

        AppWidgetManager manager = AppWidgetManager.getInstance(this);
        if(null != manager)
        {
            Log.d(TAG,"Updating all widgets...");
            manager.updateAppWidget(new ComponentName(this,SingleClickWanIP.class), views);
            Log.d(TAG,"finished and set myURL variable: " + myURL);
        }
    }

    private  String GET(String url)
    {
        InputStream inputStream = null;
        String result = "";
        try
        {
            // create HttpClient
            HttpClient httpclient = new DefaultHttpClient();

            // make GET request to the given URL
            HttpResponse httpResponse = httpclient.execute(new HttpGet(url));

            // receive response as inputStream
            inputStream = httpResponse.getEntity().getContent();

            // convert inputstream to string
            if(inputStream != null)
                result = convertInputStreamToString(inputStream);
            else
                result = "Did not work!";
        }
        catch (Exception e)
        {
            Log.d(TAG, e.getLocalizedMessage());
        }
        return result;
    }

    private String convertInputStreamToString(InputStream inputStream) throws IOException
    {
        BufferedReader bufferedReader = new BufferedReader( new InputStreamReader(inputStream));
        String line = "";
        String result = "";
        while((line = bufferedReader.readLine()) != null)
            result += line;

        inputStream.close();
        return result;
    }
}

And add the following line within the <application /> tag of your AndroidManifest.xml file:

<service android:name="[ADD-THE-PATH-TO-ProcessURL.java-HERE].ProcessURL" android:enabled="true" android:exported="false" />

Upvotes: 0

Greg Ennis
Greg Ennis

Reputation: 15379

I would request an update of the widget on onPostExecute of the asynctask since that is when you have the URL and you can now setup the pending intent correctly.

Use an intent with action AppWidgetManager.ACTION_APPWIDGET_UPDATE to request the widget update.

Upvotes: 1

Related Questions