java - 从内部类访问时查看 null :片段
问题描述
我已经为 android 获取了youtube-api示例应用程序VideoListDemoActivity
类,并将其转换为fragment
在我的应用程序中使用。
在内部类中,访问来自片段VideoListFragment
的视图videoBox
,返回null
. 在活动中,视图不为空,但在片段中,它无法获取片段视图的引用。我附上了我为这个类修改的代码。
错误异常
2021-04-28 16:42:18.695 27495-27495/com.gardify.android E/AndroidRuntime:致命异常:主进程:com.gardify.android,PID:27495 java.lang.NullPointerException:尝试调用虚拟方法' int android.view.View.getVisibility()' 在 com.gardify.android.ui.video.VideoFragment$VideoListFragment.onListItemClick(VideoFragment.java:192) 的空对象引用上
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
videoBox = getView().findViewById(R.id.video_box);
^^^^^^^^
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
setListAdapter(adapter);
}
修改类
public final class VideoFragment extends Fragment {
/**
* The duration of the animation sliding up the video in portrait.
*/
private static final int ANIMATION_DURATION_MILLIS = 300;
/**
* The padding between the video list and the video in landscape orientation.
*/
private static final int LANDSCAPE_VIDEO_PADDING_DP = 5;
/**
* The request code when calling startActivityForResult to recover from an API service error.
*/
private static final int RECOVERY_DIALOG_REQUEST = 1;
private VideoListFragment listFragment;
private YoutubeFragment videoFragment;
private View videoBox;
private View closeButton;
private View root;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
root = inflater.inflate(R.layout.video_fragment, container, false);
videoBox = root.findViewById(R.id.video_box);
closeButton = root.findViewById(R.id.close_button);
videoBox.setVisibility(View.INVISIBLE);
return root;
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
listFragment = (VideoListFragment) getActivity().getFragmentManager().findFragmentById(R.id.list_fragment);
videoFragment = (YoutubeFragment) getActivity().getFragmentManager().findFragmentById(R.id.video_fragment_container);
checkYouTubeApi();
}
private void checkYouTubeApi() {
YouTubeInitializationResult errorReason =
YouTubeApiServiceUtil.isYouTubeApiServiceAvailable(getActivity());
if (errorReason.isUserRecoverableError()) {
errorReason.getErrorDialog(getActivity(), RECOVERY_DIALOG_REQUEST).show();
} else if (errorReason != YouTubeInitializationResult.SUCCESS) {
String errorMessage = getResources().getString(R.string.an_error_occurred);
Toast.makeText(getActivity(), errorMessage, Toast.LENGTH_LONG).show();
}
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == RECOVERY_DIALOG_REQUEST) {
// Recreate the activity if user performed a recovery action
getActivity().recreate();
}
}
public void onClickClose(@SuppressWarnings("unused") View view) {
listFragment.getListView().clearChoices();
listFragment.getListView().requestLayout();
videoFragment.pause();
ViewPropertyAnimator animator = videoBox.animate()
.translationYBy(videoBox.getHeight())
.setDuration(ANIMATION_DURATION_MILLIS);
runOnAnimationEnd(animator, new Runnable() {
@Override
public void run() {
videoBox.setVisibility(View.INVISIBLE);
}
});
}
@TargetApi(16)
private void runOnAnimationEnd(ViewPropertyAnimator animator, final Runnable runnable) {
if (Build.VERSION.SDK_INT >= 16) {
animator.withEndAction(runnable);
} else {
animator.setListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
runnable.run();
}
});
}
}
/**
* A fragment that shows a static list of videos.
*/
public static final class VideoListFragment extends ListFragment {
private static final List<VideoEntry> VIDEO_LIST;
static {
List<VideoEntry> list = new ArrayList<VideoEntry>();
list.add(new VideoEntry("YouTube Collection", "Y_UmWdcTrrc"));
list.add(new VideoEntry("GMail Tap", "1KhZKNZO8mQ"));
list.add(new VideoEntry("Chrome Multitask", "UiLSiqyDf4Y"));
list.add(new VideoEntry("Google Fiber", "re0VRK6ouwI"));
list.add(new VideoEntry("Autocompleter", "blB_X38YSxQ"));
list.add(new VideoEntry("GMail Motion", "Bu927_ul_X0"));
list.add(new VideoEntry("Translate for Animals", "3I24bSteJpw"));
VIDEO_LIST = Collections.unmodifiableList(list);
}
private PageAdapter adapter;
private View videoBox;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
adapter = new PageAdapter(getActivity(), VIDEO_LIST);
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
videoBox = getView().findViewById(R.id.video_box);
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
setListAdapter(adapter);
}
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
String videoId = VIDEO_LIST.get(position).videoId;
YoutubeFragment videoFragment = (YoutubeFragment) getFragmentManager().findFragmentById(R.id.video_fragment_container);
videoFragment.setVideoId(videoId);
// The videoBox is INVISIBLE if no video was previously selected, so we need to show it now.
if (videoBox.getVisibility() != View.VISIBLE) {
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
// Initially translate off the screen so that it can be animated in from below.
videoBox.setTranslationY(videoBox.getHeight());
}
videoBox.setVisibility(View.VISIBLE);
}
// If the fragment is off the screen, we animate it in.
if (videoBox.getTranslationY() > 0) {
videoBox.animate().translationY(0).setDuration(ANIMATION_DURATION_MILLIS);
}
}
@Override
public void onDestroyView() {
super.onDestroyView();
adapter.releaseLoaders();
}
public void setLabelVisibility(boolean visible) {
adapter.setLabelVisibility(visible);
}
}
/**
* Adapter for the video list. Manages a set of YouTubeThumbnailViews, including initializing each
* of them only once and keeping track of the loader of each one. When the ListFragment gets
* destroyed it releases all the loaders.
*/
private static final class PageAdapter extends BaseAdapter {
private final List<VideoEntry> entries;
private final List<View> entryViews;
private final Map<YouTubeThumbnailView, YouTubeThumbnailLoader> thumbnailViewToLoaderMap;
private final LayoutInflater inflater;
private final ThumbnailListener thumbnailListener;
private boolean labelsVisible;
public PageAdapter(Context context, List<VideoEntry> entries) {
this.entries = entries;
entryViews = new ArrayList<View>();
thumbnailViewToLoaderMap = new HashMap<YouTubeThumbnailView, YouTubeThumbnailLoader>();
inflater = LayoutInflater.from(context);
thumbnailListener = new ThumbnailListener();
labelsVisible = true;
}
public void releaseLoaders() {
for (YouTubeThumbnailLoader loader : thumbnailViewToLoaderMap.values()) {
loader.release();
}
}
public void setLabelVisibility(boolean visible) {
labelsVisible = visible;
for (View view : entryViews) {
view.findViewById(R.id.text).setVisibility(visible ? View.VISIBLE : View.GONE);
}
}
@Override
public int getCount() {
return entries.size();
}
@Override
public VideoEntry getItem(int position) {
return entries.get(position);
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
VideoEntry entry = entries.get(position);
// There are three cases here
if (view == null) {
// 1) The view has not yet been created - we need to initialize the YouTubeThumbnailView.
view = inflater.inflate(R.layout.video_list_item, parent, false);
YouTubeThumbnailView thumbnail = (YouTubeThumbnailView) view.findViewById(R.id.thumbnail);
thumbnail.setTag(entry.videoId);
thumbnail.initialize(DeveloperKey.YOUTUBE_API_DEVELOPER_KEY, thumbnailListener);
} else {
YouTubeThumbnailView thumbnail = (YouTubeThumbnailView) view.findViewById(R.id.thumbnail);
YouTubeThumbnailLoader loader = thumbnailViewToLoaderMap.get(thumbnail);
if (loader == null) {
// 2) The view is already created, and is currently being initialized. We store the
// current videoId in the tag.
thumbnail.setTag(entry.videoId);
} else {
// 3) The view is already created and already initialized. Simply set the right videoId
// on the loader.
//thumbnail.setImageResource(R.drawable.loading_thumbnail);
loader.setVideo(entry.videoId);
}
}
TextView label = ((TextView) view.findViewById(R.id.text));
label.setText(entry.text);
label.setVisibility(labelsVisible ? View.VISIBLE : View.GONE);
return view;
}
private final class ThumbnailListener implements
YouTubeThumbnailView.OnInitializedListener,
YouTubeThumbnailLoader.OnThumbnailLoadedListener {
@Override
public void onInitializationSuccess(
YouTubeThumbnailView view, YouTubeThumbnailLoader loader) {
loader.setOnThumbnailLoadedListener(this);
thumbnailViewToLoaderMap.put(view, loader);
view.setImageResource(R.drawable.loading_thumbnail);
String videoId = (String) view.getTag();
loader.setVideo(videoId);
}
@Override
public void onInitializationFailure(
YouTubeThumbnailView view, YouTubeInitializationResult loader) {
view.setImageResource(R.drawable.no_thumbnail);
}
@Override
public void onThumbnailLoaded(YouTubeThumbnailView view, String videoId) {
}
@Override
public void onThumbnailError(YouTubeThumbnailView view, ErrorReason errorReason) {
view.setImageResource(R.drawable.no_thumbnail);
}
}
}
public static final class YoutubeFragment extends YouTubePlayerFragment
implements OnInitializedListener {
private YouTubePlayer player;
private String videoId;
public static YoutubeFragment newInstance() {
return new YoutubeFragment();
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initialize(DeveloperKey.YOUTUBE_API_DEVELOPER_KEY, this);
}
@Override
public void onDestroy() {
if (player != null) {
player.release();
}
super.onDestroy();
}
public void setVideoId(String videoId) {
if (videoId != null && !videoId.equals(this.videoId)) {
this.videoId = videoId;
if (player != null) {
player.cueVideo(videoId);
}
}
}
public void pause() {
if (player != null) {
player.pause();
}
}
@Override
public void onInitializationSuccess(Provider provider, YouTubePlayer player, boolean restored) {
this.player = player;
}
@Override
public void onInitializationFailure(Provider provider, YouTubeInitializationResult result) {
this.player = null;
}
}
private static final class VideoEntry {
private final String text;
private final String videoId;
public VideoEntry(String text, String videoId) {
this.text = text;
this.videoId = videoId;
}
}
}
修改过的xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
class="com.gardify.android.ui.video.VideoFragment$VideoListFragment"
android:id="@+id/list_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<LinearLayout
android:id="@+id/video_box"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:orientation="vertical">
<ImageButton
android:id="@+id/close_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:src="@android:drawable/btn_dialog"
android:onClick="onClickClose"/>
<fragment
class="com.gardify.android.ui.video.VideoFragment$YoutubeFragment"
android:id="@+id/video_fragment_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
解决方案
推荐阅读
- python - 如何在 Tkinter 中使用 cpu 数据创建实时图表?
- javascript - Discord.js - 为什么 __.cache.get() 代码不起作用并且命令提示符中出现错误警报“fn 不是函数”?
- lua - 有没有办法使用 IDA 从名为 ROBLOX 的游戏中获取 Lua 类型?
- powershell - PowerShell 递归对象属性
- javascript - 什么会导致 XMLHttpRequest 在浏览器默认超时之前挂起而没有错误?
- javascript - 点击时显示每个锚点对应的 div
- python - 计算熊猫滚动偏移窗口的实际持续时间
- c# - 使用 System.Runtime.Caching
- flutter - 在flutter App中应用主题数据不会改变Appbar颜色,工具栏颜色,文本,字体和按钮
- python - 不在 Django Rest 框架中打印嵌套的序列化程序?