2016-05-05 16 views
1

以下のコードはループで呼び出されます。私はthis SO answerを読んだが、私はsetTagからMenuItemには届かないので、Targetはガベージコレクションされる。 onBitmapLoadedは呼び出されません。どうすればこの問題を解決できますか?ピカソでループ内のメニュー項目にビットマップを読み込む

もう1つの質問は、アプリの最初の起動時には機能しません。このメソッドをもう一度呼び出すと、どうやって動作しますか?

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

もう1つの質問として、コールバックが最初に戻ってこない理由は、読み込み中に 'Target'参照が失われますが、2回目には応答がキャッシュされ、' 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をリストに入れておくことに決めました。

「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); 
     } 
    } 
} 
関連する問題