Я просто проверял мое приложение на другом устройстве и обнаружил, что я получаю ошибку на Nexus 4 под управлением Android 4.4.2, но NOT на Android-устройстве Desire S под управлением Android 4.0.4. У обоих из них установлено приложение YouTube (5.3.32), которое требуется для использования API.
Вопрос: Почему я получаю эти сообщения ServiceConnectionLeaked? (см LogCat ниже)
Описание:
Я использую API YouTube Android игрока 1.0.0 (https://developers.google.com/youtube/android/player/) для загрузки видео Эскизы в ListView с помощью следующего кода адаптера:
private final Map<View, YouTubeThumbnailLoader> mThumbnailViewToLoaderMap;
public ListViewAdapter(Activity activity, int layoutId, List<Suggestion> suggestions) {
super(activity, layoutId, suggestions);
mThumbnailViewToLoaderMap = new HashMap<View, YouTubeThumbnailLoader>();
}
@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 & 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();
}
}
Обломок, который держит этот ListView имеет следующий код:
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();
}
Вот что происходит:
- Создан Фрагмент, миниатюры YouTube загружены и отображаются правильно.
Теперь я повернуть устройство на первый время (скажем, в альбомной ориентации):
- Обломок создается, уже существующий адаптер подключен к ListView, но нет эскизов не загружается для всех отображаемых в данный момент элементов списка.
- Когда я прокручиваю вниз, на экран выводятся новые элементы списка.
- Если такой новый элемент списка использует новый ViewHolder, его миниатюра загружается правильно.
- Если такие новые элементы списка используют ViewHolder из первых видимых элементов списка, его миниатюра вообще не загружается.
Таким образом, это приводит список миниатюр, которые чередуются в загружаемой правильно и не загружаются вообще. Теперь повернуть устройство на второго времени (обратно в портретную ориентацию):
- Фрагмент создан, существующий адаптер подключен к ListView и все эскизы правильно загружены.
Теперь я повернуть устройство в третьего время (мы снова в ранее ошибочной альбомной ориентации):
- Обломок создается, существующий адаптер подключен к ListView и все миниатюрам загружаются правильно.
Так что только после первого поворота устройства происходит что-то, поэтому видимые миниатюры не загружаются в их элементы списка.
LogCat показывает folllowing сообщения для каждого запроса пиктограмм после первого поворота:
03-09 17:43:08.770 30446-30446/com.mypackage.name E/ActivityThread: Activity com.mypackage.name.activities.SearchActivity has leaked ServiceConnection [email protected] that was originally bound here android.app.ServiceConnectionLeaked: Activity com.mypackage.name.activities.SearchActivity has leaked ServiceConnection [email protected] 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) ...
Почему я получаю эти ServiceConnectionLeaked сообщения?
Я уже искал вокруг, и в большинстве случаев существует какая-то инициализация API, необходимая там, где нужно предоставить контекст приложения вместо контекста активности. Но с API-интерфейсом YouTubePlayer Android такой инициализации нет (по крайней мере, не в моей части кода).