これはStackOverflowに頻繁に投稿される問題の標準的な質問です。
チュートリアルに従っています。ウィザードを使用して新しいアクティビティを作成しました。アクティビティfindViewById()
でonCreate()
を使用して取得したNullPointerException
sのメソッドを呼び出そうとすると、View
を取得します。
アクティビティ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>
このチュートリアルはおそらく時代遅れであり、ウィザードで生成されたコードが好むフラグメントベースのUIではなく、アクティビティベースのUIを作成しようとしています。
ビューはフラグメントレイアウト(_fragment_main.xml
_)にあり、アクティビティレイアウト(_activity_main.xml
_)にはありません。 onCreate()
はライフサイクルの初期段階であるため、アクティビティビュー階層で見つけることができず、null
が返されます。 null
でメソッドを呼び出すと、NPEが発生します。
推奨される解決策は、コードをフラグメントonCreateView()
に移動し、膨張したフラグメントレイアウトrootView
でfindViewById()
を呼び出すことです。
_@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()
で実行されます。
OnStart()
メソッドを試してください
_View view = getView().findViewById(R.id.something);
_
またはgetView().findViewById
のonStart()
メソッドを使用してビューを宣言します
anyView.setOnClickListener(this);
によるビューのクリックリスナーの宣言
フラグメントのonViewCreatedメソッドにアクセスするビューをシフトしてみてください。onCreateメソッドでビューにアクセスしようとすると、nullポインタ例外が発生したときにレンダリングされないことがあるためです。
@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();
}
}
onCreate()
でUI要素にアクセスしようとしていますが、フラグメントビューではonCreateView()
メソッドで作成できるため、それらにアクセスするには早すぎます。 onActivityCreated()
メソッドは、アクティビティがこの状態で完全にロードされるため、それらに対するアクションを処理するのに信頼できます。
Android開発。混乱を軽減するために、最初に投稿した簡単なサンプルコードを作成しました。 アプリケーションは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>
これは有効な例です。アクティビティを使用してフラグメントを表示し、そのフラグメント内のイベントを処理する方法を示しています。また、包含アクティビティとの通信方法。
「何か」というビューはアクティビティではなくフラグメントにあるため、アクティビティでアクセスする代わりに、フラグメントクラスで次のようにアクセスする必要があります。
In 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;
}
activity_main.xmlに以下を追加します
<fragment
Android:id="@+id/myFragment"
Android:name="packagename.MainActivity$PlaceholderFragment"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content" >
</fragment>
_fragment_main.xml
_でビューを宣言したので、フラグメントのonCreateView()
メソッドでNPEを取得するコードの一部を移動します。これで問題が解決するはずです。
ほとんどすべての開発者が使用するビューを見つけるための最も人気のあるライブラリ。
私ができる限り、彼らは適切な方法論でビューを見つけることを説明するのに十分な答えです。しかし、あなたがAndroid開発者とコードを毎日頻繁に使用している場合、ビューを見つけるのに多くの時間を節約し、そのためのコードを書かないバターナイフを使用できます。ミリ秒単位でビューを見つけることができる-3ステップ。
アプリレベルのグラドルに依存関係を追加:
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;
onViewCreated()メソッドを使用するか、フラグメントからビューを使用または呼び出すたびに使用します。
override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
View v = view.findViewById(R.id.whatever)
}
findViewById()
onCreate()
メソッドとonCreateView()
メソッドを呼び出した後、同じNullPointerException
リスナーを初期化しています。
しかし、onActivityCreated(Bundle savedInstanceState) {...}
を使用したときは機能します。したがって、GroupView
にアクセスして、リスナーを設定できます。
お役に立てば幸いです。
重要なことを覚えておく必要があります:NullPointerExceptionは、変数を宣言し、値を割り当てる前に値を取得しようとすると発生します。
上記の投稿された質問には問題があります:oncreateメソッドでR.layout.activity_mainを使用していますが、xmlファイル名は "fragment_main.xml"です。これは、fragment_main.xmlファイルのビューを取得しようとしていることを意味します表示されていないため、nullポインター例外が発生します。コードを次のように変更します。
@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();
}
}