I need to call AsyncTask function since the onReceive(). The problem is when I call the function, the different TextViews it must change in the onPostExecute(), don't change it!
This is the code:
#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);
int appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
RemoteViews remoteViews;
ComponentName watchWidget;
remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget);
watchWidget = new ComponentName(context, widget.class);
remoteViews.setTextViewText(R.id.textView56, "ACTUALIZANDO");
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.widget);
new LongOperation(views, appWidgetId, appWidgetManager).execute("MyTestString"); //Calling the asyncTask
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);
}
And the AsyncTask. This part of the code we use and also works when I call sice the onUpdate:
public class LongOperation extends AsyncTask<String, Void, String> {
private RemoteViews views;
private int WidgetID;
private AppWidgetManager WidgetManager;
public LongOperation(RemoteViews views, int appWidgetID, AppWidgetManager appWidgetManager){
this.views = views;
this.WidgetID = appWidgetID;
this.WidgetManager = appWidgetManager;
}
#Override
public void onPreExecute() {
super.onPreExecute();
}
#Override
public String doInBackground(String... params) {
try {
....
} catch (Exception e) {
....
}
return temperatura;
}
#Override
public void onPostExecute(String result) {
views.setTextViewText(R.id.textView66, result+ "ÂșC ");
WidgetManager.updateAppWidget(WidgetID, views);
}
}
I think that the problem is in the appWidgetId but I can't solve...
Thanks,
MArc
The use of AsyncTask in BroadCast is bad practice, because Android may kill your process in onReceive() if there is no any active Service or Activity, and no gurantee its return.
In this case, official documentation recommends IntentService:
"The specific constraint on BroadcastReceiver execution time
emphasizes what broadcast receivers are meant to do: small, discrete
amounts of work in the background such as saving a setting or
registering a Notification. So as with other methods called in the UI
thread, applications should avoid potentially long-running operations
or calculations in a broadcast receiver. But instead of doing
intensive tasks via worker threads, your application should start an
IntentService if a potentially long running action needs to be taken
in response to an intent broadcast."
Related
sorry for question which was many time answered but for me is still now working :-(
I have following activiy code:
public class WidgetProvider extends AppWidgetProvider {
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
final int count = appWidgetIds.length;
for (int i = 0; i < count; i++) {
int widgetId = appWidgetIds[i];
RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
R.layout.simple_widget);
Intent intent = new Intent(context, SimpleWidgetProvider.class);
intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context,
0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
new Weather(remoteViews).execute();
remoteViews.setOnClickPendingIntent(R.id.actionButton, pendingIntent);
appWidgetManager.updateAppWidget(widgetId, remoteViews);
}
}
}
with Async Weather class but this doesn't work. Value is missing in remoteViews.
class Weather extends AsyncTask<Void, String, String> {
private RemoteViews remoteViews ;
public Weather(RemoteViews remoteViews) {
this.remoteViews = remoteViews;
}
#Override
protected String doInBackground(Void... arg0) {
return "COLD";
}
#Override
protected void onPostExecute(String temp) {
remoteViews.setTextViewText(R.id.textView, temp);
}
Whatever RemoteViews that you pass to updateAppWidget() will be used at that time. In your case, your Weather task will not even begin to be executed by the time that the RemoteViews has been used, and so your change to that RemoteViews will be pointless.
Instead:
Switch to Thread, as there is no value in using AsyncTask here, and
Do all the work for a given widget ID, including calling updateAppWidget(), in the Thread
I'm trying to figure out how I can use the Greenbot Eventbus library in my AppWidgetProvider. I've tried the following, which doesn't work:
public class SimpleWidgetProvider extends AppWidgetProvider {
RemoteViews remoteViews;
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
final int count = appWidgetIds.length;
for (int i = 0; i < count; i++) {
int widgetId = appWidgetIds[i];
remoteViews = new RemoteViews(context.getPackageName(), R.layout.simple_widget);
//set image
remoteViews.setImageViewResource(R.id.piggy_bank, R.drawable.piggy_bank);
Intent intent = new Intent(context, SimpleWidgetProvider.class);
intent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context,
0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
//set refresh button
remoteViews.setOnClickPendingIntent(R.id.refresh_btn, pendingIntent);
appWidgetManager.updateAppWidget(widgetId, remoteViews);
}
}
#Override
public void onEnabled(Context context) {
super.onEnabled(context);
EventBus.getDefault().register(this);
}
//set total price
#Subscribe
public void onPriceEvent(TotalPriceEvent event) {
double price = event.totalPrice;
remoteViews.setTextViewText(R.id.total_amount, String.valueOf(price));
}
#Override
public void onDisabled(Context context) {
EventBus.getDefault().unregister(this);
super.onDisabled(context);
}
}
Please, let me know if I need to attach more code.
An AppWidgetProvider is just a BroadcastReceiver with a specialized onReceive() method that delegates broadcasts to other methods based on the action. Instances of a manifest-registered BroadcastReceiver aren't meant to live very long. They run just long enough to handle a broadcast and then die, so subscribing one to an event bus isn't going to work as expected, and is kinda pointless, given the overlapping patterns. If you want to notify your SimpleWidgetProvider of something, just send a broadcast to it.
For an example, we define our own action for the SimpleWidgetProvider class, and check for it in the onReceive() method. If it's ours, we'll handle it as needed, and otherwise call the super method to allow AppWidgetProvider to properly delegate it.
public class SimpleWidgetProvider extends AppWidgetProvider {
public static final String MY_SPECIAL_ACTION = "com.mycompany.myapp.SPECIAL_ACTION";
#Override
public void onReceive(Context context, Intent intent) {
if(MY_SPECIAL_ACTION.equals(intent.getAction())) {
// Do your thing
}
else {
// Not our action, so let AppWidgetProvider handle it
super.onReceive(context, intent);
}
}
...
}
We can send a broadcast to it with the usual mechanism.
Intent widgetNotify = new Intent(context, SimpleWidgetProvider.class);
widgetNotify.setAction(SimpleWidgetProvider.MY_SPECIAL_ACTION);
widgetNotify.putExtra(...);
...
context.sendBroadcast(widgetNotify);
I would also mention that the super calls in onEnabled() and onDisabled() are unnecessary, as those methods are empty in AppWidgetProvider.
I am trying to understand an app that communicates with a widget on the home screen. But i do not understand what the following code does within the application:
Intent i = new Intent(this, AppWidget.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
updateViews.setOnClickPendingIntent(R.id.phoneState, pi);
return updateViews;
Full Class:
public class AppWidget extends AppWidgetProvider {
// This is called for every broadcast. We normally don't need to implement this
// method because the default AppWidgetProvider implementation filters all App Widget
// broadcasts and calls the above methods as appropriate
#Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction() == null) {
context.startService(new Intent(context, ToggleService.class));
} else {
super.onReceive(context, intent);
}
}
#Override
// This is called to update the App Widget at intervals defined by
// the updatePeriodMillis attribute in the AppWidgetProviderInfo. This method is also called when
// the user adds the App Widget, so it should perform the essential setup, such as define event
// handlers for Views and start a temporary Service, if necessary.
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
context.startService(new Intent(context, ToggleService.class));
}
// This class is used to set up the intent service in order to provide views for
// the widget. It also supports to set up a pending intent. Furthermore, the app widget can be
// updated with a remote adapter.
public static class ToggleService extends IntentService {
public ToggleService() {
super("AppWidget$ToggleService");
}
#Override
protected void onHandleIntent(Intent intent) {
ComponentName me = new ComponentName(this, AppWidget.class);
AppWidgetManager mgr = AppWidgetManager.getInstance(this);
mgr.updateAppWidget(me, buildUpdate(this));
}
private RemoteViews buildUpdate(Context context) {
RemoteViews updateViews = new RemoteViews(context.getPackageName(),
R.layout.widget);
AudioManager audioManager = (AudioManager) context
.getSystemService(Activity.AUDIO_SERVICE);
if (audioManager.getRingerMode() == AudioManager.RINGER_MODE_SILENT) {
updateViews.setImageViewResource(R.id.phoneState,
R.drawable.phone_state_normal);
audioManager.setRingerMode(AudioManager.RINGER_MODE_NORMAL);
} else {
updateViews.setImageViewResource(R.id.phoneState,
R.drawable.phone_state_silent);
audioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
}
//KNOW THIS CODE
Intent i = new Intent(this, AppWidget.class);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, i, 0);
updateViews.setOnClickPendingIntent(R.id.phoneState, pi);
return updateViews;
}
}
}
All it does is open the ToggleService when the user taps on the viewId R.id.phoneState.
It's kinda of a silly way of doing it, the more straight forward would be:
Intent i = new Intent(this, ToggleService.class);
PendingIntent pi = PendingIntent.getService(context, 0, i, 0);
updateViews.setOnClickPendingIntent(R.id.phoneState, pi);
you see, this code you posted calls the BroadcastReceiver that then calls the service. Makes no sense.
I am using asynctask to do my feature function and getting the values there. But my text view is not getting updated, though my log statements giving me the result.
I am not using custom intent here, just the basic one.
Here are my code snippets:
public class ListViewWidget extends AppWidgetProvider{
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
updateViews = new RemoteViews(context.getPackageName(), R.layout.list_layout);
thisWidget = new ComponentName(context, ListViewWidget.class);
FetchTask fetchTask=new FetchTask();
AppWidgetManager.getInstance(context.getApplicationContext());
fetchTask.execute();
}
//FetchTask
public static class FetchTask extends AsyncTask<URL,Integer,String> implements ServerRequestEnvironment{
protected String doInBackground(URL... arg0) {
//logic part and stuff not entered
//This is the end part that returns me the result, which is not getting printed to text view.
String name="";
int i = new Random().nextInt(27);
storeObject=store.getStores().getItems().get(i).getStore();
name= storeObject.getName();
resultStuff(name);
Log.i("StoreTag","storeval:"+name); //returns name of the 0th item
return name;
}//end of doInBackground() method
protected void onPostExecute(String name) {
// TODO Auto-generated method stub
Intent intent=new Intent("android.appwidget.action.APPWIDGET_UPDATE");
PendingIntent pendingIntent=PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
updateViews.setTextViewText(R.id.text_view,resultStuff(name));
updateViews.setOnClickPendingIntent(R.id.next, pendingIntent);
AppWidgetManager manager = AppWidgetManager.getInstance(context.getApplicationContext());
manager.updateAppWidget(thisWidget, updateViews);
}//end of PostExecute
}//End of async task class
}//end of ListViewWidget class
What I am missing here? Please please guide..
UPDATE: Is this fine? Async task to be called both in onReceive and onUpdate??
#Override
public void onReceive(Context context,Intent intent){
if(intent.getAction().equals("android.appwidget.action.APPWIDGET_UPDATE")){
fetchTask.execute();
}
}
Update 2:
public static String name="New text"
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
super.onUpdate(context, appWidgetManager, appWidgetIds);
updateViews = new RemoteViews(context.getPackageName(), R.layout.list_layout);
//-----------NEW LINE ADDED-------------
updateViews.setTextViewText(R.id.text_view,name);
thisWidget = new ComponentName(context, ListViewWidget.class);
//Now in onPostExecute()
//AppWidgetManager manager = AppWidgetManager.getInstance(context.getApplicationContext());
//manager.updateAppWidget(thisWidget, updateViews);
fetchTask.execute();
}
protected void onPostExecute(String name) {
// TODO Auto-generated method stub
Intent intent=new Intent("android.appwidget.action.APPWIDGET_UPDATE");
PendingIntent pendingIntent=PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
updateViews.setTextViewText(R.id.text_view,name);
updateViews.setOnClickPendingIntent(R.id.next, pendingIntent);
AppWidgetManager manager = AppWidgetManager.getInstance(context.getApplicationContext());
manager.updateAppWidget(thisWidget, updateViews);
}
#Dororo Didn't get you. Please explain. I have created public var in my class:
public static Context context;
public static RemoteViews updateViews;
public static ComponentName thisWidget;
FetchTask fetchTask=new FetchTask();
Have you tried using this:
TextView textView = (TextView) findViewById(R.id.textView);
textView.setText(toThis);
Are you sure you're not overwriting the updated value when you create new ComponentName(context, ListViewWidget.class);? onUpdate will be called when you call manager.updateAppWidget(thisWidget, updateViews); You shouldn't need to use static, you just need an initialisation boolean which is set to true after you've created the objects for the first time.
Solved my exception and error. Was setting context to be null. I assigned context with the application context.
I have a problem with service. I'm trying to do a simple battery level widget but the problem is that I don't know how to stop service when the widget is removed from homescreen.
Here is my service class
public class batteryService extends Service{
AppWidgetManager widgetManager;
private RemoteViews remoteViews;
private ComponentName thisWidget;
private BroadcastReceiver mBatInfoReceiver = new BroadcastReceiver()
{
#Override
public void onReceive(Context context, Intent intent)
{
widgetManager = AppWidgetManager.getInstance(context);
remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget);
thisWidget = new ComponentName(context, Widget.class);
int level = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1)*100;
int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1);
float value = (float)level/scale;
remoteViews.setTextViewText(R.id.widget_textview, String.valueOf(value));
widgetManager.updateAppWidget(thisWidget, remoteViews);
}
};
#Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}
#Override
public void onCreate() {
this.registerReceiver(mBatInfoReceiver, new IntentFilter(Intent.ACTION_BATTERY_CHANGED));
super.onCreate();
}
#Override
public void onDestroy() {
this.unregisterReceiver(mBatInfoReceiver);
super.onDestroy();
}
}
and here widget class
public class Widget extends AppWidgetProvider{
private AppWidgetManager widget_manager;
private RemoteViews remoteViews;
private ComponentName thisWidget;
private Intent intent;
#Override
public void onEnabled(Context context) {
if(intent == null)
{
intent = new Intent(context, batteryService.class);
context.startService(intent);
}
super.onEnabled(context);
}
#Override
public void onDisabled(Context context) {
if(intent != null)
{
context.stopService(intent);
intent = null;
}
super.onDisabled(context);
}
}
When I remove widget from screen the service is still a live. I was trying to change onDisable to onDeleted method but it didn't change anything.
Have you any tips for me ?
Make sure you have the appropriate action in your manifest for the disabled event:
<action android:name="android.appwidget.action.APPWIDGET_DISABLED" />
This would be alongside your existing APPWIDGET_ENABLED and perhaps the classic APPWIDGET_UPDATE actions, for the <receiver> element for your AppWidgetProvider.
Also, please consider not having your service run constantly, but rather updating the battery information once every few minutes using AlarmManager. The battery level simply does not change that often to make it necessary to attempt to keep a service in memory all of the time.
Try by using onDeleted(Context, int[])