2016-05-05 1 views
1

Код, приведенный ниже, вызывается в цикле. Я читал this SO answer, но, поскольку я не могу setTagMenuItem, Target получает собранный мусор. onBitmapLoaded не вызывается. Как я могу решить эту проблему.Загрузка растрового изображения в элемент меню в цикле с помощью Picasso

Другой вопрос: при первом запуске приложения оно не работает. Как это работает после того, как я снова вызову этот метод.

private void addServiceToMenu(Service service, final MenuItem menuItem) { 
    if (!TextUtils.isEmpty(service.getIconURL())) { 
     Resources resources = getResources(); 
     final int targetWidth = resources.getDimensionPixelSize(R.dimen.menu_icon_size); 
     final int targetHeight = resources.getDimensionPixelSize(R.dimen.menu_icon_size); 

     final Target target = new Target() { 
      @Override 
      public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) { 
       Drawable drawable = new BitmapDrawable(getResources(), bitmap); 

       drawable.setBounds(0, 0, targetWidth, targetHeight); 
       menuItem.setIcon(drawable); 
      } 

      @Override 
      public void onBitmapFailed(Drawable errorDrawable) { } 

      @Override 
      public void onPrepareLoad(Drawable placeHolderDrawable) { } 
     }; 

     Picasso.with(MainActivity.this).load(service.getIconURL()) 
       .resize(targetWidth, targetHeight) 
       .into(target); 
    } 
} 
+0

Конечно, есть где-то разумно держать 'Target' ссылку, хотя. Как поле объекта, который имеет этот метод? Некоторые действия, контроллер или просмотр? –

+1

Что касается другого вопроса, то причина, по которой обратный вызов не возвращается в первый раз, заключается в том, что ссылка «Target» теряется при загрузке, но во второй раз мы получаем кеширование ответа и мы немедленно обращаемся к «Целевому» '. –

+0

Это активность -> 'Picasso.with (MainActivity.this)' – osrl

ответ

1

Создайте класс, в котором вы можете хранить ссылки на Target.

Полный рабочий пример:

public class MainActivity extends AppCompatActivity { 

    private final List<Service> services = new ArrayList<>(); 

    { 
    // add arbitrary data just for the example 
    services.add(new Service("Android", 
     "https://github.com/google/material-design-icons/raw/master/action/drawable-xhdpi/ic_android_black_24dp.png")); 
    services.add(new Service("Account", 
     "https://github.com/google/material-design-icons/raw/master/action/drawable-xhdpi/ic_account_circle_black_24dp.png")); 
    services.add(new Service("Shopping", 
     "https://github.com/google/material-design-icons/raw/master/action/drawable-xhdpi/ic_add_shopping_cart_black_24dp.png")); 
    } 

    @Override public boolean onCreateOptionsMenu(Menu menu) { 
    for (Service service : services) { 
     // create a few MenuItems. Normally done in XML. 
     MenuItem menuItem = menu.add(service.getName()); 
     menuItem.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS); 
     // load the icon using Picasso 
     addServiceToMenu(service, menuItem); 
    } 
    return super.onCreateOptionsMenu(menu); 
    } 

    private void addServiceToMenu(Service service, final MenuItem menuItem) { 
    if (!TextUtils.isEmpty(service.getIconURL())) { 
     Resources resources = getResources(); 
     final int targetWidth = resources.getDimensionPixelSize(R.dimen.menu_icon_size); 
     final int targetHeight = resources.getDimensionPixelSize(R.dimen.menu_icon_size); 
     final MenuItemIconLoader loader = new MenuItemIconLoader(menuItem, targetHeight, targetWidth); 
     loader.load(MainActivity.this, service); 
    } 
    } 

    class MenuItemIconLoader { 

    private final WeakReference<MenuItem> itemWeakReference; 
    private final int targetHeight; 
    private final int targetWidth; 

    public MenuItemIconLoader(MenuItem menuItem, int targetHeight, int targetWidth) { 
     this.itemWeakReference = new WeakReference<>(menuItem); 
     this.targetHeight = targetHeight; 
     this.targetWidth = targetWidth; 
    } 

    private final Target target = new Target() { 

     @Override public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom from) { 
     MenuItem menuItem = itemWeakReference.get(); 
     if (menuItem != null) { 
      Drawable drawable = new BitmapDrawable(getResources(), bitmap); 
      drawable.setBounds(0, 0, targetWidth, targetHeight); 
      menuItem.setIcon(drawable); 
     } 
     } 

     @Override public void onBitmapFailed(Drawable errorDrawable) { 

     } 

     @Override public void onPrepareLoad(Drawable placeHolderDrawable) { 

     } 
    }; 

    public void load(Context context, Service service) { 
     Picasso.with(context).load(service.getIconURL()).resize(targetWidth, targetHeight).into(target); 
    } 

    } 

    static class Service { 

    private String name; 
    private String iconUrl; 

    public Service(String name, String iconUrl) { 
     this.name = name; 
     this.iconUrl = iconUrl; 
    } 

    public String getName() { 
     return name; 
    } 

    public String getIconURL() { 
     return iconUrl; 
    } 

    } 

} 
+0

Не моя ли цель тоже сильная? Если не так? – osrl

+0

Ваша цель - сбор мусора, потому что это локальная переменная, объявленная внутри метода. Picasso загружает выталкиваемый на другой поток, а ваша локальная переменная - сбор мусора. Создание целевой переменной экземпляра будет содержать ее в памяти. https://github.com/square/picasso/issues/83 –

+0

'MenuItemIconLoader' также является локальной переменной, объявленной внутри того же метода. Что хранит его в памяти? Почему нет сбора мусора? Кроме того, почему вы использовали 'WeakReference'? – osrl

0

Я реализовал @ Джаред answer, но это не сработало. Поэтому я решил сохранить все MenuItemIconLoader s в списке, и это сработало. Я думаю, что был прав насчет вопроса:

Что хранит «MenuItemIconLoader» в памяти?

Вот мое решение:

List<Service> mServices = new ArrayList<>(); 
//To keep them in memory 
final List<MenuItemIconLoader> mIconLoaderList = new ArrayList<>(); 
.... 
// 
for (int i = 0; i < mServices.size(); i++) { 
    Service service = mServices.get(i); 
    final MenuItem menuItem = menu.add(SERVICES, Menu.NONE + i, i + 1, service.getTitle()) 
      .setCheckable(true); 
    mIconLoaderList.add(new MenuItemIconLoader(MainActivity.this, menuItem)); 
} 
addServicesToMenu(); 

.... 
private void addServicesToMenu() { 
    for (int i = 0; i < mServices.size(); i++) { 
     Service service = mServices.get(i); 
     MenuItemIconLoader iconLoader = mIconLoaderList.get(i); 

     if (!TextUtils.isEmpty(service.getIconURL())) { 
      iconLoader.load(service); 
     } 
    } 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^