Pergunta

Speaking in Android. I have an application and a widget. The widget is supposed to auto update every n seconds, and it works fine until the parent app is killed. Once the app is killed, it does not update any longer. This occurs on both my timer based updates and the onClickPendingIntent updates.

Is there any way to check if the parent application is running within the widget, and if it is not running to start it? (preferably without using getRunningTasks (or any other extra permissions), but if I have to that's fine)

Here's the important bits of my widget code, for debugging it will display two numbers, one number that is updated based on the timer and one number that is updated on keypress. The widget is drawn based on the timer.

    private static final String SYNC_CLICKED = "automaticWidgetSyncButtonClick";
public static int counter = 0; // time based update
public static int counter2 = 0; // onClick update


public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
    Timer timer = new Timer();
    // 2 seconds for debug   
    timer.scheduleAtFixedRate(new MyTime(context, appWidgetManager), 1, 2000);

    RemoteViews remoteViews;
    ComponentName watchWidget;
    remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_main);
    watchWidget = new ComponentName(context, HelloWidget.class);

    remoteViews.setOnClickPendingIntent(R.id.widget_textview, getPendingSelfIntent(context, SYNC_CLICKED));
    appWidgetManager.updateAppWidget(watchWidget, remoteViews);
}

protected PendingIntent getPendingSelfIntent(Context context, String action) {
    Intent intent = new Intent(context, getClass());
    intent.setAction(action);
    return PendingIntent.getBroadcast(context, 0, intent, 0);
}

public void onReceive(Context context, Intent intent) {
    super.onReceive(context, intent);

    if (SYNC_CLICKED.equals(intent.getAction())) {
        counter2++;

        AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);

        RemoteViews remoteViews;
        ComponentName watchWidget;

        remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_main);
        watchWidget = new ComponentName(context, WidgetUpdater.class);

        remoteViews.setTextViewText(R.id.widget_textview, "Updating...");

    // unrelated async task here

        appWidgetManager.updateAppWidget(watchWidget, remoteViews);

    }
}

private class MyTime extends TimerTask {
    RemoteViews widgetView;
    AppWidgetManager appWidgetManager;
    SharedPreferences settings;
    ComponentName thisWidget;


    public MyTime(Context context, AppWidgetManager appWidgetManager) {
        this.appWidgetManager = appWidgetManager;
        settings = context.getSharedPreferences("prefs", 0);
        widgetView = new RemoteViews(context.getPackageName(), R.layout.widget_main);
        thisWidget = new ComponentName(context, HelloWidget.class);
    }

    @Override
    public void run() {
        counter++;
        String hashrate = settings.getString("hashrate", null);
        String rejected = settings.getString("rejected", null);
        widgetView.setTextViewText(R.id.widget_textview, counter + "-" + counter2);
        appWidgetManager.updateAppWidget(thisWidget, widgetView);
    }
} 

Once again, when the parent app gets killed my widget stops updating. Is there any way for me to start the parent application using my onClick method in the widget if it's not presently running?

Foi útil?

Solução

The problem is eventually your AppWidgetProvider will be destroyed by the system. It's really just a BroadcastReceiver, the lifecycle of which is limited to the duration of onReceive(), as per the documentation:

A BroadcastReceiver object is only valid for the duration of the call to onReceive(Context, Intent). Once your code returns from this function, the system considers the object to be finished and no longer active.

Letting your BroadcastReceiver hold onto your TimerTask implementation will fail, as you have already experienced. The best approach it to use AlarmManager to send a PendingIntent at the next scheduled interval. This PendingIntent could either start up a BroadcastReceiver or a Service (perhaps an IntentService) which will perform the update and schedule the next alarm.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top