我正在关注一个教程。我使用向导创建了一个新活动。尝试在我的活动
NullPointerException
中用View
获得的findViewById()
上调用方法时得到onCreate()
。活动
onCreate()
:@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
View something = findViewById(R.id.something);
something.setOnClickListener(new View.OnClickListener() { ... }); // NPE HERE
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment()).commit();
}
}
布局XML (
fragment_main.xml
):<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="packagename.MainActivity$PlaceholderFragment" >
<View
android:layout_width="100dp"
android:layout_height="100dp"
android:id="@+id/something" />
</RelativeLayout>
#1 楼
本教程可能已过时,尝试创建基于活动的UI而不是向导生成的代码首选的基于片段的UI。该视图位于片段布局(
fragment_main.xml
)中,而不位于活动布局(activity_main.xml
)。 onCreate()
在生命周期中为时过早,无法在活动视图层次结构中找到它,并返回null
。在null
上调用方法会导致NPE。首选解决方案是将代码移动到片段onCreateView()
,在膨胀的片段布局findViewById()
上调用rootView
:@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_main, container,
false);
View something = rootView.findViewById(R.id.something); // not activity findViewById()
something.setOnClickListener(new View.OnClickListener() { ... });
return rootView;
}
作为补充,片段布局最终将成为活动视图层次结构的一部分,并且可通过活动
findViewById()
发现,但仅在片段事务已运行之后才能发现。在super.onStart()
之后,在onCreate()
中执行待处理的片段事务。#2 楼
尝试使用OnStart()
方法,只需使用View view = getView().findViewById(R.id.something);
,或在
getView().findViewById
中使用onStart()
方法声明任何视图通过
anyView.setOnClickListener(this);
声明在视图上单击监听器评论
对我来说,这很有用,因为我试图访问片段的onCreateView中的同级视图,该片段在xml中声明。由于父级尚未完成膨胀,所以兄弟视图在onCreateView中仍然为空,但是在onStart中,它们具有:)
–丹尼尔·威尔逊(Daniel Wilson)
15年3月16日在1:28
#3 楼
尝试将访问的视图转移到片段的onViewCreated方法,因为有时当您尝试在onCreate方法中访问视图时,它们在出现空指针异常时不会被呈现。 @Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
View something = findViewById(R.id.something);
something.setOnClickListener(new View.OnClickListener() { ... }); // NPE HERE
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment()).commit();
}
}
#4 楼
同意,这是一个典型的错误,因为人们在开始进行Android开发时通常并不真正了解Fragments是如何工作的。为了减轻混乱,我创建了一个简单的示例代码,该代码最初发布在Application上,该代码已在android emulator中停止,但我也将其发布在此处。示例如下:
public class ContainerActivity extends FragmentActivity implements ExampleFragment.Callback
{
@Override
public void onCreate(Bundle saveInstanceState)
{
super.onCreate(saveInstanceState);
this.setContentView(R.layout.activity_container);
if (saveInstanceState == null)
{
getSupportFragmentManager().beginTransaction()
.add(R.id.activity_container_container, new ExampleFragment())
.addToBackStack(null)
.commit();
}
getSupportFragmentManager().addOnBackStackChangedListener(new OnBackStackChangedListener()
{
public void onBackStackChanged()
{
int backCount = getSupportFragmentManager().getBackStackEntryCount();
if (backCount == 0)
{
finish();
}
}
});
}
@Override
public void exampleFragmentCallback()
{
Toast.makeText(this, "Hello!", Toast.LENGTH_LONG).show();
}
}
activity_container.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<FrameLayout
android:id="@+id/activity_container_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
ExampleFragment:
public class ExampleFragment extends Fragment implements View.OnClickListener
{
public static interface Callback
{
void exampleFragmentCallback();
}
private Button btnOne;
private Button btnTwo;
private Button btnThree;
private Callback callback;
@Override
public void onAttach(Activity activity)
{
super.onAttach(activity);
try
{
this.callback = (Callback) activity;
}
catch (ClassCastException e)
{
Log.e(this.getClass().getSimpleName(), "Activity must implement Callback interface.", e);
throw e;
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View rootView = inflater.inflate(R.layout.fragment_example, container, false);
btnOne = (Button) rootView.findViewById(R.id.example_button_one);
btnTwo = (Button) rootView.findViewById(R.id.example_button_two);
btnThree = (Button) rootView.findViewById(R.id.example_button_three);
btnOne.setOnClickListener(this);
btnTwo.setOnClickListener(this);
btnThree.setOnClickListener(this);
return rootView;
}
@Override
public void onClick(View v)
{
if (btnOne == v)
{
Toast.makeText(getActivity(), "One.", Toast.LENGTH_LONG).show();
}
else if (btnTwo == v)
{
Toast.makeText(getActivity(), "Two.", Toast.LENGTH_LONG).show();
}
else if (btnThree == v)
{
callback.exampleFragmentCallback();
}
}
}
fragment_example.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<Button
android:id="@+id/example_button_one"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="30dp"
android:text="@string/hello"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"/>
<Button
android:id="@+id/example_button_two"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/example_button_one"
android:layout_alignRight="@+id/example_button_one"
android:layout_below="@+id/example_button_one"
android:layout_marginTop="30dp"
android:text="@string/hello" />
<Button
android:id="@+id/example_button_three"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignLeft="@+id/example_button_two"
android:layout_alignRight="@+id/example_button_two"
android:layout_below="@+id/example_button_two"
android:layout_marginTop="30dp"
android:text="@string/hello" />
</RelativeLayout>
这应该是一个有效的示例,它显示了如何使用“活动”显示片段,以及如何处理该片段中的事件。还有如何与包含的Activity通信。
评论
此示例将android-support-v4库用于FragmentActivity和支持片段管理器。
– EpicPandaForce
2014年7月2日在9:35
一个更完整的例子可以在stackoverflow.com/questions/24840509/上找到。
– EpicPandaForce
2014年7月31日在6:34
尽管您应该使用Otto进行通讯而不是使用回调,并使用Butterknife注入视图。
– EpicPandaForce
15年3月15日在12:10
#5 楼
视图“某物”在片段中而不在活动中,因此,除了在活动中访问它之外,您还必须在片段类中访问它,例如在PlaceholderFragment.class
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View root = inflater.inflate(R.layout.fragment_main, container,
false);
View something = root .findViewById(R.id.something);
something.setOnClickListener(new View.OnClickListener() { ... });
return root;
}
#6 楼
您正在尝试访问onCreate()
中的UI元素,但是访问它们还为时过早,因为可以在onCreateView()
方法中创建片段视图。 由于活动在此状态下已完全加载,因此
onActivityCreated()
方法可可靠地对其执行任何操作。#7 楼
将以下内容添加到您的activity_main.xml<fragment
android:id="@+id/myFragment"
android:name="packagename.MainActivity$PlaceholderFragment"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
</fragment>
#8 楼
由于您已经在fragment_main.xml
中声明了View,因此将这段代码移到片段的onCreateView()
方法中获得NPE的位置。这应该可以解决问题。
#9 楼
在上面的问题中的已发布代码中,有一个问题:您在oncreate方法中使用R.layout.activity_main,但是xml文件名为“ fragment_main.xml”,这意味着您试图获取fragment_main.xml文件未显示,因此它给出了空指针异常。更改代码,例如:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_main);// your xml layout ,where the views are
View something = findViewById(R.id.something);
something.setOnClickListener(new View.OnClickListener() { ... }); // NPE HERE
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction()
.add(R.id.container, new PlaceholderFragment()).commit();
}
}
#10 楼
您必须记住重要的事情是:当您声明变量并尝试在为其赋值之前检索其值时,会发生NullPointerException。
#11 楼
每当使用片段或从片段调用视图时,请使用onViewCreated()方法。override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
View v = view.findViewById(R.id.whatever)
}
#12 楼
在调用NullPointerException
,findViewById()
和onCreate()
方法之后,我有相同的onCreateView()
初始化侦听器。但是当我使用
onActivityCreated(Bundle savedInstanceState) {...}
时,它可以工作。因此,我可以访问GroupView
并设置我的监听器。我希望它会有所帮助。
#13 楼
几乎每个开发人员都使用的最受欢迎的查找视图的库。ButterKnife
因为我所能提供的足够的答案来解释使用正确的方法查找视图。但是,如果您是android开发人员,并且每天都经常编写代码,则可以使用黄油刀,这样可以节省很多时间来查找视图,而您无需编写代码,只需2-3个步骤,您就可以在几毫秒内找到视图。
在应用程序级别gradle中添加依赖项:
implementation 'com.jakewharton:butterknife:8.8.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
添加黄油刀插件:
File -> Settings -> plugins->
然后搜索Android ButterKnife Zelezny并安装插件,然后重新启动您的工作室即可。
现在只需转到您活动的Oncreate方法,然后右键单击您的layout_name并点击“生成”按钮并选择“黄油刀注入”选项,您的视图引用将自动创建,如下所述:
@BindView(R.id.rv_featured_artist)
ViewPager rvFeaturedArtist;
@BindView(R.id.indicator)
PageIndicator indicator;
@BindView(R.id.rv_artist)
RecyclerView rvArtist;
@BindView(R.id.nsv)
NestedScrollingView nsv;
@BindView(R.id.btn_filter)
Button btnFilter;
评论
findViewById部分应位于onActivityCreated中。
– AndroidGeek
16年8月9日在7:50
@Nepster可以但不一定要。
–laalto
16年8月9日在7:52
有时活动尚未附加到片段。
– AndroidGeek
16年8月9日在7:53
@Nepster这就是为什么在rootView而不是Activity上调用findViewById()的原因。
–laalto
16年8月9日在7:54