Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android widget stops working after a while?

I have a flashlight app with a widget. The widget is used to turn the flashlight on and off and does not display main activity or anything. After a few hours, however, the widget does nothing. I mean if you click it, nothing happens. I have two classes to accomplish this a Provider and a Receiver.

Provider:

public class WidgetProvider extends AppWidgetProvider {

  @
  Override
  public void onUpdate(Context context, AppWidgetManager appWidgetManager,
    int[] appWidgetIds) {

    Intent receiver = new Intent(context, FlashlightWidgetReceiver.class);
    receiver.setAction("COM_FLASHLIGHT");
    receiver.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
    PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, receiver, 0);

    RemoteViews views = new RemoteViews(context.getPackageName(),
      R.layout.appwidget_layout);
    views.setOnClickPendingIntent(R.id.imageButton, pendingIntent);

    appWidgetManager.updateAppWidget(appWidgetIds, views);

  }
}

Receiver:

public class FlashlightWidgetReceiver extends BroadcastReceiver {
  private static boolean isLightOn = false;
  private static Camera camera;
  MediaPlayer mp;@
  Override
  public void onReceive(Context context, Intent intent) {
    RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.appwidget_layout);

    if (isLightOn) {
      views.setImageViewResource(R.id.imageButton, R.drawable.btn_switch_off);
      mp = MediaPlayer.create(context, R.raw.light_switch_off);
    } else {
      views.setImageViewResource(R.id.imageButton, R.drawable.btn_switch_on);
      mp = MediaPlayer.create(context, R.raw.light_switch_on);
    }
    mp.setOnCompletionListener(new MediaPlayer.OnCompletionListener() {

      @
      Override
      public void onCompletion(MediaPlayer mp) {
        // TODO Auto-generated method stub
        mp.release();
      }
    });
    mp.start();
    AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
    appWidgetManager.updateAppWidget(new ComponentName(context, WidgetProvider.class),
      views);

    if (isLightOn) {
      if (camera != null) {
        camera.stopPreview();
        camera.release();
        camera = null;
        isLightOn = false;
      }

    } else {
      camera = Camera.open();

      if (camera == null) {
        Toast.makeText(context, "No Camera!", Toast.LENGTH_SHORT).show();
      } else {
        Camera.Parameters param = camera.getParameters();
        param.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
        try {
          camera.setParameters(param);
          camera.startPreview();
          isLightOn = true;
        } catch (Exception e) {
          Toast.makeText(context, "No Flash!", Toast.LENGTH_SHORT).show();
        }
      }
    }
  }
}

Setup:

<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
    android:minWidth="40dp"
    android:minHeight="40dp"
    android:maxWidth="40dp"
    android:maxHeight="40dp"
    android:updatePeriodMillis="86400000"
    android:initialLayout="@layout/appwidget_layout"
    android:resizeMode="horizontal|vertical">
</appwidget-provider>

Update: Reducing the update interval makes the widget refresh more often so if it's stuck it works again after 30 min and then it might freeze again sometime.

Update 2: Changing the date instantly freezes the widget until it's refreshed.

Update 3: Changing the date somehow restarts the launcher and whenever the launcher is restarted the widget freezes for 30 mins.

like image 865
Muhammad Ali Avatar asked May 12 '15 01:05

Muhammad Ali


2 Answers

Look for this post, I think this problem is explained here the dark side of app widgets

like image 147
curioushikhov Avatar answered Sep 18 '22 14:09

curioushikhov


Alright guys, I finally got time to fix this problem once and for all :)

I created more methods for the provider instead of doing everything in onUpdate, one important method needed:

    public static PendingIntent buildButtonPendingIntent(Context context) {
      Intent intent = new Intent();
      intent.setAction("COM_FLASHLIGHT");
      return PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    }

And this method is called through the receiver when the widget is clicked using the code below:

private void turnFlash(Context context) {
    RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.appwidget_layout);
    views.setOnClickPendingIntent(R.id.imageButton,       WidgetProvider.buildButtonPendingIntent(context));
}

That is all, no more hiccups!

like image 20
Muhammad Ali Avatar answered Sep 17 '22 14:09

Muhammad Ali