виджет приложения setImageViewUri не обновляет изображение

у меня есть виджет приложения, который содержит только одно изображение. я перерисовываю это изображение и сохраняю его как png в частной памяти приложений, а затем я устанавливаю изображение RemoteViews с uri (widget.setImageViewUri(R.id.widget_icon, uri)) вместо того, чтобы отправлять растровое изображение самостоятельно, потому что в очень редких случаях ситуации я получаю !!! НЕУДАЧНАЯ СДЕЛКА СВЯЗИВАТЕЛЯ !!!

проблема в том, что по мере изменения изображения со временем изображение виджета не меняется. я проверил сохраненный png с помощью root explorer, и он обновляется правильно. но правильное изображение не отображается. каждый виджет показывает изображение с момента его добавления на главный экран. если я использую setImageViewBitmap(...), он работает правильно, за исключением редкой неудачной транзакции связывателя.

я обновляю виджет из службы с помощью метода ниже. он не работает на андроиде 2.3.7, а также с запущенным эмулятором 2.2. В чем может быть проблема? это как-то кешируется?

public void updateWidget(Context context) {
  // redraws the widget's image
  updateIcon();

  OutputStream stream;
  try {
    stream = context.openFileOutput("icon.png", Context.MODE_WORLD_READABLE);
  }
  catch (FileNotFoundException ex) {
    ex.printStackTrace();
    return;
  }

  m_Icon.compress(CompressFormat.PNG, 100, stream);

  try {
    stream.close();
  }
  catch (IOException ex) {
    ex.printStackTrace();
  }

  AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
  int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, WidgetProvider.class));

  Intent intent = new Intent(context, MyDialog.class);
  intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);

  PendingIntent clickIntent = PendingIntent.getActivity(context, 0, intent, 0);

  File file = new File(context.getFilesDir().getAbsolutePath() + File.separator + "icon.png");
//      Uri uri = Uri.fromFile(file);

  // update all widgets on home screen
  for (int wid : appWidgetIds) {
    RemoteViews widget = new RemoteViews(context.getPackageName(), R.layout.widget);
    widget.setOnClickPendingIntent(R.id.widget_layout, clickIntent);

    // === EDIT ===
    // Uri.fromFile(file); does not work correctly on android 2.1, only 2.2 and up
    // widget's image will disappear
//        widget.setImageViewUri(R.id.widget_icon, uri);
    widget.setImageViewUri(R.id.widget_icon, Uri.parse(file.getPath()));

    intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, wid);

    appWidgetManager.updateAppWidget(wid, widget);
  }
}

EDIT: я также попробовал собственный ContentProvider и установил uri "content://...", но с тем же результатом. виджет показывает изображение с момента его добавления на главный экран и не обновляется с течением времени.

logcat не показывает никаких ошибок.


person shelll    schedule 26.10.2011    source источник
comment
Вы используете один и тот же URI (одно и то же имя файла) для всех своих значков, и в этом проблема. URI должен быть уникальным по файлу, ресурсу... Система не обновляет рисуемый объект и использует первый загруженный и его ожидаемое поведение. Я думаю, что лучше использовать FileProvider и предоставить несколько файлов. вы можете удалить устаревший и обновить виджет с новым URI.   -  person Anis BEN NSIR    schedule 02.01.2017
comment
@AnisBENNSIR Этот вопрос был задан и решен пять лет назад...   -  person shelll    schedule 03.01.2017
comment
Извините, но награда находится в открытом состоянии ... Может быть, мой комментарий будет полезен для нового пользователя, принятый ответ - не лучшее решение.   -  person Anis BEN NSIR    schedule 03.01.2017


Ответы (3)


Если Uri останется без изменений, похоже, Android не будет обновлять образ. Однако я нашел небольшой хак, чтобы обойти это. Просто позвоните widget.setImageViewUri(R.id.widget_icon, Uri.parse("")); перед widget.setImageViewUri(R.id.widget_icon, uri);.

Он вызывает setImageViewUri() дважды, но, кажется, работает нормально. Я хотел бы услышать лучший способ исправить это, так как я сам сталкиваюсь с этой проблемой.

person Michell Bak    schedule 26.10.2011
comment
я пытался это сделать, но я отправлял нулевой Uri, который давал сбой. пустая строка решила эту проблему, спасибо! есть какой-то кеш, который надо уметь отключать при необходимости :( - person shelll; 27.10.2011
comment
сначала установка пустого uri, а затем установка правильного uri решает проблему, но выдает огромное количество предупреждений в logcat при каждом обновлении виджета, потому что пустой uri недействителен... так что это только частичное решение, но оно работает. - person shelll; 27.10.2011
comment
Да, это проблема с использованием этого решения. Как я уже сказал, это хак, и я хотел бы найти лучший способ, но я просто не знаю лучшего способа сделать это. - person Michell Bak; 27.10.2011
comment
есть еще одна проблема с этим подходом. виджет мерцает на некоторых обновлениях. я думаю, мне придется сохранить изображение дважды и каждый раз назначать uri второго изображения. - person shelll; 31.10.2011
comment
Я такого не испытывал, должен сказать. - person Michell Bak; 31.10.2011
comment
Прошло уже почти 6 лет с этого ответа, который до сих пор отлично работал для меня. Но недавно я обнаружил, что при определенных обстоятельствах (Android O + Pixel Launcher) процедура обновления виджета никогда не достигает загрузки второго (подлинного) URI... после первого (поддельного) URI происходит сбой, но не загружается подлинный URI, таким образом оставляя пустой виджет. С тем же кодом, тем же устройством и той же ОС, но с другим лаунчером (Nova) все работает нормально. Таким образом, это может быть связано с пусковой установкой, но, вероятно, является результатом использования неуклюжего решения, такого как использование недопустимого URI. Должен быть лучший способ? - person drmrbrewer; 03.08.2017

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

public static Bitmap getBitmap( String imageLocation ) {

    BitmapFactory.Options options = new BitmapFactory.Options();
    options.inPreferredConfig = Bitmap.Config.ARGB_8888;

    return BitmapFactory.decodeFile(imageLocation, options);
}

тогда

bitmap = BitmapUtils.getBitmap( address.getPhotoLocation() );
row.setImageViewBitmap( R.id.row_image, bitmap );
person Juan Mendez    schedule 26.10.2017

person    schedule
comment
у меня была эта проблема давным-давно, но мое текущее решение похоже на ваше в сочетании с принятым ответом. вместо установки пустого uri или поворота двух имен изображений я просто всегда устанавливаю два uri изображения и сохраняю растровое изображение для них обоих. это работает, нет ветвления и не выдает никаких ошибок в logcat, таких как пустой uri. - person shelll; 29.04.2012
comment
Это приведет к увеличению использования хранилища, подумайте, если код используется многими виджетами, это не очень хорошая практика, вместо этого используйте принятый ответ и забудьте о журнале. - person YEH; 27.11.2015
comment
пожалуйста, не могли бы вы расширить решение, которое вы используете @shell? Итак, вы просто сохраняете две идентичные копии растрового изображения с разными именами и, как и в принятом ответе, делаете widget.setImageViewUri() дважды подряд, указывая на два растровых изображения соответственно? то есть такой же, как принятый ответ, за исключением того, что вместо пустого URI вы используете URI, который указывает на идентичную копию растрового изображения, поэтому эффективно загружает одно и то же изображение дважды подряд? - person drmrbrewer; 03.08.2017
comment
@drmrbrewer да, я делаю именно это. я сохраняю растровое изображение дважды с разными именами. изображения маленькие, поэтому проблем с хранением нет. нет мерцания, как с трюком с пустым URL. и в логарифме нет предупреждений. - person shelll; 03.08.2017
comment
Хорошо, спасибо @shell, я попробую реализовать это. Как упоминалось в моем комментарии к принятому решению, у меня оно работало нормально (без мерцания), пока я не нажал определенную комбинацию устройства/ОС/лаунчера, поэтому мне нужно попробовать что-то другое. По какой причине вы не можете просто переключаться между двумя именами файлов, сохраняя только один растровый рисунок в хранилище в любое время (удаляя другой) и используя только один setImageViewUri(), а не два? Помимо добавления сложности (для небольшого выигрыша, если изображения все равно маленькие)? - person drmrbrewer; 03.08.2017
comment
@drmrbrewer Я не хотел создавать сложную логику для такой маленькой проблемы. наличие двух изображений, сохраненных все время, и всегда установка uri дважды - это пуленепробиваемый. мое приложение было установлено более чем на 200 тыс. устройств без каких-либо жалоб пользователей на проблемы с памятью :) - person shelll; 03.08.2017
comment
Это должен быть лучший ответ на 2018 год. В другом принятом ответе есть проблемы с некоторыми устройствами. - person woltran; 25.12.2018