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.
Related
I tried lots of solutions but after weeks i have not been able to solve this issue: why "notifyappwidgetviewdatachanged" doesn't work? how can i update a listview placed on my widget? Where am i wrong?
Here are my classes.
Widget Provider:
public class Widget_Provider extends AppWidgetProvider
{
public static final String ACTION_MOSTRAORARI = "fACTION_TOAST";
public static final String EXTRA_STRING = "EXTRA_STRING";
#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)
{
RemoteViews views = updateWidgetListView(context, appWidgetId);
final Intent onItemClick = new Intent(context, Widget_Provider.class);
onItemClick.setAction(ACTION_MOSTRAORARI);
onItemClick.setData(Uri.parse(onItemClick.toUri(Intent.URI_INTENT_SCHEME)));
final PendingIntent onClickPendingIntent = PendingIntent.getBroadcast(context, 0, onItemClick, PendingIntent.FLAG_UPDATE_CURRENT);
views.setPendingIntentTemplate(R.id.myStopList, onClickPendingIntent);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
super.onUpdate(context, appWidgetManager, appWidgetIds);
}
public RemoteViews updateWidgetListView(Context context, int appWidgetId)
{
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.widget);
Intent svcIntent = new Intent(context, Widget_Service.class);
svcIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
svcIntent.setData(Uri.parse(svcIntent.toUri(Intent.URI_INTENT_SCHEME)));
remoteViews.setRemoteAdapter(R.id.myStopList, svcIntent);
return remoteViews;
}
#Override
public void onReceive(Context context, Intent intent)
{
if (intent.getAction().equals(ACTION_MOSTRAORARI)) {
if (MainUtils.isNewtworkAvailable(context))
{
String item = intent.getExtras().getString(EXTRA_STRING);
Intent intentOrari = new Intent(context, Diag_MostraOrari.class);
intentOrari.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
context.startActivity(intentOrari);
}
}
super.onReceive(context, intent);
}
#Override
public void onDeleted(Context context, int[] appWidgetIds) {}
#Override
public void onEnabled(Context context) {}
#Override
public void onDisabled(Context context) {}
}
Widget Service:
public class Widget_Service extends RemoteViewsService
{
#Override
public RemoteViewsFactory onGetViewFactory(Intent intent)
{
Map<String, ArrayList<String>> map = new TreeMap<>(String.CASE_INSENSITIVE_ORDER);
/* ---
* Here i fetch data from a local db and store it on "map"
*/ ---
return (new Widget_ListProvider(this.getApplicationContext(), intent, map));
}
}
ListProvider:
public class Widget_ListProvider implements RemoteViewsFactory
{
private Map<String, ArrayList<String>> map = new HashMap<>();
private ArrayList<ListItem_Widget> listItemList = new ArrayList<>();
private Context context = null;
private int appWidgetId;
public Widget_ListProvider(Context context, Intent intent, Map<String, ArrayList<String>> map)
{
this.map = map;
this.context = context;
appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
populateListItem();
}
//This function populate the arraylist "listItemList" by the data stored on "map"
private void populateListItem() { [...] }
#Override
public int getCount() {
return listItemList.size();
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public RemoteViews getViewAt(int position)
{
final RemoteViews remoteView = new RemoteViews(context.getPackageName(), R.layout.listitem_widget);
ListItem_Widget listItem = listItemList.get(position);
remoteView.setTextViewText(R.id.heading, listItem.heading);
remoteView.setTextViewText(R.id.content, listItem.content);
final Intent fillInIntent = new Intent();
fillInIntent.setAction(Widget.ACTION_MOSTRAORARI);
final Bundle bundle = new Bundle();
bundle.putString(Widget.EXTRA_STRING, listItem.heading);
fillInIntent.putExtras(bundle);
remoteView.setOnClickFillInIntent(R.id.listrow, fillInIntent);
return remoteView;
}
#Override
public RemoteViews getLoadingView() {
return null;
}
#Override
public int getViewTypeCount() {
return 1;
}
#Override
public boolean hasStableIds() {
return true;
}
#Override
public void onCreate() {}
#Override
public void onDataSetChanged() {}
#Override
public void onDestroy() {}
}
The xml of my listview custom item contains just two textviews: "heading" and "content".
Where am i wrong? why when i call "notifyappwidgetviewdatachanged" from another activity nothing happens?
[EDIT]
That's the activity where i need to update my widget.
public class Diag_Line extends AppCompatActivity
{
//[...]
#Override
protected void onCreate(Bundle savedInstanceState)
{
//[...]
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(getApplicationContext());
ComponentName thisAppWidget = new ComponentName(getApplicationContext().getPackageName(), Widget.class.getName());
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(thisAppWidget);
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIds, R.id.myStopList);
//"myStopList" is the id of my listview inside the widget xml.
//[...]
}
}
Well, the problem is a quite obvious: In your RemoteViewsFactory you have an empty method onDataSetChanged(). But when you're triggering notifyAppWidgetViewDataChanged(), you're getting callback in onDataSetChanged(). For better understanding check this pic.
If Diag_Line is a Configuration Activity just make something like this:
appWidgetManager.updateAppWidget(appWidgetIds, views); // views is a RemoteViews that you need to build
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIds, R.id.myStopList);
Also check official documentation here
UPDATE
Some hints for you. If you're working with widget, make all fetching data and fillings RemoteViews on background (IntentService is a nice approach). So just make IntentService and make logic for widget here. Don't forget to make him foreground (only for Android O), if you're triggering your updates by broadcasts. Also you can check library that makes all for you.
In order for notifyAppWidgetViewDataChanged() to work properly
we need to retreive the data in onDataSetChanged() method of RemoteViewSourceFactory
like this:
override fun onDataSetChanged() {
listOfArticles = newsDatabaseRepo.getSynchronouslySavedNews() as ArrayList<Articles>
}
as suggested in here
And have a method to refresh the widget if a change occured:
private fun refreshWidget() {
val appWidgetManager =
AppWidgetManager.getInstance(applicationContext)
val thisAppWidget = ComponentName(
applicationContext.packageName,
MyAppWidgetProvider::class.java.name
)
val appWidgetIds = appWidgetManager.getAppWidgetIds(thisAppWidget)
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIds, R.id.stack_view)
}
After calling the above method and once I come out of my App I am able to notice the changes in My Widget
So in order to check if onDataSetChanged is called after notifyAppWidgetViewDataChanged()
I kept a debug point and onDataSetChanged() was called and the list was updated as suggested in here here
Had a similar problem updating my widget, it was calling onDataSetChanged but not refreshing the layout. So in my case I had to set updateAppWidget to null before updating with remoteviews like this:
appWidgetManager.updateAppWidget(appWidgetId, null);
appWidgetManager.updateAppWidget(appWidgetId, remoteViews);
Looks like there is some sort of caching happening here.
I'm a newbie and i'm finding difficulty in getting texts from a string array. I tried creating a widget in my app and i wanted the widget to update it's text view from the string array i declared in the resources folder, but this does not seams to work out. Here is my code.
MainActivity.Java
public class MainActivity extends AppCompatActivity {
public static TextView Quote;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Quote = (TextView) findViewById(R.id.appwidget_text);
final String[] Quotes = getResources().getStringArray(R.array.Qoutes);
Random rand = new Random();
int randNum = rand.nextInt(Quotes.length);
Quote.setText(Quotes[randNum]);
}}
NewAppWidget.java
public class NewAppWidget extends AppWidgetProvider {
static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
int appWidgetId) {
CharSequence widgetText = MainActivity.Quote.getText().toString();
// Construct the RemoteViews object
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.new_app_widget);
views.setTextViewText(R.id.appwidget_text, widgetText);
// Instruct the widget manager to update the widget
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);
}
Intent intent = new Intent(context, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(context,0 , intent, 0);
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.new_app_widget);
remoteViews.setOnClickPendingIntent(R.id.interfaceID,pendingIntent);
appWidgetManager.updateAppWidget(appWidgetIds, remoteViews);
}
#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
}}
Thank You
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."
I initialize one variable in an onUpdate() method and after that I call onReceive() function which runs fine but cannot access varible set in onUpdate() method. Why is that? Those varible is string variableand are declared public. Am I missing something?
public class WidgetTest extends AppWidgetProvider {
public static String ACTION_WIDGET_RECEIVER = "ActionReceiverWidget";
public String state;
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
{
Log.e("UPDATE", "Start");
RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.main);
state="State_update"
System.out.println(state);// My variable is initilised
Intent active = new Intent(context, WidgetTest.class);
active.setAction(ACTION_WIDGET_RECEIVER);
PendingIntent actionPendingIntent = PendingIntent.getBroadcast(context, 0, active, 0);
remoteViews.setOnClickPendingIntent(R.id.buttonclick, actionPendingIntent);
super.onUpdate(context, appWidgetManager, appWidgetIds);
appWidgetManager.updateAppWidget(appWidgetIds, remoteViews);
Log.e("UPDATE", "End");
}
#Override
public void onReceive(Context context, Intent intent)
{
super.onReceive(context, intent);
Log.e("RECEIVE", "Start 2");
if (intent.getAction().equals(ACTION_WIDGET_RECEIVER))
{
Log.e("Test", "My State is "state);//it gives me null point exception;
}
Log.e("RECEIVE", "End");
}
state varible in onReceive gives null point exception
for a AppWidgetReceiver , first onReceive() will be called and then based on the Action received, it will call onUpdate(...) method. so here you are initializing state in onUpdate() which will be called after onReceive(), thus state is null in onReceive().
I want to make a widget app that is able to dial a number and user can set the number when he first drag and drop widget to home screen using widget configuration.But when the phone restarts widget uses default number again. I decide to save the entered phonenumber to Shared Preferences to save and load user's phone number but eclipse says that using getSharedPreferences is not allowed in onUpdate.Is there another way to perform it?
What should I do?
my code:
public class Main extends AppWidgetProvider {
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
// TODO Auto-generated method stub
super.onUpdate(context, appWidgetManager, appWidgetIds);
for(int i=0 ; i<appWidgetIds.length ; i++)
{
SharedPreferences details = getSharedPreferences("OPERATOR", 0);
int appWidgetId = appWidgetIds[i];
String phNumber = "5554574";
Intent intent = new Intent(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:"+(phNumber)));
PendingIntent pending = PendingIntent.getActivity(context, 0, intent, 0);
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.main);
views.setOnClickPendingIntent(R.id.button1, pending);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}
}
Use:
SharedPreferences details = context.getSharedPreferences("OPERATOR", 0);
SharedPreferences has to be acquired from the context. onUpdate(...) provides you the context.
Your changed code should look like this:
public class Main extends AppWidgetProvider {
#Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
int[] appWidgetIds) {
// TODO Auto-generated method stub
super.onUpdate(context, appWidgetManager, appWidgetIds);
for(int i=0 ; i<appWidgetIds.length ; i++)
{
SharedPreferences details = context.getSharedPreferences("OPERATOR", 0);
int appWidgetId = appWidgetIds[i];
String phNumber = "5554574";
Intent intent = new Intent(Intent.ACTION_CALL);
intent.setData(Uri.parse("tel:"+(phNumber)));
PendingIntent pending = PendingIntent.getActivity(context, 0, intent, 0);
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.main);
views.setOnClickPendingIntent(R.id.button1, pending);
appWidgetManager.updateAppWidget(appWidgetId, views);
}
}
}
Please try it.
AppWidgetProvider is not a Context. But you can often create a static method to reach the context of an application, then do this
In Android Manifest file declare following
<application android:name="com.example.MyApplication">
</application>
then write the class
public class MyApplication extends Application{
private static Context context;
public void onCreate(){
super.onCreate();
MyApplication.context = getApplicationContext();
}
public static Context getAppContext() {
return MyApplication.context;
}
}
Then you can use
SharedPreferences details = MyApplication.getAppContext().getSharedPreferences("OPERATOR", 0);
I haven't worked with widgets yet so can't guarantee this solution but hope it work!