Android Homescreen Widget becomes Unresponsive

2019-06-07 05:19发布

问题:

I have an Android home screen widget I am working on and everything works great, except after about 5 to 6 days the four buttons revert to their default state and become unresponsive. I do not understand why the buttons are becoming unresponsive. If I remove and add the widget again it works again. If I wait for about 24-48 hours, it will begin to work again for a period of time.

I have tried to remove the android:updatePeriodMillis so that the widget does not update on its own (it is self-contained and only really needs updated upon user interaction). This has not worked either.

This is how I am setting up my PendingIntents withinonUpdate (modeled after the answer to this question):

Intent intent1 = new Intent(context, MyWidgetProvider.class);
intent1.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId);
intent1.setAction(FIRST_INTENT);
intent1.setData(Uri.parse(first_band_intent.toUri(Intent.URI_INTENT_SCHEME)));
PendingIntent pendingIntent1 = PendingIntent.getBroadcast(context, widgetId, intent1, PendingIntent.FLAG_UPDATE_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.first_button, pendingIntent1);

I then update the widget's view items within the onReceive method:

@Override
public void onReceive(Context context, Intent intent) {
    int widgetID = intent.getExtras().getInt(AppWidgetManager.EXTRA_APPWIDGET_ID);
    String preferences = PREFS + Integer.toString(widgetID);
    SharedPreferences values = context.getSharedPreferences(preferences, 0);
    int firstBandValue = values.getInt("first_band_value", 1);
    int secondBandValue = values.getInt("second_band_value", 0);
    int multiplierValue = values.getInt("multiplier_value", 2);
    int toleranceValue = values.getInt("tolerance_value", 1);

    RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout);

    if (intent.getAction().equals(FIRST_BAND)) {
        // nextBandColor() will set the proper band based on the next value and return an integer that is BandValue + 1
        firstBandValue = getNextBandColor(context, BandType.FIRST, firstBandValue);

        SharedPreferences.Editor editor = values.edit();
        editor.putInt("first_band_value", firstBandValue);
        editor.commit();
    }
    else if (intent.getAction().equals(SECOND_BAND)) {
        // nextBandColor() will return an integer that is BandValue + 1
        secondBandValue = getNextBandColor(context, BandType.SECOND, secondBandValue);

        SharedPreferences.Editor editor = values.edit();
        editor.putInt("second_band_value", secondBandValue);
        editor.commit();
    }
    else if (intent.getAction().equals(MULTIPLIER)) {
        // nextBandColor() will return an integer that is BandValue + 1
        multiplierValue = getNextBandColor(context, BandType.MULTIPLIER, multiplierValue);

        SharedPreferences.Editor editor = values.edit();
        editor.putInt("multiplier_value", multiplierValue);
        editor.commit();
    }
    else if (intent.getAction().equals(TOLERANCE)) {
        // nextBandColor() will return an integer that is BandValue + 1
        toleranceValue = getNextBandColor(context, BandType.TOLERANCE, toleranceValue);

        SharedPreferences.Editor editor = values.edit();
        editor.putInt("tolerance_value", toleranceValue);
        editor.commit();
    }
    else {
        super.onReceive(context, intent);
    }

    //Update the view items based on the new integer values; calls updateAppWidget()
    updateBands(context, widgetID, firstBandValue, secondBandValue, multiplierValue, toleranceValue);

    // Concatenate the integer value of the first band value with the integer value of the second band color
    String value = Integer.toString(firstBandValue) + Integer.toString(secondBandValue);

    // Turn the concatenation of the two integers into a double value
    baseValue = Double.parseDouble(value);

    multiplyBaseValue(multiplierValue);

    String units = getUnitsAndAdjustBaseValue();
    String tolerance = getTolerance(toleranceValue);

    DecimalFormat df = new DecimalFormat("#.#");
    resistance = df.format(baseValue) + units + tolerance;

    remoteViews.setTextViewText(R.id.resistance_value, resistance);


    AppWidgetManager manager = AppWidgetManager.getInstance(context);
    manager.updateAppWidget(widgetID, remoteViews);
}

This widget is designed to be stand-alone, without any Activity or Service.

UPDATE 1: If I add a return statement to the else of my onReceive after the super.onReceive(), then it reverts to the original layout, but does not become unresponsive.

UPDATE 2: I read here that the onReceive() method must complete processing within 5 seconds. Could the issue be that my onReceive() is not completing within the allotted time and thus causing the widget to freeze?

This issue is also device independent. It has happened on a Galaxy Nexus, Nexus 7 2012, and Galaxy S4.

What could be causing the issue of this unresponsiveness?

回答1:

Test your onReceive() code first to see if the error lies in there or elsewhere - it is always best to test assumptions when looking for "random" or "weird" bugs.

So to test it, simplify it absolutely, to make it 100% trivial. Remove all the interesting code, and just make it change the text to something simple. Something that could no possibly have a bug in it.

@Override
public void onReceive(Context context, Intent intent) {
    int widgetID = intent.getExtras().getInt(AppWidgetManager.EXTRA_APPWIDGET_ID);

    RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
    remoteViews.setTextViewText(R.id.resistance_value, "1.2 ohms");

    AppWidgetManager manager = AppWidgetManager.getInstance(context);
    manager.updateAppWidget(widgetID, remoteViews);
}

If this still breaks, then you know the bug is not within your onReceive() code. So you can then look elsewhere.


If this fixes the issue, then you know that part of your onReceive() has broken the widget.

Add the code back bit by bit, add lots of logging (Log.d()).

You may want to look at your SharedPreferences access, since this is file access. Also have a look at this post, and consider using SharedPreferences.Editor.apply():

  • What's the difference between commit() and apply() in Shared Preference

Typically with this approach, you will be able to find the bug, or at least narrow it down to something really specific, which will make it easier to get help here.