Ошибка обновления виджета приложения с помощью коллекции

Я создал виджет приложения, используя коллекцию для своего приложения. Виджет показывает дату и список элементов в эту конкретную дату. Все работает нормально, и виджет обновляется по мере необходимости. Но иногда то, что происходит при изменении даты в виджетах, нажимая следующую и предыдущую кнопку, список не обновляется, значит, элементы не обновляются в эту конкретную дату. Такое поведение случайное, и иногда оно происходит. Так почему это происходит, что-то не так в моем коде.

Код, который я использую:

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(){ } } 

Solutions Collecting From Web of "Ошибка обновления виджета приложения с помощью коллекции"

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); } } } 

Вы можете попробовать, если вы PendingIntent.FLAG_UPDATE_CURRENT на PendingIntent.FLAG_CANCEL_CURRENT в ваших prevButtonPendingIntent и в prevButtonPendingIntent .

Когда вы создаете PendingIntents в updateAppWidget , для каждого виджета вы создаете эти два:

 PendingIntent nextButtonPendingIntent = PendingIntent.getBroadcast(context, widgetId, nextButtonIntent, PendingIntent.FLAG_UPDATE_CURRENT); PendingIntent prevButtonPendingIntent = PendingIntent.getBroadcast(context, widgetId, prevButtonIntent, PendingIntent.FLAG_UPDATE_CURRENT); 

Для обоих вы устанавливаете второй аргумент widgetId . Система PendingIntent не видит, отличается ли аргумент Intent . (Фактически, это определенно не должно делать этого – в противном случае вы не смогли бы обновить существующий PendingIntent до нового намерения.) Это означает, что nextButtonPendingIntent и prevButtonPendingIntent совпадают.

Решение состоит в том, чтобы указать в этом аргументе известные, отличные числа и поместить другую полезную информацию (например, идентификатор виджета) внутри намерения:

 nextButtonIntent.putExtra("widget_id", widgetId); 

И чтобы получить его в onReceive():

 int widgetId = intent.getIntExtra("widget_id");