Youtube 在 setRaetainInstance(true) 时泄漏服务连接

Youtube Leaked Service Connection when setRaetainInstance(true)

我遇到以下错误:

04-26 11:41:58.662: E/ActivityThread(10933): Activity MyActivity has leaked ServiceConnection com.google.android.youtube.player.internal.r$e@2cf388d that was originally bound here

我有一个片段,我在 onCreate 中设置了以下内容:

/**
 * 
 */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    this.setRetainInstance(true);
}

我设置这个是因为我有一个带有缩略图的 youtube 视频列表,但我没有 希望每次用户旋转屏幕时重新加载这些缩略图。 那只是不必要的流量。

以下是我的列表视图适配器:

public class YoutubeListAdapter extends BaseAdapter {
    private List<TutorialEntry> entries = null;
    private List<View> entryViews = null;
    private Map<YouTubeThumbnailView, YouTubeThumbnailLoader> thumbnailViewToLoaderMap = null;
    private LayoutInflater inflater = null;
    private TutorialThumbnailListener thumbnailListener = null;
    private boolean labelsVisible = false;;

    public YoutubeListAdapter(Context context, List<TutorialEntry> entries) {
        this.entries = entries;
        this.entryViews = new ArrayList<View>();
        this.thumbnailViewToLoaderMap = new HashMap<YouTubeThumbnailView, YouTubeThumbnailLoader>();
        this.inflater = LayoutInflater.from(context);
        this.thumbnailListener = new TutorialThumbnailListener(this.thumbnailViewToLoaderMap);
        this.labelsVisible = true;
    }

    @Override
    public int getCount() {
        return this.entries.size();
    }

    @Override
    public TutorialEntry getItem(int position) {
        return entries.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        TutorialEntry entry = entries.get(position);

        ViewHolder holder = null;

        if (convertView == null) {
            convertView = this.inflater.inflate(R.layout.fragment_tutorials_row, parent, false);

            holder = new ViewHolder();
            holder.thumbnail = (YouTubeThumbnailView) convertView.findViewById(R.id.tutorials_row_thumbnail);
            holder.thumbnail.setTag(entry.getVideoId());
            holder.thumbnail.initialize(Globals.GOOGLE_API_KEY, this.thumbnailListener);
            holder.textViewTitle = (TextView) convertView.findViewById(R.id.tutorials_row_title);

            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();

            YouTubeThumbnailLoader loader = this.thumbnailViewToLoaderMap.get(holder.thumbnail);

            if (loader == null) {
                holder.thumbnail.setTag(entry.getVideoId());
            } else {
                holder.thumbnail.setImageResource(R.drawable.youtube_loading_thumbnail);

                loader.setVideo(entry.getVideoId());
            }
        }

        holder.textViewTitle.setText(entry.getTitle());
        holder.textViewTitle.setVisibility(labelsVisible ? View.VISIBLE : View.GONE);

        return convertView;
    }

    public void releaseLoaders() {
        for (YouTubeThumbnailLoader loader : this.thumbnailViewToLoaderMap.values()) {
            loader.release();
        }
    }

    public void setLabelVisibility(boolean labelsVisible) {
        this.labelsVisible = labelsVisible;

        for (View view : this.entryViews) {
            view.findViewById(R.id.tutorials_row_title).setVisibility(labelsVisible ? View.VISIBLE : View.GONE);
        }
    }

    private static class ViewHolder {
        private YouTubeThumbnailView thumbnail = null;
        private TextView textViewTitle = null;
    }
}

问题出现在这一行:

holder.thumbnail.initialize(Globals.GOOGLE_API_KEY, this.thumbnailListener);

谁能帮我了解那里发生了什么以及我该如何解决这个问题?

这个异常通常是因为没有释放所有加载器。据我所知,你永远不会调用你的 releaseLoaders() 方法,所以当 Activity 被拆除时加载程序只是坐在那里。 Android 的设计方式,你应该释放这些加载器,否则你会发生内存泄漏。

就我个人而言,我将我的加载程序发布放在我的 onstop() 方法中,它运行得非常好。

@Override
public void onStop() {
    super.onStop();
    for (YouTubeThumbnailLoader loader : thumbnailViewToLoaderMap.values()) {
        loader.release();
    }
}