Ahmadjoni Muhamad
Ahmadjoni Muhamad

Reputation: 51

Android Widget - update when a button is clicked

Good day. I'm trying to create a widget that will show the balance on the screen. Created 2 buttons and set up the listener to determine which button was pressed.

Difficulty: How to update data by clicking on the button or reload the widget so that the data is updated?

import android.app.AlarmManager;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.RemoteViews;
import android.widget.Toast;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.text.DateFormat;
import java.util.Date;

public class EthWidgetProvider extends AppWidgetProvider {
    private static final String SYNC_CLICKED    = "automaticWidgetSyncButtonClick";
    private static final String SYNC_CLICKED2    = "automaticWidgetSyncButtonClick2";


    static void updateAppWidget(final Context context, final AppWidgetManager appWidgetManager, final int appWidgetId) {
        RequestSingleton.getInstance(context).fetchData(new VolleyCallback() {
            @Override
            public void onSuccessRequest(JSONArray result) {
                Log.i("Response", result.toString());
                String price = "";
                try {
                    JSONObject etherObject = result.getJSONObject(0);
                    price = etherObject.getString("price_usd");
                } catch (JSONException e) {
                    Log.e("JSONException", e.toString());
                }
                Log.i("Price", price);
                RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.example_widget);
                views.setTextViewText(R.id.gprs, "$" + price);

                String currentDateTimeString = DateFormat.getDateTimeInstance().format(new Date());
                views.setTextViewText(R.id.timeofday, currentDateTimeString);

                appWidgetManager.updateAppWidget(appWidgetId, views);
            }
        });
    }
    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {


        RemoteViews remoteViews;
        ComponentName watchWidget;

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

        remoteViews.setOnClickPendingIntent(R.id.refresh, getPendingSelfIntent(context, SYNC_CLICKED));
        remoteViews.setOnClickPendingIntent(R.id.example_widget_button, getPendingSelfIntent(context, SYNC_CLICKED2));
        appWidgetManager.updateAppWidget(watchWidget, remoteViews);

        for(int appId : appWidgetIds) {
            updateAppWidget(context, appWidgetManager, appId);
        }
    }

    @Override
    public void onReceive(Context context, Intent intent) {
        // TODO Auto-generated method stub
        super.onReceive(context, intent);

        if (SYNC_CLICKED.equals(intent.getAction())) {

            AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);

            RemoteViews remoteViews;
            ComponentName watchWidget;

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

            remoteViews.setTextViewText(R.id.timeofday, "TESTING");

            appWidgetManager.updateAppWidget(watchWidget, remoteViews);

        }

        if (SYNC_CLICKED2.equals(intent.getAction())) {

            AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);

            RemoteViews remoteViews;
            ComponentName watchWidget;

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

            remoteViews.setTextViewText(R.id.timeofday, "TESTING2");

            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);
    }
}

By pressing button 1, I need to show the activity. By pressing the second button, you need to update the widget so that the data is updated, that is, so that the request to the server goes again and the data is updated.

Any help would be appreciated.

Upvotes: 4

Views: 4053

Answers (3)

fsljfke
fsljfke

Reputation: 461

There is a very helpful must-read official guide titled "Build an App Widget": (https://developer.android.com/guide/topics/appwidgets)

Please read this page carefully so you understand the concepts and focus on the AppWidgetProvider section for your problem. Although in this section, they use: PendingIntent.getActivity(), you are supposed to use a Service as PendingIntent.getService() to have your Service called on button click, and then have the Service update your Widget.

Basically you'll see that you need to:

  1. Create a Service

  2. Create a PendingIntent:

    Intent intent = new Intent(context, YourService.class);
    PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, 0);
    
  3. Set the onClickPendingIntent listener on your RemoteViews object like this:

    views.setOnClickPendingIntent(R.id.button, pendingIntent);
    

Upvotes: 1

Style-7
Style-7

Reputation: 1208

To call activity:

remoteViews.setOnClickPendingIntent( R.id.button1, PendingIntent.getActivity(context, 0, new Intent( context, Main.class), 0) );

To update widgets from another class :

AppWidgetManager appWidgetManager = AppWidgetManager.getInstance( context );
int ids[] = appWidgetManager.getAppWidgetIds( componentName );
for( int id : ids ){
    //update textView here
    appWidgetManager.updateAppWidget( id, views);
}

Upvotes: 0

l0v3
l0v3

Reputation: 973

I don't get you idea with the Broadcast.

  1. The broadcast should not be inner class
  2. Broadcast should extend BroadcastReceiver class
  3. Broadcast should be defined in manifest

So when you do this, your receiver should be called after buttons are clicked.

But, you want something to wake up your Widget. And then Widget#onUpdate will fetch the updated data (that you download on widget click) and show them. To request update of your widget, you can use something like this:

public static void updateAppWidget(@NonNull Context applicationContext,
        @NonNull Class<? extends AppWidgetProvider> widgetProviderClass) {
    final ComponentName component = new ComponentName(applicationContext, widgetProviderClass);
    final int[] widgetIds;
    try {
        widgetIds = AppWidgetManager.getInstance(applicationContext).getAppWidgetIds(component);
    } catch (RuntimeException re) {
        Log.d(re, "Unable to obtain widget IDs.");
        return;
    }

    if (widgetIds.length == 0) {
        Log.d("There is no widget to be updated.");
        return;
    }

    final Intent intent = new Intent(applicationContext, widgetProviderClass);
    intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
    intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, widgetIds);

    applicationContext.sendBroadcast(intent);
}

So to sum it up:

  • In widget setup views, listeners, and populate with last known data.
  • In listener broadcast either open Activity, or run some download
  • Don't forget BroadcastReceivers are running on UI thread; use goAsync() approach.
  • The downloaded data should be stored to some place, where widget can obtain them
  • call mentioned function to trigger widget update.

I believe, this is a quite specific and complex topic unlike the rest of Android, so feel free to ask anything I might missed :)

Upvotes: 2

Related Questions