iTamp
iTamp

Reputation: 803

Update Android ListView in Widget

I have a problem with my App-Widget when i try to update the content.

The widget looks like this: https://i.sstatic.net/tEGLv.jpg

The Widget consists of a Header (Buttons + TextViews) and a ListView. If the User press a Button the ListView shows the content of the next day and everything works fine. But the problem is, if i try to update the widget from my app or the automatically timeperiod the ListView doenst update.

Here the my Code.

AppWidgetProvider:

public class StudyWidgetProvider extends AppWidgetProvider{

private static String BUTTON_BACK = "BUTTON_BACK";
private static String BUTTON_FORWARD = "BUTTON_FORWARD";

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

@Override
public void onReceive(Context context, Intent intent) {
    super.onReceive(context, intent);
    if(WidgetViewsFactory.currentDate == null){
        WidgetViewsFactory.currentDate = Calendar.getInstance();
    }

    String action = intent.getAction();
    if(action != null){
        if(action.equals(BUTTON_BACK)){
            WidgetViewsFactory.currentDate.add(Calendar.DATE, -1);
        }
        if(action.equals(BUTTON_FORWARD)){
            WidgetViewsFactory.currentDate.add(Calendar.DATE, 1);
        }
    }

    context.startService(new Intent(context, UpdateService.class));
}   
 }

The UpdateService which handles the update of the Widget.

    @Override
@Deprecated
public void onStart(Intent intent, int startId) {
    super.onStart(intent, startId);
    Log.i(LOG_TAG, "Update-Service started");

    RemoteViews widget = buildUpdate(this);
    ComponentName thisWidget = new ComponentName(this, StudyWidgetProvider.class);
    AppWidgetManager manager = AppWidgetManager.getInstance(this);

    manager.notifyAppWidgetViewDataChanged(manager.getAppWidgetIds(thisWidget), R.id.words);
    manager.updateAppWidget(thisWidget, widget);

    Log.i(LOG_TAG, "The Content!");
    if(widgetObjects == null){
        Log.i(LOG_TAG, "WidgetObjects sind NULL");
    } else {
        Log.i(LOG_TAG, "WidgetObjects sind NICHT-NULL");

        for(int i=0; i<widgetObjects.size(); i++){
            Log.i(LOG_TAG, "--- " + widgetObjects.get(i).getName());
        }
    }

    Log.i(LOG_TAG, "Update-Service ended");
}


public RemoteViews buildUpdate(Context context){
    RemoteViews retVal = new RemoteViews(context.getPackageName(), R.layout.widget);

    if(WidgetViewsFactory.currentDate == null){
        WidgetViewsFactory.currentDate = Calendar.getInstance();
    }

    AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
    ComponentName thisAppWidget = new ComponentName(context.getPackageName(), StudyWidgetProvider.class.getName());
    int[] appWidgetIds = appWidgetManager.getAppWidgetIds(thisAppWidget);

    loadSDCardContent(context, appWidgetManager, appWidgetIds);

    //Setzen des Widget-UIs
    Intent intent = new Intent(context, WidgetService.class);
    intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds);
    intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));

    retVal.setRemoteAdapter(R.id.words, intent);

    SimpleDateFormat dateFormater = new SimpleDateFormat("EEEE");
    retVal.setTextViewText(R.id.widget_day, dateFormater.format(WidgetViewsFactory.currentDate.getTime()));
    dateFormater = new SimpleDateFormat("dd.MM.yyyy");
    retVal.setTextViewText(R.id.widget_date, dateFormater.format(WidgetViewsFactory.currentDate.getTime()));

    //Button-Actions
    Intent backIntent = new Intent(context, StudyWidgetProvider.class);
    backIntent.setAction(BUTTON_BACK);
    Intent forwardIntent = new Intent(context, StudyWidgetProvider.class);
    forwardIntent.setAction(BUTTON_FORWARD);
    PendingIntent backPendingIntent = PendingIntent.getBroadcast(context, 0, backIntent, PendingIntent.FLAG_UPDATE_CURRENT);
    PendingIntent forwardPendingIntent = PendingIntent.getBroadcast(context, 0, forwardIntent, PendingIntent.FLAG_UPDATE_CURRENT);
    retVal.setOnClickPendingIntent(R.id.widget_but_back, backPendingIntent);
    retVal.setOnClickPendingIntent(R.id.widget_but_forward, forwardPendingIntent);

    Intent clickIntent = new Intent(context, WidgetActivity.class);
    PendingIntent clickPI=PendingIntent.getActivity(context, 0, clickIntent, PendingIntent.FLAG_UPDATE_CURRENT);
    retVal.setPendingIntentTemplate(R.id.words, clickPI);

    return retVal;
}

And heres how i update the widget from my app:

public RemoteViews buildUpdate(Context context){
    RemoteViews retVal = new RemoteViews(context.getPackageName(), R.layout.widget);

    if(WidgetViewsFactory.currentDate == null){
        WidgetViewsFactory.currentDate = Calendar.getInstance();
    }

    AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
    ComponentName thisAppWidget = new ComponentName(context.getPackageName(), StudyWidgetProvider.class.getName());
    int[] appWidgetIds = appWidgetManager.getAppWidgetIds(thisAppWidget);

    loadSDCardContent(context, appWidgetManager, appWidgetIds);

    //Setzen des Widget-UIs
    Intent intent = new Intent(context, WidgetService.class);
    intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetIds);
    intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));

    retVal.setRemoteAdapter(R.id.words, intent);

    SimpleDateFormat dateFormater = new SimpleDateFormat("EEEE");
    retVal.setTextViewText(R.id.widget_day, dateFormater.format(WidgetViewsFactory.currentDate.getTime()));
    dateFormater = new SimpleDateFormat("dd.MM.yyyy");
    retVal.setTextViewText(R.id.widget_date, dateFormater.format(WidgetViewsFactory.currentDate.getTime()));

    //Button-Actions
    Intent backIntent = new Intent(context, StudyWidgetProvider.class);
    backIntent.setAction(BUTTON_BACK);
    Intent forwardIntent = new Intent(context, StudyWidgetProvider.class);
    forwardIntent.setAction(BUTTON_FORWARD);
    PendingIntent backPendingIntent = PendingIntent.getBroadcast(context, 0, backIntent, PendingIntent.FLAG_UPDATE_CURRENT);
    PendingIntent forwardPendingIntent = PendingIntent.getBroadcast(context, 0, forwardIntent, PendingIntent.FLAG_UPDATE_CURRENT);
    retVal.setOnClickPendingIntent(R.id.widget_but_back, backPendingIntent);
    retVal.setOnClickPendingIntent(R.id.widget_but_forward, forwardPendingIntent);

    Intent clickIntent = new Intent(context, WidgetActivity.class);
    PendingIntent clickPI=PendingIntent.getActivity(context, 0, clickIntent, PendingIntent.FLAG_UPDATE_CURRENT);
    retVal.setPendingIntentTemplate(R.id.words, clickPI);

    return retVal;
}

The strange thing is when i hit the button of the widget, everythings work as i wish. The onDatasetChanged-method of my listview gets called and the content is changing, but if i try this from my app nothing happens

I hope someone of you have an idea why this isnt working. Im stuck on this for now 2 days and i have no clue...

Thanks for helping!

EDIT Ive found out that this isnt working on my device (htc with miui v4) but on the emulator.

EDIT 2 I installed Android 4 (with Sense 4) on my device, and after that it worked too. It looks like MIUI was the problem.

Upvotes: 3

Views: 6808

Answers (3)

vikas kumar
vikas kumar

Reputation: 11018

This works

 @Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
    super.onUpdate(context, appWidgetManager, appWidgetIds);
    for (int widgetId : appWidgetIds) {
        RemoteViews mView = initViews(context, appWidgetManager, widgetId);
        appWidgetManager.updateAppWidget(widgetId, mView);
    }

    super.onUpdate(context, appWidgetManager, appWidgetIds);
}



@SuppressWarnings("deprecation")
@SuppressLint("NewApi")
private RemoteViews initViews(Context context,
                              AppWidgetManager widgetManager, int widgetId) {

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

    Intent intent = new Intent(context, WidgetService.class);
    intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, widgetId);

    intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));
    mView.setRemoteAdapter(widgetId, R.id.widgetCollectionList, intent);

    return mView;
}

Upvotes: 0

Nic Wilson
Nic Wilson

Reputation: 170

I'm going to necro this question because I had the same issue and found a solution.

              manager.notifyAppWidgetViewDataChanged

This sends a call to onDataSetChanged() in your RemoteViewsFactory. Add a call to build your Views in that method. This solved all my problems.

Upvotes: 7

Code Droid
Code Droid

Reputation: 10472

Communicate with the Widget via Broadcasts only. Dont call it directly like this. Use stickyBroadcasts if needed.

Upvotes: 1

Related Questions