APP Widget Textview not updating (Java, android studio) - java

I am trying to update textview in an app widget but nothing is refreshing
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
for(int appWidgetID : appWidgetIds){
Intent intent = new Intent(context, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context,0,intent,0);
RemoteViews views = new RemoteViews(context.getPackageName(),R.layout.timetable_widget);
views.setOnClickPendingIntent(R.id.btnPress,pendingIntent);
views.setTextViewText(R.id.textView2, "HELLO__WORLD");
appWidgetManager.updateAppWidget(appWidgetID,views);
}
}

Do you really receive an update broadcast? The update time for widgets is forced to at least 30mins, like this:
<appwidget-provider
...
android:updatePeriodMillis="xxx" // if set a millis less than 30mins, it will not work
...
/>
Or set the updatePeriodMillisupdate to 0 and update widget by sending custom broadcast:
Register intent-filter of your action
Receive your action in your widget' s onReceive and update the text
To prevent any ANR timeouts, we perform the update in a service.
fun updateWidget(context: Context) {
val appWidgetManager = AppWidgetManager.getInstance(context)
val widgetComponentName = ComponentName(context.packageName, YourWidget::class.java.name)
val appWidgetIds: IntArray = appWidgetManager.getAppWidgetIds(widgetComponentName)
RemoteViews(context.packageName, R.layout.your_widget).apply {
setTextViewText(R.id.text, "new text")
appWidgetManager.updateAppWidget(appWidgetIds, this)
}
}

Related

How to call a method in the Mainactivity by clicking a widget using Android studio?

I am a beginer, so be kind. I have an app with four buttons. If I run the app and click a single button, data is sent to specific device (one of four) using Bluetooth. I also have a widget that needs to call a method for data sending for the first device, so simulating a click of the first button i.e. calling a method in the Mainactivity class with a parameter 1.
Thank you for your help.
So currently from a widget I can start the Mainactivity, opening an app, but I would like to run a specific method instead.
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
// There may be multiple widgets active, so update all of them
for (int i = 0; i < appWidgetIds.length; i++) {
int appWidgetId = appWidgetIds[i];
Intent intent = new Intent(context, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.io_t3widget);
views.setOnClickPendingIntent(R.id.appwidget_text, pendingIntent);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}

onAppWidgetOptionsChanged() called on screen awake. How to prevent this?

I have a calendar widget and I'm updating it myself everyday at 12:01AM as well when the size is changed so I don't have a need for automatic update. I also set the updatePeriodMillis to 0. The problem I'm having is that the App Widget calls onAppWidgetOptionsChanged():
Every time the screen unlocks
Every time you're brought home
It wouldn't be an issue for me, but the problem is you can see for a split second the App Widget updating. Anyone know of any way I can prevent that from happening?
For reference here is part of my WidgetProvider class
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action != null) {
if (action.equals(ACTION_REFRESH) || action.equals(ACTION_NEXT) || action.equals(ACTION_PREVIOUS)) {
context.sendBroadcast(new Intent(action));
}
}
Bundle extra = intent.getExtras();
if (extra != null && extra.containsKey(KEY_APP_WIDGET_ID)) {
updateAppWidget(context, AppWidgetManager.getInstance(context), extra.getInt(KEY_APP_WIDGET_ID));
}
super.onReceive(context, intent);
}
#Override
public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions) {
int width = Util.dp2px(newOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH));
Intent broadcastIntent = new Intent(ACTION_REFRESH);
broadcastIntent.putExtra(KEY_SIZE_CHANGE, width);
context.sendBroadcast(broadcastIntent);
updateAppWidget(context, appWidgetManager, appWidgetId);
super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions);
}
private static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
int appWidgetId) {
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget);
Intent intent = new Intent(context, WidgetService.class);
views.setRemoteAdapter(R.id.widget_calendar_container, intent);
// Buttons on widget click handlers
views.setOnClickPendingIntent(R.id.widget_refresh, getPendingSelfIntent(context, ACTION_REFRESH, appWidgetId));
views.setOnClickPendingIntent(R.id.widget_next, getPendingSelfIntent(context, ACTION_NEXT, appWidgetId));
views.setOnClickPendingIntent(R.id.widget_previous, getPendingSelfIntent(context, ACTION_PREVIOUS, appWidgetId));
// Widget Container click handler
Intent homeIntent = new Intent(Intent.ACTION_MAIN);
homeIntent.addCategory(Intent.CATEGORY_LAUNCHER);
homeIntent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
homeIntent.setComponent(new ComponentName(context.getPackageName(), Home.class.getName()));
PendingIntent homePendingIntent = PendingIntent.getActivity(context, 0, homeIntent, 0);
views.setPendingIntentTemplate(R.id.widget_calendar_container, homePendingIntent);
// Instruct the widget manager to update the widget
appWidgetManager.updateAppWidget(appWidgetId, views);
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetId, R.id.widget_calendar_container);
}
I prefer another answer, but this is what I got so far.
#Override
public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions) {
int width = Util.dp2px(newOptions.getInt(AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH));
if (width != WidgetRemoteViewsFactory.width) {
Intent broadcastIntent = new Intent(ACTION_REFRESH);
broadcastIntent.putExtra(KEY_SIZE_CHANGE, width);
LocalBroadcastManager.getInstance(context).sendBroadcast(broadcastIntent);
updateAppWidget(context, appWidgetManager, appWidgetId);
super.onAppWidgetOptionsChanged(context, appWidgetManager, appWidgetId, newOptions);
}
}
I made the field I am interested in width static on WidgetRemoteViewsFactory and I am only broadcasting when that field changes. I can't seem to prevent onAppWidgetOptionsChanged() from being called because AppWidgetManager.ACTION_APPWIDGET_OPTIONS_CHANGED is being broadcasted and received every time the screen is awaken.
Android Documentation says
Called in response to the AppWidgetManager.ACTION_APPWIDGET_OPTIONS_CHANGED broadcast when this widget has been layed out at a new size. -
AppWidgetProvider#onAppWidgetOptionsChanged
But that action is being broadcasted every time the screen awakens.
If anyone has a better solution, please feel free to post it. There has to be a better solution or this is a bug on Android's side.

Android widget talk to service and service talk to widget

I have an Android app whose service is started when app starts and when app is killed, service is also destroyed.
I have a home screen widget starting alongside with app. It has 3 imageviews - "Play","Next","Previous".
On press of any of these imageview in widget, they need to talk to service and service talks to library etc.
When service has an answer, it responds to widget with status OK or NO. Based on the response, I need to update the imageviews.
When the app is killed, I need to gray out my widget fully. In this situation, when I click on the greyed out widget, I need to start the app. Could anyone help me please
how I could achieve this.
Here is my widget code -
public class MyWidgetProvider extends AppWidgetProvider {
private Intent serviceIntent;
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
RemoteViews remoteViews;
ComponentName componentName;
remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
componentName = new ComponentName(context, ControlScreenWidgetProvider.class);
remoteViews.setOnClickPendingIntent(R.id.PLAY,getPendingSelfIntent(context, "PLAY",componentName));
remoteViews.setOnClickPendingIntent(R.id.NEXT,getPendingSelfIntent(context, "NEXT",componentName));
remoteViews.setOnClickPendingIntent(R.id.PREVIOUS,getPendingSelfIntent(context, "PREVIOUS",componentName));
appWidgetManager.updateAppWidget(componentName, remoteViews);
}
#Override
public void onReceive(Context context, Intent intent)
{
super.onReceive(context, intent);
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
RemoteViews remoteViews;
ComponentName componentName;
remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
componentName = new ComponentName(context, MyWidgetProvider.class);
if ("PLAY".equals(intent.getAction())) {
remoteViews.setOnClickPendingIntent(R.id.PLAY,getPendingSelfIntent(context, "PLAY",componentName));
// Dont know what to do here
}
else if ("NEXT".equals(intent.getAction())) {
remoteViews.setOnClickPendingIntent(R.id.lock_door,getPendingSelfIntent(context, "NEXT",componentName));
// Dont know what to do here
}
else if ("PREVIOUS".equals(intent.getAction())) {
remoteViews.setOnClickPendingIntent(R.id.lock_door,getPendingSelfIntent(context, "PREVIOUS",componentName));
// Dont know what to do here
}
appWidgetManager.updateAppWidget(componentName, remoteViews);
}
protected PendingIntent getPendingSelfIntent(Context context, String action, ComponentName componentName) {
Intent intent = new Intent(context, MyWidgetProvider.class);
intent.setAction(action);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, componentName);
return PendingIntent.getService(context, 0, intent, 0);
}
}

Onclick Event for Android Widget

I've read about 10 posts now about onclick events and Widgets and I understand they are implemented differently. However, despite the success other people are having I seem to be finding it impossible to get it to work. I'm using Android Studio 2.2 and have created a simple test app. I have a button called button. I want a toast to display when I press the button.
I've copied the code as suggested in the other posts. Can someone take a look and see if I am doing anything wrong?
public class NewAppWidget extends AppWidgetProvider {
private static final String MyOnClick = "myOnClickTag";
protected PendingIntent getPendingSelfIntent(Context context, String action) {
Intent intent = new Intent(context, getClass());
intent.setAction(action);
return PendingIntent.getBroadcast(context, 0, intent, 0);
}
void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
int appWidgetId) {
CharSequence widgetText = context.getString(R.string.appwidget_text);
// Construct the RemoteViews object
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.new_app_widget);
views.setOnClickPendingIntent(R.id.button, getPendingSelfIntent(context, MyOnClick));
views.setTextViewText(R.id.appwidget_text, widgetText);
// Instruct the widget manager to update the widget
appWidgetManager.updateAppWidget(appWidgetId, views);
}
//RemoteViews.setOnClickPendingIntent(R.id.button, getPendingSelfIntent(context, MyOnClick));
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
// There may be multiple widgets active, so update all of them
for (int appWidgetId : appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId);
}
}
#Override
public void onEnabled(Context context) {
// Enter relevant functionality for when the first widget is created
}
#Override
public void onDisabled(Context context) {
// Enter relevant functionality for when the last widget is disabled
}
#Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);//add this line
if (MyOnClick.equals(intent.getAction())){
//your onClick action is here
//display in short period of time
Toast.makeText(context, "msg msgasdasd", Toast.LENGTH_SHORT).show();
}
};
}
OK - really weird. Restarted the android emulator and it started working.
Mmmmm.
Cheers

Android Widget - How to check if parent app is running

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?
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.

Categories

Resources