title: In ListView: Activity has leaked ServiceConnection <youtube.player.internal> that was originally bound here
body: <p><strong>Update:</strong></p>
  
  <p>I just tested my app on another device and found out that I do get the error on a Nexus 4 running Android 4.4.2, but <em>NOT</em> on an Desire S running Android 4.0.4. Both of them have the current YouTube App installed (5.3.32), which is required for using the API.</p>
  
  <p><strong>Question: Why do I get these ServiceConnectionLeaked messages?</strong> (See Logcat below)</p>
  
  <p><strong>Description:</strong></p>
  
  <p>I'm using the YouTube Android Player API 1.0.0 (<a href="https://developers.google.com/youtube/android/player/" rel="nofollow">https://developers.google.com/youtube/android/player/</a>) to load video Thumbnails in a ListView with the following adapter code:</p>
  
  <pre><code>private final Map&lt;View, YouTubeThumbnailLoader&gt; mThumbnailViewToLoaderMap;
  
  public ListViewAdapter(Activity activity, int layoutId, List&lt;Suggestion&gt; suggestions) {
      super(activity, layoutId, suggestions);     
      mThumbnailViewToLoaderMap = new HashMap&lt;View, YouTubeThumbnailLoader&gt;();
  }
  
  @Override
  public View getView(int position, View convertView, ViewGroup parent) {
  
      ViewHolder holder;
  
      String videoId = getYoutubeId();
  
      // There are three cases here...
      if (convertView == null) {
          convertView = LayoutInflater.from(mActivity).inflate(R.layout.row_suggestion, parent, false);
  
          holder = new ViewHolder();
          holder.thumbnailView = (YouTubeThumbnailView) convertView.findViewById(R.id.youtubeThumbnail);
  
          // ... case 1: The youtube view has not yet been created - we need to initialize the YouTubeThumbnailView.
          holder.thumbnailView.setLayoutParams(mThumbnailLayoutParams);
          holder.thumbnailView.setTag(videoId);
          holder.thumbnailView.initialize(DeveloperKey.DEVELOPER_KEY, this);
  
          convertView.setTag(holder);
  
      } else {
  
          holder = (ViewHolder) convertView.getTag();
  
          // ... case 2 &amp; 3 The view is already created and...
          YouTubeThumbnailLoader loader = mThumbnailViewToLoaderMap.get(holder.thumbnailView);
  
          // ... is currently being initialized. We store the current videoId in the tag.
          if (loader == null) {
              holder.thumbnailView.setTag(videoId);
  
          // ... already initialized. Simply set the right videoId on the loader.
          } else {
              loader.setVideo(videoId);
          }
      }
  
      holder.thumbnailView.setImageResource(R.drawable.thumbnail_loading);
  
      return convertView;
  }
  
  
  @Override
  public void onInitializationSuccess(YouTubeThumbnailView youTubeThumbnailView, YouTubeThumbnailLoader youTubeThumbnailLoader) {
      String videoId = (String) youTubeThumbnailView.getTag();
      mThumbnailViewToLoaderMap.put(youTubeThumbnailView, youTubeThumbnailLoader);
      youTubeThumbnailLoader.setOnThumbnailLoadedListener(this);
      youTubeThumbnailLoader.setVideo(videoId);
  }
  
  public void releaseLoaders() {
      for (YouTubeThumbnailLoader loader : mThumbnailViewToLoaderMap.values()) {
          loader.release();
      }
  }
  </code></pre>
  
  <p>The Fragment which holds this listView has the following code:</p>
  
  <pre><code>private ListViewAdapter listViewAdapter;
  
  @Override
  public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setRetainInstance(true);
  }
  
  Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
      rootView = (ViewGroup) inflater.inflate(R.layout.fragment_search_results, container, false);
      listView = (ListView) rootView.findViewById(R.id.suggestion_list);
  
      // see if there is already an adapter
      // and use it as our adapter (e.g. after device rotation)
      if (listViewAdapter != null) {
          listView.setAdapter(listViewAdapter);
      }
  
      return rootView;
  }
  
  @Override
  public void onDestroyView() {
      super.onDestroyView();
      mListViewAdapter.releaseLoaders();
  }
  </code></pre>
  
  <p>Here is what happens:</p>
  
  <ul>
  <li>The Fragment is created, the YouTube-Thumbnails are loaded and displayed correctly.</li>
  </ul>
  
  <p>Now I rotate the device the <strong>first</strong> time (let's say into landscape orientation): </p>
  
  <ul>
  <li>The Fragment is created, the already existing adapter is connected to the listView, but no thumbnail is loaded for all currently visible list items. </li>
  <li>When I scroll down, new list items enter the screen. 
  <ul>
  <li>If such a new list items uses a new ViewHolder its thumbnail is loaded correctly.</li>
  <li>If such a new list items uses a ViewHolder from the first visible list items its thumbnail is not loaded at all.</li>
  </ul></li>
  </ul>
  
  <p>So this results in a list of thumbnails which alternate in being loaded correctly and not loaded at all.
  Now I rotate the device a <strong>second</strong> time (back to portrait orientation):</p>
  
  <ul>
  <li>The Fragment is created, the existing adapter is connected to the listView and all thumbnails are loaded correctly.</li>
  </ul>
  
  <p>Now I rotate the device a <strong>third</strong> time (we are again in the previously erroneous landscape orientation):</p>
  
  <ul>
  <li>The Fragment is created, the existing adapter is connected to the listView and all thumbnails are loaded correctly.</li>
  </ul>
  
  <p>So only after the first time the device gets rotated something happens, so visible thumbnails are not loaded into their list items.</p>
  
  <p>The logcat shows the folllowing message for every thumbnail request after the first rotation:</p>
  
  <pre>
      03-09 17:43:08.770  30446-30446/com.mypackage.name E/ActivityThread: Activity com.mypackage.name.activities.SearchActivity has leaked ServiceConnection com.google.android.youtube.player.internal.r$e@41b0a6c0 that was originally bound here
      android.app.ServiceConnectionLeaked: Activity com.mypackage.name.activities.SearchActivity has leaked ServiceConnection com.google.android.youtube.player.internal.r$e@41b0a6c0 that was originally bound here
              at android.app.LoadedApk$ServiceDispatcher.(LoadedApk.java:1041)
              at android.app.LoadedApk.getServiceDispatcher(LoadedApk.java:935)
              at android.app.ContextImpl.bindServiceAsUser(ContextImpl.java:1692)
              at android.app.ContextImpl.bindService(ContextImpl.java:1680)
              at android.content.ContextWrapper.bindService(ContextWrapper.java:496)
              at com.google.android.youtube.player.internal.r.e(Unknown Source)
              at com.google.android.youtube.player.YouTubeThumbnailView.initialize(Unknown Source)
              at com.mypackage.name.adapters.ListViewAdapter.getView(ListViewAdapter.java:94)
              at com.mypackage.name.views.ListView.obtainView(ListView.java:1285)
              at com.mypackage.name.views.ListView.fillDown(ListView.java:1046)
              at com.mypackage.name.views.ListView.populate(ListView.java:720)
              at com.mypackage.name.views.ListView.onLayout(ListView.java:677)
              at android.view.View.layout(View.java:14520)
              at android.view.ViewGroup.layout(ViewGroup.java:4604)
              at android.widget.RelativeLayout.onLayout(RelativeLayout.java:1077)
              at android.view.View.layout(View.java:14520)
              at android.view.ViewGroup.layout(ViewGroup.java:4604)
              at android.widget.FrameLayout.onLayout(FrameLayout.java:448)
              ...
  </pre>
  
  <p><strong>Why do I get these ServiceConnectionLeaked messages?</strong></p>
  
  <p>I already searched around and in most cases there is some kind of API initialization necessary where one has to supply the application context instead of the activity context. 
  But with the YouTubePlayer Android API there is no such initialization (at least not in my part of the code).</p>