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();
}
}
我遇到以下错误:
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();
}
}