Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 310
Ahmadjoni Muhamad Avatar asked Oct 18 '25 04:10

Ahmadjoni Muhamad


2 Answers

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 :)

like image 65
l0v3 Avatar answered Oct 19 '25 18:10

l0v3


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);
    
like image 36
fsljfke Avatar answered Oct 19 '25 19:10

fsljfke



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!