1

I am currently working on an update on a widget I made a while ago, and I am having troubles with the widget view freezing, or it stops updating after a while.

The app is a system monitor that updates every second (Yes, I know it is bad for battery life for it to update this often, but I set up some broadcast receivers to disable updating to help this significantly), and since Alarm managers no longer allow updating every second, I had to use a handler and a runnable to call an object that takes context to update our remote views and widget.

It starts with a provider creating and calling the object:

ProviderHelper.java

//Save our context
        context = parentContext;

        //creating Handler to update every second
        handler = new Handler();

        //Create our updater
        updater = new WidgetUpdater(parentContext);

        //Start our sleep receiver
        registBroadcastReceiver(context);

        //Set our quit to false
        quit = false;

         runUpdate = new Runnable() {
            public void run() {

                //Run our updates in the service
                if(!ProviderHelper.isQuitting())
                {
                    updater.runUpdate(context);
                }


                //Quit the handler
                if(ProviderHelper.isQuitting()) {

                    //Remove all pending callbacks, and then return
                    handler.removeCallbacks(this);
                    return;
                }
                //Use post at time to only update when the phone is not in deep sleep :)
                else handler.postAtTime(this, SystemClock.uptimeMillis() + updateInterval);


            }
        };

        handler.post(runUpdate);
    }

Then we call a helper to update the specified section of the widget

WidgetUpdater.java

    public void update(Context context) {

        Log.d("WIDGET UPDATER", "Updating...");

    //call time methods, not calling if unchecked
    if (timeMan.timeStatus()) timeMan.getTime();

    //call system methods
    if (battMan.percentStatus() || battMan.tempStatus()) {
        battMan.getBatteryPercent(context);
        battMan.getBatteryTemp(context);
    }

    if (cpuMan.cpuStatus()) cpuMan.getCpuUsage();

    if (timeMan.upTimeStatus()) timeMan.getUptime();

    //call memory methods
    if (diskMan.memoryStatus()) diskMan.getSpace();

    if (diskMan.ramStatus()) diskMan.getRam(context);

    //call network methods
    if (networkMan.typeStatus()) networkMan.getNetworkType(context);

    if (networkMan.ipStatus()) networkMan.getIp(context);

    if (networkMan.downSpeedStatus() || networkMan.upSpeedStatus()) networkMan.getSpeeds();

    //update widget for all size
    // Need to grab our views every single time
    views = new RemoteViews(context.getApplicationContext().getPackageName(), R.layout.widget_layout);
    AppWidgetManager manager = AppWidgetManager.getInstance(context);
    manager.updateAppWidget(thiswidget, views);
    manager.updateAppWidget(thiswidgetsmall, views);
    manager.updateAppWidget(thiswidgetbig, views);
    manager.updateAppWidget(thiswidgetbigger, views);
    manager.updateAppWidget(thiswidgetsmallest, views);

        //Try notifying the wifgets their data changed
        //Yes this is redundant, I am trying everything to get this to work
        manager.notifyAppWidgetViewDataChanged(manager.getAppWidgetIds(thiswidget), views.getLayoutId());
        manager.notifyAppWidgetViewDataChanged(manager.getAppWidgetIds(thiswidgetsmall), views.getLayoutId());
        manager.notifyAppWidgetViewDataChanged(manager.getAppWidgetIds(thiswidgetbig), views.getLayoutId());
        manager.notifyAppWidgetViewDataChanged(manager.getAppWidgetIds(thiswidgetbigger), views.getLayoutId());
        manager.notifyAppWidgetViewDataChanged(manager.getAppWidgetIds(thiswidgetsmallest), views.getLayoutId());
}

For example, here is a call from the time widget helper

TimeHelper.java

//function for time
@SuppressLint("SimpleDateFormat")
public void getTime()
{
    //time, creating date and inserting it to simple date format
    Date date = new Date();
    SimpleDateFormat time= new SimpleDateFormat("hh:mm:ss a");
    SimpleDateFormat day = new SimpleDateFormat("EEEE, MMMM dd, yyyy");
    if(shortBool) day = new SimpleDateFormat("EEE, MMM dd, yyyy");
    else day = new SimpleDateFormat("EEEE, MMMM dd, yyyy");

    //24 hour settings
    if(hourFormat == true) time = new SimpleDateFormat("HH:mm:ss a");
    else time = new SimpleDateFormat("hh:mm:ss a");

    //setting text to time
    views.setTextViewText(R.id.time, "Time: " + time.format(date));
    views.setTextViewText(R.id.date, "Date: " + day.format(date));
}

And I already posted this, but here is how I am updating the views:

WidgetUpdater.java (In update function posted above)

//update widget for all size
        // Need to grab our views every single time?
        views = new RemoteViews(context.getApplicationContext().getPackageName(), R.layout.widget_layout);
        AppWidgetManager manager = AppWidgetManager.getInstance(context);
        manager.updateAppWidget(thiswidget, views);
        manager.updateAppWidget(thiswidgetsmall, views);
        manager.updateAppWidget(thiswidgetbig, views);
        manager.updateAppWidget(thiswidgetbigger, views);
        manager.updateAppWidget(thiswidgetsmallest, views);

            //Try notifying the wifgets their data changed
            //Yes this is redundant, I am trying everything to get this to work
            manager.notifyAppWidgetViewDataChanged(manager.getAppWidgetIds(thiswidget), views.getLayoutId());
            manager.notifyAppWidgetViewDataChanged(manager.getAppWidgetIds(thiswidgetsmall), views.getLayoutId());
            manager.notifyAppWidgetViewDataChanged(manager.getAppWidgetIds(thiswidgetbig), views.getLayoutId());
            manager.notifyAppWidgetViewDataChanged(manager.getAppWidgetIds(thiswidgetbigger), views.getLayoutId());
            manager.notifyAppWidgetViewDataChanged(manager.getAppWidgetIds(thiswidgetsmallest), views.getLayoutId());

I've tried solutions such as these:

Android AppWidgetManager method updateAppWidget fails to set intents, load data. And it happens randomly

Android widget stops working after a while?

And they didn't work. And If you noticed, I am logging whenever the update function is called where the AppWidgetManager is being called to update the app widget, so I am certain this is all being called as well. In the sense that the update function is being called, however the remoteview of the widget is NOT updating (in case that was unclear). Any help on why the widget remote view would stop updating after a while of time (~5-10 minutes), would be much appreciated. If you need any more info please let me know!

Also the project is open-source, so you can view all of the code here:

https://github.com/torch2424/Stats-Monitor-Widget

Thank you!

Community
  • 1
  • 1
Torch2424
  • 168
  • 3
  • 8

0 Answers0