Access layout elements from inside the AppWidgetProvider widget

I'm starting to go crazy trying to figure it out. It seems to be very easy, I'm starting to wonder if this is possible.

What I'm trying to do is create a home screen widget that contains only ImageButton. When pressed, the idea is to change some setting (e.g. wi-fi switch) and then change the image of the buttons.

I have an ImageButton declared this way in my main.xml

<ImageButton android:id="@+id/buttonOne" android:src="@drawable/button_normal_ringer" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" /> 

my AppWidgetProvider class named ButtonWidget

*** note that the RemoteViews class is a locally stored variable. this allowed me to access the layout elements of RViews ... or so I thought.

 @Override public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) { remoteViews = new RemoteViews(context.getPackageName(), R.layout.main); Intent active = new Intent(context, ButtonWidget.class); active.setAction(VIBRATE_UPDATE); active.putExtra("msg","TESTING"); PendingIntent actionPendingIntent = PendingIntent.getBroadcast(context, 0, active, 0); remoteViews.setOnClickPendingIntent(R.id.buttonOne, actionPendingIntent); appWidgetManager.updateAppWidget(appWidgetIds, remoteViews); } @Override public void onReceive(Context context, Intent intent) { // v1.5 fix that doesn't call onDelete Action final String action = intent.getAction(); Log.d("onReceive",action); if (AppWidgetManager.ACTION_APPWIDGET_DELETED.equals(action)) { final int appWidgetId = intent.getExtras().getInt( AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID); if (appWidgetId != AppWidgetManager.INVALID_APPWIDGET_ID) { this.onDeleted(context, new int[] { appWidgetId }); } } else { // check, if our Action was called if (intent.getAction().equals(VIBRATE_UPDATE)) { String msg = "null"; try { msg = intent.getStringExtra("msg"); } catch (NullPointerException e) { Log.e("Error", "msg = null"); } Log.d("onReceive",msg); if(remoteViews != null){ Log.d("onReceive",""+remoteViews.getLayoutId()); remoteViews.setImageViewResource(R.id.buttonOne, R.drawable.button_pressed_ringer); Log.d("onReceive", "tried to switch"); } else{ Log.d("F!", "--naughty language used here!!!--"); } } super.onReceive(context, intent); } } 

So, I tested this, and the onReceive method works fine, I can send notifications and all kinds of materials (removed from the code for readability)

what I cannot do is change any properties of the elements of the view.

To fix this, I made RemoteViews a local and static private variable. Using the log, I could see that when there are several instances of the application on the screen, they all refer to the same instance of RemoteView. perfect for what I'm trying to do

The problem is trying to change the ImageButton image.

I can do this from within the onUpdate method using this.

 remoteViews.setImageViewResource(R.id.buttonOne, R.drawable.button_pressed_ringer); 

which does not bring me any benefit, although after creating the widget. For some reason, despite the fact that inside one class it is inside the onReceive method, this line does not work.

This line was used to sketch the Null pointer until I changed the variable to static. now it passes a null test, refers to the same layout as at the beginning, reads a line, but does nothing.

It, like the code, does not even exist, just twitches.

SO ......

Is there any way to change the layout elements from the widget after creating the widget !? I want to do this based on the environment, not with running the configuration.

I have addressed various issues, and this seems to be a problem that really has not been resolved, such as link text and link text

oh, and for those who find this and want a good initial tutorial for widgets, it’s easy to keep track of (although a little outdated, it’s convenient for you with widgets) .pdf link text

hope someone can help here. I seem to have a feeling that this is illegal, and there is another way to go about this. I LOVE to be told a different approach !!!!

thanks

+4
source share
2 answers

You can redraw the screen using a different layout, only with a modified ImageButton. It sounds like a hacker solution, but it works for me.

 // Your appWidgetProvider class should track which layout it currently on private static int layoutId; // onReceive should be something like this @Override public void onReceive(Context context, Intent intent) { Bundle bundle = intent.getExtras(); if (bundle != null) { int newLayoutId = bundle.getInt("layout_id"); // Change the current layout id to the layout id contained in the bundle layoutId = newLayoutId; initViews(context); } else { initViews(context); } } // Initialize the view according to the chosen layout private void initViews(Context context) { RemoteViews views = null; // Set the initial layout if (layoutId == 0) { Intent layoutIntent = new Intent("android.appwidget.action.APPWIDGET_UPDATE"); Bundle layoutBundle = new Bundle(); // I put in the layoutId of the next layout. Note that the layoutId is not // from R. I just made up some easy to remember number for my layoutId layoutBundle.putInt("layout_id", 1); PendingIntent lPendingIntent = PendingIntent.getBroadcast(context, 0, layoutIntent, PendingIntent.FLAG_ONE_SHOT); // Set the layout to the first layout views = new RemoteViews(context.getPackageName(), R.layout.layout_zero); // I used buttons to trigger a layout change views.setOnClickPendingIntent(R.id.btnNext, lPendingIntent); } // Else if there some trigger to change the layout... else if (layoutId == 1) { Intent layoutIntent = new Intent("android.appwidget.action.APPWIDGET_UPDATE"); Bundle layoutBundle = new Bundle(); // Since I only have two layouts, I put here the id of the previous layout layoutBundle.putInt("layout_id", 0); PendingIntent lPendingIntent = PendingIntent.getBroadcast(context, 0, layoutIntent, PendingIntent.FLAG_ONE_SHOT); // Set the layout to the second layout // This layout should be almost the same as the first layout except for the // part that you want to change views = new RemoteViews(context.getPackageName(), R.layout.layout_one); views.setOnClickPendingIntent(R.id.btnPrev, lPendingIntent); } } 

As you can see, I used two different layouts that the user can switch by clicking. You can use different triggers to change the layout depending on what you need. A similar solution can be found link text . Forgive me for putting the code in onReceive instead of onUpdate :)

+2
source

@Avendael Your code works great. The only thing you need to do is add an update widget. Something like that

 public static void buildUpdate(Context context) { RemoteViews updateViews; //Have your own condition here if (1==1){ layoutId = R.layout.main; } else { layoutId = R.layout.main1; } updateViews = new RemoteViews(context.getPackageName(), layoutId); //actually do things here //then finally, return our remoteView AppWidgetManager.getInstance(context).updateAppWidget( new ComponentName(context, ButtonWidget.class), updateViews); 

}

Call this buildUpdate method (context) after assigning a new remote view to update the widget layout. For example, we can post this after views.setOnClickPendingIntent (); in the code above. This is a really great approach, was very helpful for me with greetings ...

0
source

Source: https://habr.com/ru/post/1316271/


All Articles