The problem is that after I use the built in Task Manager's Clean Memory/Ram, My widget stops working .I guess this is related to the Task Manager's method of cleaning RAM.After a lot of research and some attempts, I found that i need
BroadcastReciever to listen to package changes and updates:
So i implemented but its not working because document says that the Restarted/Cleared package does not receive this broadcast
register receiver in the manifest file:
<receiver android:name="com.app.lab.receiver.onRestartReciever">
<intent-filter>
<action android:name="android.intent.action.PACKAGE_REPLACED" />
<action android:name="android.intent.action.PACKAGE_RESTARTED" />
<action android:name="android.intent.action.PACKAGE_DATA_CLEARED"/>
<data android:scheme="package" />
</intent-filter>
PACKAGE_REPLACED - called in particular to notify application update.
PACKAGE_RESTARTED - called when most memory cleaners are cleaning memmory.
the "data" row is used to monitor action applied for the specific package.
public class onRestartReciever extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
Log.d("DEBUG", "onRestartReciever");//I am not getting this log on clearing memory from task manager
}
}
I tried to use dummy service to get its lifecycle ie to check when onDestroy is called but what I found it not a reliable way ,onDestroy may not be called when application is killed by Task Manager.
So finally, my question : Is there any way to tell the android system to reStart appWidgets when Task manager or OS cleans memory .
Note: My widget contains only one button that launches an Activity.It works most of the time but stops responding if OS itself cleans memory or user forcefully do it from task manager.I've downloaded some of the widget it seem to continue working fine after cleaning memory also.
Update: To under my problem no need of going through complete code it is simple Application . My application dose not contain any Activty or Service. It contains only widget with one button which gives toast message.There is only two class in my application(WidgetProvider and onRestartReciever) thats it
Widget class WidgetProvider.class
public class WidgetProvider extends AppWidgetProvider {
private RemoteViews remoteViews;
private ComponentName watchWidget;
PendingIntent pi;
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
remoteViews = new RemoteViews(context.getPackageName(),
R.layout.touchwidget);
Intent toggleClickPlayer = new Intent(context.getApplicationContext() ,WidgetProvider.class);
toggleClickPlayer.setAction("PLAYER");
PendingIntent toggleIntentPlayer = PendingIntent.getBroadcast(context,0, toggleClickPlayer,endingIntent.FLAG_CANCEL_CURRENT);
remoteViews.setOnClickPendingIntent(R.id.player, toggleIntentPlayer);
appWidgetManager.updateAppWidget(appWidgetIds, remoteViews);
}
#Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
watchWidget = new ComponentName(context,WidgetProvider.class);
remoteViews = new RemoteViews(context.getPackageName(),R.layout.touchwidget);
Toast.makeText(context, " Player started",Toast.LENGTH_SHORT).show();
(AppWidgetManager.getInstance(context)).updateAppWidget(watchWidget, remoteViews);
}
}
}
Widget does not bound to application life cycle. All the widgets are bound together. If all what your widget got is a button than there is no reason for it to stop working. You problem is some place else.
For some reason your button intent is fail to start what you set it to start.
If you show me your code for setting the button, I be able to help you more, but it is another question, and you better Google for answer before posting.
EDIT: It looks like you didn't understood the idea of widgets. Right now what your button is doing is starting the widget. It looks weird to me, I am not sure what exactly is happening there... I suggest that your button will start a completely new service. That service will show your toast. You defiantly do not need to listen for restart package broadcast.
Related
I have an app where users can call each other through an SDK. Everything is working fine. I just need to be able to make calls like fabebook and whatsapp even when the app is closed. It should be able to start a particular activity even when the app is completely closed. I've followed some stackoverflow questions and I tried using the notification receiver but Its not working.
NotificationReceiver:
public class NotificationReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
Intent intentNotification = new Intent();
intentNotification.setAction("com.start.app");
context.sendBroadcast(intentNotification);
}
}
Manifest:
<receiver
android:name=".Notifications.NotificationReceiver"
android:enabled="true"
android:exported="false"></receiver>
What exactly you looking for ..
This can be done by creating a broadcast receiver class and send a broadcast when message received and on your broadcast receivers onReceive method call the specific activity you wish to open.
Dont forget to add the reciever in your manifest
Not tested but i think it will work..
I have been trying to develop this features for days and just keep getting errors and bugs. I am making an app that will notify users when it's time to pray. I have all the prayer times inside a db downloaded from a server in json format. The data is all correct as I have checked multiple times.
I have created a Service that will set Alarm using AlarmManager.
Then I bind my MainActivity to the Service. From the main activity I set Alarm using a method from the service called setAlarmAccordingToDB().
The problem is when I bind my service. The service gets destroyed when app is closed. Upcoming notifications are not notified.
Then I tried to start the service and bind it to my activity.Called setAlarmAccordingToDB(). What happened was setAlarmAccordingToDB was called repeatedly. It kept setting up new alarms non-stop.
Any advice on how upcoming notifications should be set?
You probably need to use a Wakeful service, so the device/process wakes up when the alarm is called.
I have used this code for a while in my app (not the project, just modified my code from Mark's examples) with great results.
https://github.com/commonsguy/cwac-wakeful
I tried to use a separate class for broadcastReceiver and it seems to work. I just used Alarm Manager and BroadcastReceiver. After the revised code, my app could fire the notifications even when the phone screen is turned off and app closed.
Before this i used:-
broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
displayNotification();
}
};
Now, I created a class:-
public class Receiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
NotificationManager notificationManager;
notificationManager = (NotificationManager)context.getSystemService(context.NOTIFICATION_SERVICE);
displayNotification(context);
}
}
In the AndroidManifest.xml I added
<receiver android:name=".Receiver" android:process=":remote"></receiver>
I'm trying just some very simple code to get an Android widget going but with no luck. I've looked around everywhere and haven't found a good answer.
All I want (for now) is to increment a counter when the widget is touched and display the current value.
This is my AppWidgetProvider:
public class WordWidget extends AppWidgetProvider
{
Integer touchCounter = 0;
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
{
//This is run when a new widget is added or when the update period expires.
Log.v("wotd", "Updating " + appWidgetIds.length + " widgets");
for(int x = 0; x < appWidgetIds.length; x++)
{
Integer thisWidgetId = appWidgetIds[x];
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widgetlayout);
remoteViews.setTextViewText(R.id.mainText, touchCounter.toString());
Intent widgetIntent = new Intent(context, WordWidget.class);
widgetIntent.setAction("UPDATE_NUMBER");
PendingIntent widgetPendingIntent = PendingIntent.getBroadcast(context, 0, widgetIntent, 0);
remoteViews.setOnClickPendingIntent(R.id.widgetLinearLayout, widgetPendingIntent);
appWidgetManager.updateAppWidget(thisWidgetId, remoteViews);
}
}
#Override
public void onReceive(Context context, Intent intent)
{
Log.v("wotd", "In onReceive with intent=" + intent.toString());
if (intent.getAction().equals("UPDATE_NUMBER"))
{
Log.v("wotd", "In UPDATE_NUMBER");
touchCounter++;
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widgetlayout);
remoteViews.setTextViewText(R.id.mainText, touchCounter.toString());
} else
{
Log.v("wotd", "In ELSE... going on to super.onReceive()");
super.onReceive(context, intent);
}
}
}
This is part of my manifest:
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name" >
<receiver
android:icon="#drawable/ic_launcher"
android:name="com.example.mywidget.WordWidget"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
<action android:name="UPDATE_NUMBER" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="#xml/widgetinfo" />
</receiver>
</application>
The log shows the onReceive() is called immediately after being placed on the home screen, and after being touched, however the number never increases. I don't totally understand how widgets work, but are they killed after onUpdate()? So to do this I would have to use some kind of persistant storage?
Also, if I currently add another widget both would show the same values and increment even if I just touch one. Is there a way for each and any widget to have it's own counter?
Thanks!
Actually you have answered your question. But let's clarify some things:
A. AppWidgets are NOT killed as long as they are on a home screen. But they don't belong to you. They are running in the process of the home application. To be more specific their views are running in the process of the home application, this is why you are see your widget but it doesn't do what you are expected and this is why we are using RemoteViews instead of Views in order to update them.
B. AppWidgetProviders (in your case the WordWidget class), on the other hand, are destroyed as soon as the onReceive method finishes. All the variables in them are re-initialized every time the onReceive method gets called. This is why your number never increases. The purpose of an AppWidgetProvider is to update the widget's RemoteViews and to inform your application that a registered broadcast has arrived.
C. AppWidgetProvider's onUpdate method provides you an Array with the widgets Ids that must be updated. This is the only code point you can use to get the number of your widget instances and their Ids. Because of the RemoteViews there is NO way to get some useful value from the Views of your widget (for example you can NOT read the counter value from the TextView) so you must use the provided information and DO persist your counter values per widget id. When the next onUpdate gets called you read the value from the storage, increase it, update the widget with the new value and then store the new value back.
D. If your widget has to do many things or slow things (like networking) when its time to update itself, you should consider using a service for this. But in your case (to increase a number) your approach is just fine as long as you persist the counters in the persistent storage or somewhere else.
Finally I 've noticed that in your onReceive override you are calling the "super.onReceive" only if you don't receive the "UPDATE_NUMBER" action. This is NOT a good practice, unless there is a GOOD reason (that's another story) always call super.onReceive as the first or the last command in your override.
Hope this helps...
I have a simple appwidget and I want to update it when an action occurs in an activity (in the same app). in onUpdate(), I immediately update the widget, which works fine. In my activity, I call the same static update method in my appwidget that is called in onUpdate() to update the views. the widget is not updated.
I can trace the code right into the AppWidgetManager.updateAppWidget() method, and all this good, but the widget does not update.
The only possible difference I can see is that the context object passed into my static update method is different, when it's called from the context of an activity vs. the context of a appwidget's onUpdate() method. however, there are lots of examples on the web of this so I expect it should work.
Without seeing your code I'm not 100% sure how you are trying to do it, however here is the method I use. Within my Activity I have the following method:
private void updateAllWidgets(){
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(getApplicationContext());
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(this, MyWidget.class));
if (appWidgetIds.length > 0) {
new MyWidget().onUpdate(this, appWidgetManager, appWidgetIds);
}
}
Where MyWidget is the class of the appwidget. I can call this method from anywhere within my Activity to update all my appwidgets.
Rather than use a static method take advantage of the fact that the widget is already a broadcast receiver and register an update intent for it in your manifest. Then whenever you need to update it from the activity just call
//in your activity
sendBroadcast(new Intent(MyWidget.ACTION_UPDATE).putExtra(whatever));
//In widget class
public static final String ACTION_UPDATE = "com.example.UPDATE_MY_WIDGET";
and inside the receiver tags of your manifest file
<intent-filter>
<action android:name="com.example.UPDATE_MY_WIDGET"/>
</intent-filter>
What I am trying to do is once the AppWidget is removed from the homescreen of the user's Android phone, I want to stop the background service that Updates the AppWidget.
Here is the code that I am using...don't understand whats wrong?
#Override
public void onDeleted(Context context, int[] appWidgetIds){
Intent serviceIntent = new Intent(context, UpdateService.class);
context.stopService(serviceIntent);
super.onDeleted(context, appWidgetIds);
}
Any ideas? Thanks for the help.
After a lot of Research I finally fixed it. My goal here was to stop the background service if all AppWidget instances are removed from the screen.
This is what did it...
Used shared preferences to toggle 1 and 0. SharePref toggled to 1 when the very first instance of the widget is put on the screen by the user. It is toggled back to 0 when the last instance of the App widget is removed from the screen.
#Override OnReceive method in the Service. Listen for these broadcasts - AppWidget Enabled (broadcast when the very first instance of the widget is put on the screen) , AppWidget Disabled (broadcast by the OS when the very last instance of the widget is removed from the screen)
When AppWidget Disabled is broadcast call the overridden method OnDisabled method.
3.In #Override OnDisabled method call stopService. Works perfect.
Remember the difference between OnDeleted and OnDisabled. OnDeleted is called when an instance of the widget is removed, it doesn't mean that the widget being deleted is the last one. I wanted my service to still run even if there was a single widget instance on the screen.
*Also if you do not want to do all of the above and let Android take care of the Service etc...use IntentService. **
I think the stopservice is calling onDestroy in the Service itselfs.
It works for me with the following code in the Service
#Override
public void onDestroy() {
super.onDestroy();
timer.cancel();
//Toast.makeText(this, "Service Destroyed", Toast.LENGTH_LONG).show();
}
timer ist the timer which i am starting in the _startService void