web-dev-qa-db-ja.com

画像をURLからカスタムInfoWindow google maps v2に追加します

Androidアプリで作業しています。ユーザーはGoogleマップでレストランを検索します。Googleマップでは、隣人のすべてのレストランのマーカーを表示します。マーカーをタップすると表示されますカスタムInfoWindowを作成します。私の問題は、Googleの場所から返される画像を読み込めないことです。画像のURLを正しく取得できましたが、Windowに表示できません。

InfoWindow

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:orientation="vertical"
Android:background="@color/bg_color" >

<ImageView
        Android:id="@+id/place_icon"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:focusable="false"" />

<TextView
    Android:id="@+id/place_title"
    Android:layout_width="wrap_content"
    Android:layout_height="wrap_content" />

<TextView
    Android:id="@+id/place_vicinity"
    Android:layout_width="wrap_content"
    Android:layout_height="wrap_content" />

<LinearLayout 
    Android:layout_width="wrap_content"
    Android:layout_height="wrap_content"
    Android:orientation="horizontal"
    Android:background="@color/bg_color" >

    <RatingBar
         Android:id="@+id/place_rating"
         style="?android:attr/ratingBarStyleSmall"
         Android:numStars="5"
         Android:rating="0"
         Android:isIndicator="false"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:layout_marginLeft="5dip" />

    <ImageView
        Android:id="@+id/navigate_icon"
        Android:layout_width="wrap_content"
        Android:layout_height="wrap_content"
        Android:focusable="false"
        Android:src="@drawable/navigate" />

</LinearLayout>

作成時に私はこれを持っています

mGoogleMap.setInfoWindowAdapter(new InfoWindowAdapter() {

            // Use default InfoWindow frame
            @Override
            public View getInfoWindow(Marker arg0) {
                return null;
            }

            // Defines the contents of the InfoWindow
            @Override
            public View getInfoContents(Marker arg0) {

                // Getting view from the layout file info_window_layout
                View v = getLayoutInflater().inflate(R.layout.info_window_layout, null);

                // Getting the snippet from the marker
                String snippet = arg0.getSnippet();

                // Getting the snippet from the marker
                String titlestr = arg0.getTitle();

                String cutchar1= "%#";
                String cutchar2= "%##";
                String ratingstr = snippet.substring(0,snippet.indexOf( cutchar1 ));
                String vicinitystr = snippet.substring(snippet.indexOf( cutchar1 )+2, snippet.indexOf( cutchar2 ) );
                String iconurl= snippet.substring(snippet.indexOf( cutchar2 )+3);

                // Getting reference to the TextView to set latitude
                TextView title = (TextView) v.findViewById(R.id.place_title);

                TextView vicinity = (TextView) v.findViewById(R.id.place_vicinity);

                ImageView image = (ImageView) v.findViewById(R.id.navigate_icon);

                // Setting the latitude
                title.setText(titlestr);

                // declare RatingBar object
                RatingBar rating=(RatingBar) v.findViewById(R.id.place_rating);// create RatingBar object
                if( !(ratingstr.equals("null")) ){
                    rating.setRating(Float.parseFloat(ratingstr));
                }
                vicinity.setText(vicinitystr);                  

                final DownloadImageTask download = new DownloadImageTask((ImageView) v.findViewById(R.id.place_icon) ,arg0);
                download.execute(iconurl);
                // Returning the view containing InfoWindow contents
                return v;

            }

});

そしてDownloadImageコードは:

private class DownloadImageTask extends AsyncTask<String, Void, Bitmap> {
      ImageView bmImage;
      Marker marker;
      boolean refresh;

      public DownloadImageTask(final ImageView bmImage, final Marker marker) {
          this.bmImage = bmImage;
          this.marker=marker;
          this.refresh=false;
      }

     public void SetRefresh(boolean refresh ){
         this.refresh=true;

     }

    /*  @Override
      protected void onPreExecute() 
      {
          super.onPreExecute();
          bmImage.setImageBitmap(null);
      }*/

      @Override
      protected Bitmap doInBackground(String... urls) {
          String urldisplay = urls[0];
          Bitmap mIcon11 = null;
          try {
            InputStream in = new Java.net.URL(urldisplay).openStream();
            mIcon11 = BitmapFactory.decodeStream(in);
          } catch (Exception e) {
              Log.e("Error", e.getMessage());
              e.printStackTrace();
          }
          return mIcon11;
      }
      @Override
      protected void onPostExecute(Bitmap result) {
          if(!refresh){
              SetRefresh(refresh);
              bmImage.setImageBitmap(result);
              marker.showInfoWindow();
          }
      }
    }

最後に、コードを実行してマーカーをタップすると、getInfoContentsが実行を停止せず、アイコンが表示されません。

なぜこれが起こるのですか?

18
Mixalis

同様のアプリを作成しています。

まず、InfoWindowにダウンロードした画像が表示されないのは、MapFragmentがビューをCanvasにレンダリングしてから描画するためです。情報ウィンドウに表示されるのは、作成したビューではなく、それらの「画像」または「スクリーンショット」です。基本的に、MarkerオブジェクトでshowInfoWindow()を再度呼び出す必要があります。これにより、Canvasが再レンダリングされ、画像が表示されます。

ただし、そうは言っても、私の経験では、URLからBitmapを読み込んで設定することは最善の解決策ではありません。 AndroidはBitmapsをうまく処理しません。いくつかのビットマップをロードした後、システムメモリの量に応じて、OutOfMemoryError例外は時間の問題ですあなたが持っている。

非同期ダウンロードとキャッシュ(メモリとディスク内)を処理し、実際のイメージの読み込みを1行だけにする(Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);)ピカソライブラリの使用をお勧めします。 (詳細は http://square.github.io/picasso/ にあります)

前の答えは良かったが、彼が言ったように、「遅延」は私の好みには少し不思議すぎる。ピカソにはコールバックを使用するオプションがあり、それを使用することをお勧めします(私はそれをアプリで使用しています)。

まず、ピカソのCallbackインターフェースを実装するクラス(アクティビティの内部にすることができます)を作成し、コンストラクターでMarkerを受け取ります(そのため、showInfoWindow()を呼び出すことができます)再びマーカー。

_private class InfoWindowRefresher implements Callback {
   private Marker markerToRefresh;

   private InfoWindowRefresher(Marker markerToRefresh) {
        this.markerToRefresh = markerToRefresh;
    }

    @Override
    public void onSuccess() {
        markerToRefresh.showInfoWindow();
    }

    @Override
    public void onError() {}
}
_

情報ウィンドウは次のようになります。

_mMap.setInfoWindowAdapter(new GoogleMap.InfoWindowAdapter() {
    @Override
    public View getInfoWindow(Marker marker) {
        // inflate view window

        // set other views content

        // set image view like this:
        if (not_first_time_showing_info_window) {
            Picasso.with(ActivityClass.this).load(restaurantPictureURL).into(imgInfoWindowPicture);
        } else { // if it's the first time, load the image with the callback set
            not_first_time_showing_info_window=true;
            Picasso.with(ActivityClass.this).load(restaurantPictureURL).into(imgInfoWindowPicture,new InfoWindowRefresher(marker));
        }

        return v;
    }

    @Override
    public View getInfoContents(Marker marker) {
        return null;
    }
});
_

ご覧のとおり、コールバックは非常に単純です。ただし、この方法を使用するときは、最初の呼び出しでのみコールバックを使用し、後続の呼び出しでは使用しないように注意する必要があります(私は単に_not_first_time_showing_info_window_アイデアを反映するには...それをプログラムロジックに含める方法を確認する必要があります。そうしないと、PicassoコールバックがshowInfoWindow()を呼び出し、それが再実行されます-showInfoWindow()...をリコールするコールバックを呼び出します。

主なことは、コールバックを使用してピカソのロードを1回だけ実行し、その後の呼び出しではコールバックなしで実行することです。

37
Daniel Gray

私はこの問題をブラックマジック(別名、遅延の設定)を使用して解決しました。私はピカソのキャッシュを利用して、最初の読み込みが始まってから数ミリ秒後にshowInfoWindowを呼び出しました。

これが私のCustomWindowAdapterです。

class CustomWindowAdapter implements InfoWindowAdapter{
   LayoutInflater mInflater;
   Map<Marker, String> imageStringMapMarker;
   Context context;

   public CustomWindowAdapter(LayoutInflater i,  Map<Marker, String> imageStringMapMarker2, Context context ){
      mInflater = i;
      imageStringMapMarker = imageStringMapMarker2;
   }

   @Override
   public View getInfoContents(final Marker marker) {

      View v = mInflater.inflate(R.layout.custom_info_window, null);

      ImageView ivThumbnail = (ImageView) v.findViewById(R.id.ivThumbnail);
      String urlImage = imageStringMapMarker.get(marker).toString();
      Picasso.with(context).load(Uri.parse(urlImage)).resize(250,250).into(ivThumbnail);

      return v;

   }

   @Override
   public View getInfoWindow(Marker marker) {
    // TODO Auto-generated method stub
     return null;
   }
}

そして、これがメインアクティビティの情報ウィンドウを呼び出すためのメソッドで、ここで遅延を実装しています。

myMap.setInfoWindowAdapter(new CustomWindowAdapter(this.getLayoutInflater(),
imageStringMapMarker, getApplicationContext()));
myMap.setOnMarkerClickListener(new OnMarkerClickListener() {

    @Override
    public boolean onMarkerClick(final Marker mark) {


    mark.showInfoWindow();

        final Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                mark.showInfoWindow();

            }
        }, 200);

        return true;
    }
});
10

その時点でgetInfoContents()から返すものは何でもBitmapに変換され、結果の表示に使用されます。後で[Bitmapが既に作成および使用されている時点で、ダウンロードが完了するまで、イメージは表示されません。

getInfoContents()が呼び出される前に、イメージをダウンロードする必要があります。

7
CommonsWare

@ Daniel Grey answer も参照してこれを行います。

if (userImg.getDrawable() == null) {
  Picasso.with(ctx).load(UtilitiesApp.urlServer + user.getImgUrl())
      .error(R.drawable.logo)
      .into(userImg, new InfoWindowRefresher(marker));
} else {
  Picasso.with(ctx).load(UtilitiesApp.urlServer + user.getImgUrl())
      .error(R.drawable.logo)
      .into(userImg);
}


public class InfoWindowRefresher implements Callback {
  private Marker markerToRefresh;

  public InfoWindowRefresher(Marker markerToRefresh) {
    this.markerToRefresh = markerToRefresh;
  }

  @Override
  public void onSuccess() {
    markerToRefresh.showInfoWindow();
  }

  @Override
  public void onError() {}
}
1
Cristian Hoyos