When I'm running in debugging mode I can't seem to reach any breakpoints that are inside of the service, why is that?
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
context.startService(new Intent(context, UpdateService.class));
}
public static class UpdateService extends Service {
#Override
public void onStart(Intent intent, int startId) {
// Build the widget update for today
RemoteViews updateViews = buildUpdate(this);
// Push update for this widget to the home screen
ComponentName thisWidget = new ComponentName(this, WidgetProvider.class);
AppWidgetManager manager = AppWidgetManager.getInstance(this);
manager.updateAppWidget(thisWidget, updateViews);
}
public RemoteViews buildUpdate(Context context) {
return new RemoteViews(context.getPackageName(), R.id.widget_main_layout);
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
}
The "onUpdate"-method is only executed if the widget is initalized (e.g. put on the homescreen) or the updatePeriodMillis are expired. If you want to execute the service e.g. by a click on the widget, you have to "attach" a pending intent like this:
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
final Intent intent = new Intent(context, UpdateService.class);
PendingIntent pendingIntent = PendingIntent.getService(context, 0, intent, 0);
// Get the layout for the App Widget and attach an on-click listener to
// the button
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout....);
views.setOnClickPendingIntent(R.id.button, pendingIntent);
for(int i=0,n=appWidgetIds.length;i<n;i++){
int appWidgetId = appWidgetIds[i];
appWidgetManager.updateAppWidget(appWidgetId , views);
}
(cleaned up version of a working widget).
The point is, that the onUpdate() method is really very seldom executed. The real interaction with a widget is specified through pending intents.
Your Service might not be registered in the manifest. Or your AppWidgetProvider might not be registered in the manifest.
You might want to think of not using a service for what you're doing. If it's just running the updateViews() once a day then consider just setting android:updatePeriodMillis to 86400000 in the XML file that's linked to your appwidget. Your XML file would look something like this:
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="72dp"
android:maxWidth="72dp"
android:updatePeriodMillis="86400000" >
</appwidget-provider>
This will have android update your appwidget once a day without having a service run in the background that might get killed by a task killer that the user is running which then stops your widget from updating. Just a note, if you need it to update faster than every 30 minutes then android:updatePeriodMillis won't work (it's minimum value is 30 minutes) at that point I'd recommend using an AlarmManager since that'll use up less battery than a Service and also won't be killed by task killers.
Related
Good Day! I want to add text from inside application to widget, i have a main activity and it has list view and lots of text contents and it has a button to add the text to widget via shared preference, it's works fine when i close the widget and recreate it only, otherwise it's not automatically refresh.if anyone know; how to solve this please help me. here i attached the widget code below.
public class WidgetMaster extends AppWidgetProvider {
static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
int appWidgetId) {
Intent intentHome = new Intent(context, MainActivity.class);
PendingIntent pendingIntentHome = PendingIntent.getActivity(context, 0, intentHome, 0);
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_master);
views.setOnClickPendingIntent(R.id.wid_home, pendingIntentHome);
final SharedPreferences sharedPreferencestoWi = context.getSharedPreferences(String.valueOf(R.string.addTextToWidgetPref), MODE_PRIVATE);
String forWidget = sharedPreferencestoWi.getString("textToWidget", "");
String dum = "add from reading";
if(forWidget.equals("")){
views.setTextViewText(R.id.dum_appwidget_text, dum);
appWidgetManager.updateAppWidget(appWidgetId, views);
} else {
views.setTextViewText(R.id.appwidget_text, forWidget);
views.setViewVisibility(R.id.appwidget_text, 0);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}
#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
}
}
How do you update the widget from mainActivity?
In the widget configuration file you can specify a fixed update interval. The smallest update interval is 1800000 milliseconds (30 minutes).
But its better to update widget programmatically, to do this You should send a broadCast to update widget and use a
method like alarmManager or Handler for a repeating task for example you can use the following broadCast to update widget form mainActivity:
Intent intent = new Intent(this, WidgetMaster.class);
intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
int[] ids = AppWidgetManager.getInstance(getApplication())
.getAppWidgetIds(new ComponentName(getApplication(),WidgetMaster.class));
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, ids);
sendBroadcast(intent);
I am trying to make a widget for my app, and I want it to be with a buttonm progress bar and text view, which would later be changed, so I need to somehow work with the views themselves, like I can from an activity, show a view, hide a view, change a button background etc...
I tried tweaking with the sample code from the Android documentations, but I can only start an activity with this
public class WidgetProvider extends AppWidgetProvider {
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
final int N = appWidgetIds.length;
for (int i = 0; i < N; i++) {
int appWidgetId = appWidgetIds[i];
Intent intent = new Intent(context, ActivityMain.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget_layout);
views.setOnClickPendingIntent(R.id.sync_button, pendingIntent);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}
#Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
}
}
Does the widget need to be connected to an activity in order to make actions (connect to the internet, write in the database, write in the objects of the apps instance (if there is one))? And can I work with views the way I am asking?
Outside of setting on-click PendingIntents on views, there isn't much you can do inside of a widget. The standard recipe is:
Make a PendingIntent that sends a broadcast (PendingIntent.getBroadcast()) and set it on the appropriate view in your widget.
In the BroadcastReceiver that receives the intent, you update the widget to show a spinner and start a Service to do whatever long-running work you want to do (e.g connect to the internet).
Once that work is done, you can update your widget again and remove the spinner.
I created an AppWidget for my App and setup the updatePeriodMillis to 0,
because this Widget is not doing anything, if the user does not interact.
Everything works fine, untill Android cleans the ram. Then the widget won't respond anymore until the App is started again or the device is rebooted (in both cases the onUpdate() will run again).
So my question: What do I need to do, to bring it back to work, after Android kicked out the Application?
This is part of the manifest:
<receiver android:name="WidgetProvider" >
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="PATH.widgetBtnStartClicked" />
</intent-filter>
<meta-data android:name="android.appwidget.provider"
android:resource="#xml/appwidget_provider_info" />
</receiver>
This is part of my WidgetProvider:
public class WidgetProvider extends AppWidgetProvider {
private static final String BTN_START_CLICKED = "PATH.widgetBtnStartClicked";
private static Values values;
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
// get RemoteView (widget):
for (int i = 0; i < appWidgetIds.length; i++) {
int appWidgetId = appWidgetIds[i];
RemoteViews views = new RemoteViews(context.getPackageName(),
R.layout.appwidget);
// Register onClick for App-start-button:
Intent intentLaunch = new Intent(BTN_APP_LAUNCH_CLICKED);
intentLaunch.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntentLaunch = PendingIntent.getBroadcast(
context, appWidgetId, intentLaunch,
PendingIntent.FLAG_UPDATE_CURRENT);
views.setOnClickPendingIntent(R.id.appwidget_btn_launch,
pendingIntentLaunch);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}
#Override
public void onReceive(Context context, Intent intent) {
RemoteViews views = new RemoteViews(context.getPackageName(),
R.layout.appwidget);
super.onReceive(context, intent);
AppWidgetManager appWidgetManager = AppWidgetManager
.getInstance(context);
ComponentName componentName = new ComponentName(context,
WidgetProvider.class);
if (intent.getAction().equals(BTN_APP_LAUNCH_CLICKED)) {
//do some stuff..
}
// update views
appWidgetManager.updateAppWidget(componentName, views);
}
I hope there is everything you need to understand the problem. Just tell me, if not!
I think your app relies only on onUpdate() to refresh the widget. There are other events that cause the pending intents to 'drop off' the widget.
Such as the RAM clearing you mention.
I recommend you:
+ put your widget update code in a separate service class
+ have that class triggered when different events happen. onUpdate() and other events, example, the one that causes your RAM to be cleared.
+ ensure you update everything each time with remoteviews, because no old pending intents etc are preserved.
You can take total control over the events that trigger the widget to update.
If it suits your situation, you can also set an arbitrary alarm, using the alarmmanager and a receiver class. in this way, you can set the alarm to only be received when the phone wakes, and use that to call your update service class. in your update service class, then clear any alarm (if the update is called from another event) and set another alarm.
There are lots of questions on SO about who to use a service with widgets. It shouldnt take long to work it out. To put that info here is outside of the scope of this question.
I have created a widget which show countdown at every second.
But sometimes randomly its stops and never starts, i have to remove it from screen and again add to home screen will do it start.
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
final AppWidgetManager mngr = appWidgetManager;
new CountDownTimer(endTime.getTimeInMillis(), 1000) {
public void onTick(long millisUntilFinished) {
updateClockValues(c, mngr);
}
public void onFinish() {
}
}.start();
}
private void updateClockValues(Context context, AppWidgetManager mngr) {
System.out.println("update widget function");
RemoteViews remoteViews;
AppWidgetManager appWidgetManager = mngr;
ComponentName thisWidget;
final long sec = // some code to find seconds...and other values
// Get views for widget
remoteViews = new RemoteViews(context.getPackageName(),
R.layout.widgetxml);
thisWidget = new ComponentName(context, BreakingDownWidget.class);
remoteViews.setOnClickPendingIntent(R.id.rlMain, configPendingIntent);
remoteViews.setTextViewText(R.id.txtSec, sec);
// Update widget
appWidgetManager.updateAppWidget(thisWidget, remoteViews);
}
Any one can tell me, how to start widget again when getting focus, sometimes after switching between screens will stop this.
Thanks in advance.
I have created a widget which show countdown at every second.
Please do not do that. You are wasting the user's CPU time and battery life. App widgets are designed to be updated every few minutes, not once per second.
But sometimes randomly its stops and never starts, i have to remove it from screen and again add to home screen will do it start.
Of course. An AppWidgetProvider is a manifest-registered BroadcastReceiver. These components are supposed to live for a few milliseconds, long enough for onReceive() to complete, then go away. Android can and will terminate your process afterwards, if it needs the RAM. Your CountDownTimer is forking a background thread, which is not supported from a manifest-registered BroadcastReceiver.
I am currently learning about widgets in Android.
I want to create a WIFI widget that will display the SSID, the RSSI (Signal) level.
But I also want to be able to send it data from a service I am running that calculates the Quality of Sound over wifi.
Here is what I have after some reading and a quick tutorial:
public class WlanWidget extends AppWidgetProvider{
RemoteViews remoteViews;
AppWidgetManager appWidgetManager;
ComponentName thisWidget;
WifiManager wifiManager;
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
Timer timer = new Timer();
timer.scheduleAtFixedRate(new WlanTimer(context, appWidgetManager), 1, 10000);
}
private class WlanTimer extends TimerTask{
RemoteViews remoteViews;
AppWidgetManager appWidgetManager;
ComponentName thisWidget;
public WlanTimer(Context context, AppWidgetManager appWidgetManager) {
this.appWidgetManager = appWidgetManager;
remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget);
thisWidget = new ComponentName(context, WlanWidget.class);
wifiManager = (WifiManager)context.getSystemService(Context.WIFI_SERVICE);
}
#Override
public void run() {
remoteViews.setTextViewText(R.id.widget_textview,
wifiManager.getConnectionInfo().getSSID());
appWidgetManager.updateAppWidget(thisWidget, remoteViews);
}
}
The above seems to work ok, it updates the SSID on the widget every 10 seconds.
However what is the most efficent way to get the information from my service that will be already running to update periodically on my widget?
Also is there a better approach to updating the the widget rather than using a timer and timertask? (Avoid polling)
UPDATE
As per Karan's suggestion I have added the following code in my Service:
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget);
ComponentName thisWidget = new ComponentName( context, WlanWidget.class );
remoteViews.setTextViewText(R.id.widget_QCLevel, " " + qcPercentage);
AppWidgetManager.getInstance( context ).updateAppWidget( thisWidget, remoteViews );
This gets run everytime the RSSI level changes but it still never updates the TextView on my widget, any ideas why?
EDIT
Got it working, thanks Karan
You can use the following code to update the data of widget :
ComponentName thisWidget = new ComponentName( getContext(), <ProviderClass> );
AppWidgetManager.getInstance( getContext() ).updateAppWidget( thisWidget, rempoteViews );
If you look at the documentation about widgets, you are supposed to be able to set a time between 2 updates :
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="294dp"
android:minHeight="72dp"
android:updatePeriodMillis="86400000"
android:initialLayout="#layout/example_appwidget"
android:configure="com.example.android.ExampleAppWidgetConfigure" >
With this, you should be able to put any period you want ?
(It mentions that the update might not occur directly after your call for it, and henceforce to do it as often as possible but you have to take care of the battery)