I have created an app widget using collection for my app, The widget shows date and list of items on that particular date. Everything works fine and the widget is updating as required, but sometimes what happens while changing the date in the widget by clicking next and previous button, the list is not refreshed means the items are not updated on that particular date. This behavior is random and its occur sometimes only. So why this happen, anything wrong in my code.
Code that I have used:
WidgetProvider.class
public class WidgetProvider extends AppWidgetProvider
{
private ThemeManager m_ThemeManagerObject;
private static String WIDGET_NEXT_BUTTON = "in.test.widgetApp.WIDGET_NEXT_BUTTON";
private static String WIDGET_PREV_BUTTON = "in.test.widgetApp.WIDGET_PREV_BUTTON";
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
{
super.onUpdate(context, appWidgetManager, appWidgetIds);
// Set Date to current Date
NoteManager.getSingletonObject().setWidgetToCurrentDate();
// Code to update the widget by current date
updateAppWidget(context, AppWidgetManager.getInstance(context), appWidgetIds);
}
@Override
public void onReceive(Context context, Intent intent)
{
super.onReceive(context, intent);
int numOfDays = 1;
ComponentName thisWidget = new ComponentName(context, WidgetProvider.class);
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);
if (intent.getAction().equals(WIDGET_NEXT_BUTTON))
{
// Increase no of days by one
// Update the widget by new date
NoteManager.getSingletonObject().setWidgetDate(numOfDays);
updateAppWidget(context, AppWidgetManager.getInstance(context), appWidgetIds);
}
else if (intent.getAction().equals(WIDGET_PREV_BUTTON))
{
// Decrease no of days by one
// Update the widget by new date
NoteManager.getSingletonObject().setWidgetDate(-numOfDays);
updateAppWidget(context, AppWidgetManager.getInstance(context), appWidgetIds);
}
}
public void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
{
// Get the folder path of all-page-view
ContextWrapper cw = new ContextWrapper(context.getApplicationContext());
File customDirectoryPath = cw.getDir(Utilities.CUSTOM_DIRECTORY_NAME_PREFIX, Context.MODE_PRIVATE);
File allPageDirectoryPath = new File(customDirectoryPath.getPath() + "/" + Utilities.All_PAGE_DIRECTORY_NAME_PREFIX);
if (!(allPageDirectoryPath.exists()))
allPageDirectoryPath.mkdirs();
// Create an singleton object of ThemeManager class
m_ThemeManagerObject = ThemeManager.getSingletonObject();
m_ThemeManagerObject.readTheme(allPageDirectoryPath.getPath());
// Create an instance of SimpleDateFormat class
SimpleDateFormat dateFormater = new SimpleDateFormat("dd-MMM, EEE", Locale.US);
/* loop through all widget instances */
for (int widgetId : appWidgetIds)
{
// Create an instance of remote view class
RemoteViews remoteView = new RemoteViews(context.getPackageName(), R.layout.widget_list);
Intent svcIntent = new Intent(context, WidgetService.class);
svcIntent.setData(Uri.fromParts("content", String.valueOf(widgetId), null));
remoteView.setRemoteAdapter(R.id.widget_list, svcIntent);
// Show day, month and week day inside the widget
remoteView.setTextViewText(R.id.txt_date, dateFormater.format(NoteManager.getSingletonObject().getWidgetDate().getTime()));
// If the list is empty. Show empty widget with juswrite-icon & empty text to the user
remoteView.setEmptyView(R.id.widget_list, R.id.widget_empty_text);
// On click of next button
Intent nextButtonIntent = new Intent(WIDGET_NEXT_BUTTON);
/* use widgetId as second parameter - it helped me to better address particular widget instance */
PendingIntent nextButtonPendingIntent = PendingIntent.getBroadcast(context, widgetId, nextButtonIntent, PendingIntent.FLAG_UPDATE_CURRENT);
remoteView.setOnClickPendingIntent(R.id.btn_next_month, nextButtonPendingIntent);
remoteView.setInt(R.id.btn_next_month, "setBackgroundResource", m_ThemeManagerObject.getNextButtonBgImage());
// On click of previous button
Intent prevButtonIntent = new Intent(WIDGET_PREV_BUTTON);
/* use widgetId as second parameter - same as above */
PendingIntent prevButtonPendingIntent = PendingIntent.getBroadcast(context, widgetId, prevButtonIntent, PendingIntent.FLAG_UPDATE_CURRENT);
remoteView.setOnClickPendingIntent(R.id.btn_prev_month, prevButtonPendingIntent);
remoteView.setInt(R.id.btn_prev_month, "setBackgroundResource", m_ThemeManagerObject.getPrevButtonBgImage());
// Open application on click of app widget
Intent clickIntent = new Intent(context, AllPageViewActivity.class);
PendingIntent clickPI = PendingIntent.getActivity(context, 0,clickIntent,PendingIntent.FLAG_UPDATE_CURRENT);
remoteView.setOnClickPendingIntent(R.id.widget_empty_text, clickPI);
remoteView.setOnClickPendingIntent(R.id.txt_date, clickPI);
/* update one widget instance at a time*/
appWidgetManager.updateAppWidget(widgetId, remoteView);
}
}
}
WidgetService.class
public class WidgetService extends RemoteViewsService
{
@Override
public RemoteViewsFactory onGetViewFactory(Intent intent)
{
return(new WidgetDisplay(this.getApplicationContext(), intent));
}
}
WidgetDisplay.class
public class WidgetDisplay implements RemoteViewsService.RemoteViewsFactory
{
private File m_CustomDirectoryPath, m_AllPageDirectoryPath;
private NoteManager m_NoteManagerObject;
private ThemeManager m_ThemeManagerObject;
private ArrayList<String> m_AlarmItemNameArrayList;
private ArrayList<Integer> m_ItemIndexArray;
private Context ctxt=null;
int appWidgetId;
Bitmap canvasBackground;
public WidgetDisplay(Context ctxt, Intent intent)
{
this.ctxt=ctxt;
appWidgetId = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
AppWidgetManager.INVALID_APPWIDGET_ID);
setImageInView(this.ctxt);
}
private void setImageInView(Context context)
{
ContextWrapper cw = new ContextWrapper(ctxt.getApplicationContext());
m_CustomDirectoryPath = cw.getDir(Utilities.CUSTOM_DIRECTORY_NAME_PREFIX, Context.MODE_PRIVATE);
m_AllPageDirectoryPath = new File(m_CustomDirectoryPath.getPath() + "/" + Utilities.All_PAGE_DIRECTORY_NAME_PREFIX);
m_NoteManagerObject = NoteManager.getSingletonObject();
m_ThemeManagerObject = ThemeManager.getSingletonObject();
m_NoteManagerObject.readSettings(m_AllPageDirectoryPath.getPath());
m_NoteManagerObject.readAllPageChangesFromFile(m_AllPageDirectoryPath.getPath());
m_NoteManagerObject.readAlarmFromFile(m_AllPageDirectoryPath.getPath());
m_ThemeManagerObject.readTheme(m_AllPageDirectoryPath.getPath());
m_AlarmItemNameArrayList = new ArrayList<String>(m_NoteManagerObject.getAlarmCount());
m_ItemIndexArray = new ArrayList<Integer>(m_NoteManagerObject.getAlarmCount());
SimpleDateFormat sdFormatter = new SimpleDateFormat("dd-MMM-yyyy", Locale.US);
String selectedDate = sdFormatter.format(m_NoteManagerObject.getWidgetDate());
for(int i=0; i<m_NoteManagerObject.getAlarmCount(); i++)
{
String ArrayDate = sdFormatter.format(m_NoteManagerObject.getAlarmTime(i));
if(selectedDate.equals(ArrayDate))
{
File noteDirectoryPath = new File(m_CustomDirectoryPath.getPath() + "/" + m_NoteManagerObject.getAlarmFolder(i));
m_AlarmItemNameArrayList.add(noteDirectoryPath.getPath() + "/" + m_NoteManagerObject.getAlarmItem(i));
m_ItemIndexArray.add(i);
}
}
}
@Override
public int getCount()
{
return(m_AlarmItemNameArrayList.size());
}
@Override
public RemoteViews getViewAt(int position)
{
new ImageLoaderTask(position).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
// Set combine image to the image view using remote view instance
RemoteViews remoteView = new RemoteViews(ctxt.getPackageName(), R.layout.widget_list_item);
remoteView.setImageViewBitmap(R.id.image_view, canvasBackground);
// Set time text view using remote view instance
SimpleDateFormat timeFormater;
if(m_NoteManagerObject.get24HourFormat())
{
timeFormater = new SimpleDateFormat("HH:mm", Locale.US);
}
else
{
timeFormater = new SimpleDateFormat("hh:mm a", Locale.US );
}
// Show time on the top of each image view
String time = timeFormater.format(m_NoteManagerObject.getAlarmTime(m_ItemIndexArray.get(position)));
remoteView.setTextViewText(R.id.text_alarm_time, time);
Intent clickIntent = new Intent(ctxt, AllPageViewActivity.class);
PendingIntent clickPI=PendingIntent.getActivity(ctxt, 0,clickIntent,PendingIntent.FLAG_UPDATE_CURRENT);
remoteView.setOnClickPendingIntent(R.id.image_view, clickPI);
return(remoteView);
}
class ImageLoaderTask extends AsyncTask<URL, Integer, Long>
{
private int position;
ImageLoaderTask(int position)
{
this.position = position;
}
@Override
protected void onPreExecute()
{
// Get foreground and background image
Bitmap bitmapImage = BitmapFactory.decodeFile(m_AlarmItemNameArrayList.get(position)).copy(Bitmap.Config.ARGB_8888, true);
canvasBackground = BitmapFactory.decodeResource(ctxt.getResources(), m_ThemeManagerObject.getWidgetListItemBgImage(m_ItemIndexArray.get(position), bitmapImage)).copy(Bitmap.Config.ARGB_8888, true);
// Scaled foreground image and combine with the background image
bitmapImage = Bitmap.createScaledBitmap(bitmapImage, 380, bitmapImage.getHeight() / 2, true);
Canvas comboImage = new Canvas(canvasBackground);
comboImage.drawBitmap(bitmapImage, 0f, 0f, null);
}
@Override
protected Long doInBackground(URL... urls)
{
return null;
}
@Override
protected void onProgressUpdate(Integer... progress)
{
}
@Override
protected void onPostExecute(Long result)
{
}
}
@Override
public void onCreate(){
}
@Override
public void onDestroy(){
}
@Override
public RemoteViews getLoadingView()
{
return(null);
}
@Override
public int getViewTypeCount(){
return(1);
}
@Override
public long getItemId(int position){
return(position);
}
@Override
public boolean hasStableIds(){
return(true);
}
@Override
public void onDataSetChanged(){
}
}
Full update: Call AppWidgetManager. updateAppWidget(int, android. widget. RemoteViews) to fully update the widget.
Collection widgets specialize in displaying many elements of the same type, such as a collection of pictures from a gallery app, a collection of articles from a news app or a collection of messages from a communication app.
App widgets are miniature application views that can be embedded in other applications (such as the home screen) and receive periodic updates. These views are referred to as widgets in the user interface, and you can publish one with an app widget provider (or widget provider).
WidgetProvider.class
public class WidgetProvider extends AppWidgetProvider
{
private NoteManager m_NoteManagerObject;
private ThemeManager m_ThemeManagerObject;
private SimpleDateFormat m_DateFormater;
private static String WIDGET_NEXT_BUTTON = "in.test.widgetApp.WIDGET_NEXT_BUTTON";
private static String WIDGET_PREV_BUTTON = "in.test.widgetApp.WIDGET_PREV_BUTTON";
public WidgetProvider()
{
// Create an singleton object of NoteManager class
m_NoteManagerObject = NoteManager.getSingletonObject();
// Create an singleton object of ThemeManager class
m_ThemeManagerObject = ThemeManager.getSingletonObject();
// Create an instance of SimpleDateFormat class
m_DateFormater = new SimpleDateFormat("dd-MMM, EEE", Locale.US);
}
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds)
{
super.onUpdate(context, appWidgetManager, appWidgetIds);
// Set Date to current Date
m_NoteManagerObject.setWidgetToCurrentDate();
// Get the folder path of all-page-view
ContextWrapper cw = new ContextWrapper(context.getApplicationContext());
File customDirectoryPath = cw.getDir(Utilities.CUSTOM_DIRECTORY_NAME_PREFIX, Context.MODE_PRIVATE);
File allPageDirectoryPath = new File(customDirectoryPath.getPath() + "/" + Utilities.All_PAGE_DIRECTORY_NAME_PREFIX);
if (!(allPageDirectoryPath.exists()))
allPageDirectoryPath.mkdirs();
m_ThemeManagerObject.readTheme(allPageDirectoryPath.getPath());
// Set up the intent that starts the WidgetService, which will
// provide the views for this collection.
// When intents are compared, the extras are ignored, so we need to embed the extras
// into the data so that the extras will not be ignored.
Intent intent = new Intent(context, WidgetService.class);
intent.setData(Uri.fromParts("content", String.valueOf(appWidgetIds), null));
// Instantiate the RemoteViews object for the App Widget layout.
// Set up the RemoteViews object to use a RemoteViews adapter.
// This adapter connects to a RemoteViewsService through the specified intent.
// This is how you populate the data.
RemoteViews remoteView = new RemoteViews(context.getPackageName(), R.layout.widget_list);
remoteView.setRemoteAdapter(R.id.widget_list, intent);
// Show day, month and week day inside the widget
remoteView.setTextViewText(R.id.txt_date, m_DateFormater.format(m_NoteManagerObject.getWidgetDate().getTime()));
// The empty view is displayed when the collection has no items.
remoteView.setEmptyView(R.id.widget_list, R.id.widget_empty_text);
// On click of next button
// This section makes it possible for items to have individualized behavior.
// Set the action for the intent.
// When the user touches a particular view, it will have the effect of
// broadcasting ACTION.
Intent nextButtonIntent = new Intent(context, WidgetProvider.class);
nextButtonIntent.setAction(WIDGET_NEXT_BUTTON);
PendingIntent nextButtonPendingIntent = PendingIntent.getBroadcast(context, 0, nextButtonIntent, PendingIntent.FLAG_UPDATE_CURRENT);
remoteView.setOnClickPendingIntent(R.id.btn_next_month, nextButtonPendingIntent);
remoteView.setInt(R.id.btn_next_month, "setBackgroundResource", m_ThemeManagerObject.getNextButtonBgImage());
// On click of previous button
// This section makes it possible for items to have individualized behavior.
// Set the action for the intent.
// When the user touches a particular view, it will have the effect of
// broadcasting ACTION.
Intent prevButtonIntent = new Intent(context, WidgetProvider.class);
prevButtonIntent.setAction(WIDGET_PREV_BUTTON);
PendingIntent prevButtonPendingIntent = PendingIntent.getBroadcast(context, 0, prevButtonIntent, PendingIntent.FLAG_UPDATE_CURRENT);
remoteView.setOnClickPendingIntent(R.id.btn_prev_month, prevButtonPendingIntent);
remoteView.setInt(R.id.btn_prev_month, "setBackgroundResource", m_ThemeManagerObject.getPrevButtonBgImage());
// Open application on click of app widget
Intent clickIntent = new Intent(context, AllPageViewActivity.class);
PendingIntent clickPI = PendingIntent.getActivity(context, 0,clickIntent,PendingIntent.FLAG_UPDATE_CURRENT);
remoteView.setOnClickPendingIntent(R.id.widget_empty_text, clickPI);
remoteView.setOnClickPendingIntent(R.id.txt_date, clickPI);
appWidgetManager.updateAppWidget(appWidgetIds, remoteView);
}
@Override
public void onReceive(Context context, Intent intent)
{
super.onReceive(context, intent);
int numOfDays = 1;
ComponentName thisWidget = new ComponentName(context, WidgetProvider.class);
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);
if (intent.getAction().equals(WIDGET_NEXT_BUTTON))
{
// Increase no of days by one
m_NoteManagerObject.setWidgetDate(numOfDays);
// Update remote view
RemoteViews remoteView = new RemoteViews(context.getPackageName(), R.layout.widget_list);
remoteView.setTextViewText(R.id.txt_date, m_DateFormater.format(m_NoteManagerObject.getWidgetDate().getTime()));
appWidgetManager.updateAppWidget(appWidgetIds, remoteView);
// Update list content of the widget
// This will call onDataSetChanged() method of WidgetDisplay class
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIds, R.id.widget_list);
}
else if (intent.getAction().equals(WIDGET_PREV_BUTTON))
{
// Decrease no of days by one
m_NoteManagerObject.setWidgetDate(-numOfDays);
// Update remote view
RemoteViews remoteView = new RemoteViews(context.getPackageName(), R.layout.widget_list);
remoteView.setTextViewText(R.id.txt_date, m_DateFormater.format(m_NoteManagerObject.getWidgetDate().getTime()));
appWidgetManager.updateAppWidget(appWidgetIds, remoteView);
// Update list content of the widget
// This will call onDataSetChanged() method of WidgetDisplay class
appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIds, R.id.widget_list);
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With