56609


androidアプリを個人開発しています。  
アプリは野球の成績を入力してランキングを作成するというものです。

本題です。  
最初に呼び出されるactivityのHome.javaで、ボタンのリスナを呼び出しHome.javaからInput.javaへ遷移するときにRuntimeExceptionが発生してアプリが落ちます。logcatを見るとInput_2.javaのgetStrint()で、NullPointerExceptionが発生していました。そもそもInput_2.javaは、Input.javaでSpinnerの項目を選択した時に呼び出されるFragmentのはずなので、なぜ呼び出されたのかわかりません。また、なぜgetString()でNullPointerExceptionが発生したのかもわかりません。

質問をまとめます。

  1. Input.javaに遷移するときになぜInput_2.javaが呼び出されるのか。
  2. getStringメソッドでなぜNullPointerExceptionが発生するのか。

です。

初めてのアプリ開発なので基本的なことがわかっていないかもしれませんが、ご教授をお願いします。

Home.java

[code]

    import android.content.Intent;
    import android.database.sqlite.SQLiteDatabase;
    import android.database.sqlite.SQLiteStatement;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.text.Editable;
    import android.text.TextWatcher;
    import android.view.View;
    import android.widget.ArrayAdapter;
    import android.widget.Button;
    import android.widget.EditText;
    import android.widget.ListView;
    import android.widget.TextView;
    
    import java.util.ArrayList;
    
    public class Home extends AppCompatActivity {
        //選手IDを表すフィールド　登録ボタンが押される度に＋1
        int playerId = 0;
        //選手名を表示するListViewのフィード
        ListView playerMenu;
        //登録ボタンのフィード
        Button entryButton;
        //入力ボタンのフィード
        Button inputButton;
        //ランキングボタンのフィード
        Button rankingButton;
        //選手を入力するEditTextのフィード
        EditText nameEditText;
        //ListViewに項目がないとき表示するビューのフィード
        TextView emptyTextView;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.home_main);
    
            //登録ボタンを所得
            entryButton = findViewById(R.id.enterButton);
            //選手を入力するEditTextを取得
            nameEditText = findViewById(R.id.nameEditText);
            //選手名を表示するListViewを取得
            playerMenu = findViewById(R.id.playerList);
            //ListViewに項目がない時に表示するビューを取得
            emptyTextView = findViewById(R.id.emptyTextView);
            playerMenu.setEmptyView(emptyTextView);
            //nameEditTextにリスナを登録
            nameEditText.addTextChangedListener(new EditEventListener());
    
            //ArrayListを作成
            ArrayList<String> item = new ArrayList<>();
            //データベースから選手名を取得
            DatabaseOperation.returnItem(item, Home.this);
            //ArrayAdapterのコンストラクタ
            ArrayAdapter<String> adapter = new ArrayAdapter<>(Home.this, android.R.layout.simple_list_item_1, item);
            //ListViewにアダプターをセット
            playerMenu.setAdapter(adapter);
        }
    
        //登録ボタンがタップされた時の処理メソッド
        public void onEnterButtonClick(View view) {
            //IDを取得
            playerId += 1;
            //入力された選手名を取得
            nameEditText = findViewById(R.id.nameEditText);
            String name = nameEditText.getText().toString();
    
            //データベースヘルパーオブジェクトを作成
            DatabaseHelper helper = new DatabaseHelper(Home.this);
            //データベースヘルパーオブジェクトからデータベース接続オブジェクトを取得
            SQLiteDatabase db = helper.getWritableDatabase();
            try {
                //インサート用のSQL文字列の用意
                String sqlInsert = "INSERT INTO baseballscore (_id, name) VALUES (?, ?)";
                //SQL文字列をもとにプリペアドステートメントを取得
                SQLiteStatement stmt = db.compileStatement(sqlInsert);
                //変数バインド
                stmt.bindLong(1,playerId);
                stmt.bindString(2,name);
                //インサートSQLの実行
                stmt.executeInsert();
            }
            finally {
                db.close();
            }
            //入力値を削除
            nameEditText.setText("");
            //登録ボタンをタップできないように変更
            entryButton.setEnabled(false);
    
            //選手名を表示するListViewを取得
            playerMenu = findViewById(R.id.playerList);
    
            //ArrayListを作成
            ArrayList<String> item = new ArrayList<>();
            //データベースから選手名を取得
            DatabaseOperation.returnItem(item, Home.this);
            //ArrayAdapterのコンストラクタ
            ArrayAdapter<String> adapter = new ArrayAdapter<>(Home.this, android.R.layout.simple_list_item_1, item);
            //ListViewにアダプターをセット
            playerMenu.setAdapter(adapter);
        }
    
        //入力ボタンがタップされた時の処理メソッド
        public void onInputButtonClick (View view) {
            //インテントオブジェクトを生成
            Intent intent = new Intent(Home.this, Input.class);
            //遷移
            startActivity(intent);
        }
    
        //ランキングボタンがタップされた時の処理メソッド
        public void onRankingButtonClick(View view) {
            //インテントオブジェクトを生成
            Intent intent = new Intent(Home.this, Ranking.class);
            //遷移
            startActivity(intent);
        }
    
        //EditText選手名が入力された時の処理が記述されたメンバクラス
        private class EditEventListener implements TextWatcher {
            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
            }
    
            @Override
            public void afterTextChanged(Editable s) {
                //登録ボタンをタップできるように設定
                entryButton.setEnabled(true);
            }
        }
    
    }
    
[/code]

Input.java

[code]

    import android.support.v4.app.FragmentManager;
    import android.support.v4.app.FragmentTransaction;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.AdapterView;
    import android.widget.ArrayAdapter;
    import android.widget.Spinner;
    import java.util.ArrayList;
    
    public class Input extends AppCompatActivity {
         //選手を選択するSpinnerのフィード
        Spinner  pSelectSpinner;
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.input);
    
            //選手を選択するSpinnerを取得
            pSelectSpinner = findViewById(R.id.playerSelectSpinner);
    
            //ArrayListを作成
            ArrayList<String> item = new ArrayList<>();
            //データベースから選手名を取得
            DatabaseOperation.returnItem(item, Input.this);
            //ArrayAdapterのコンストラクタ
            ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, item);
            //リストに表示するレイアウトを指定
            adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
            //Spinnerにアダプターをセット
            pSelectSpinner.setAdapter(adapter);
            //Spinnerにリスナを登録
            pSelectSpinner.setOnItemSelectedListener(new OnItemSelectedListener());
        }
    
        //戻るボタンがタップされた時の処理メソッド
        public void onBackButtonClick(View view) {
            //このActivityを終了
            finish();
        }
    
        //Spinnerのリスナクラス
        public class OnItemSelectedListener implements AdapterView.OnItemSelectedListener {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                //タップされた行のデータを取得
                String playerName = (String) parent.getItemAtPosition(position);
                //引継ぎデータをまとめて格納できるbundleオブジェクト生成
                Bundle bundle = new Bundle();
                //bundleオブジェクト引継ぎデータを格納
                bundle.putString("playerName", playerName);
    
                //フラグメントマネージャーの取得
                FragmentManager manager = getSupportFragmentManager();
                //フラグメンテーションの開始
                FragmentTransaction transaction = manager.beginTransaction();
                //Input_2を生成
                Input_2 input_2 = new Input_2();
                //引継ぎデータをInput_2に格納
                input_2.setArguments(bundle);
                //生成したInput_2をinput_eFragmentレイアウト部品に追加
                transaction.add(R.id.input_2Fragment, input_2);
                //フラグメントトランザクションのコミット
                transaction.commit();
            }
            @Override
            public void onNothingSelected(AdapterView<?> parent) {
            }
        }
    
    }
    
[/code]

Input_2.java

[code]

    import android.os.Bundle;
    import android.support.v4.app.Fragment;
    import android.view.LayoutInflater;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.TextView;
    
    public class Input_2 extends Fragment {
    
        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            //フラグメントで表示する画面をxmlファイルからインフレーとする
            View view = inflater.inflate(R.layout.input_2, container, false);
    
            //引継ぎデータを所得
            Bundle extras = getArguments();
            String playerName = extras.getString("playerName");
    
            //選手名を表示させるTextViewを取得
            TextView tvPlayerName = view.findViewById(R.id.playerName);
            //TextViewに選手名を表示
            tvPlayerName.setText(playerName);
            //インフレートされた画面を戻り値として返す
            return view;
        }
    
    }
    
[/code]

logcat

[code]

    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.websarva.wings.android.baseballscore/com.websarva.wings.android.baseballscore.Input}: android.view.InflateException: Binary XML file line #33: Binary XML file line #33: Error inflating class fragment
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2817)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892)
            at android.app.ActivityThread.-wrap11(Unknown Source:0)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593)
            at android.os.Handler.dispatchMessage(Handler.java:105)
            at android.os.Looper.loop(Looper.java:164)
            at android.app.ActivityThread.main(ActivityThread.java:6541)
            at java.lang.reflect.Method.invoke(Native Method)
            at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
         Caused by: android.view.InflateException: Binary XML file line #33: Binary XML file line #33: Error inflating class fragment
         Caused by: android.view.InflateException: Binary XML file line #33: Error inflating class fragment
         Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.os.Bundle.getString(java.lang.String)' on a null object reference
            at com.websarva.wings.android.baseballscore.Input_2.onCreateView(Input_2.java:21)
            at android.support.v4.app.Fragment.performCreateView(Fragment.java:2439)
            at android.support.v4.app.FragmentManagerImpl.ensureInflatedFragmentView(FragmentManager.java:1689)
            at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1431)
            at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1684)
            at android.support.v4.app.FragmentManagerImpl.addFragment(FragmentManager.java:1930)
            at android.support.v4.app.FragmentManagerImpl.onCreateView(FragmentManager.java:3745)
            at android.support.v4.app.FragmentController.onCreateView(FragmentController.java:120)
            at android.support.v4.app.FragmentActivity.dispatchFragmentsOnCreateView(FragmentActivity.java:405)
            at android.support.v4.app.FragmentActivity.onCreateView(FragmentActivity.java:387)
            at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:780)
            at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:730)
            at android.view.LayoutInflater.rInflate(LayoutInflater.java:863)
            at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:515)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:423)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:374)
            at android.support.v7.app.AppCompatDelegateImpl.setContentView(AppCompatDelegateImpl.java:469)
            at android.support.v7.app.AppCompatActivity.setContentView(AppCompatActivity.java:140)
            at com.websarva.wings.android.baseballscore.Input.onCreate(Input.java:19)
            at android.app.Activity.performCreate(Activity.java:6975)
            at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1213)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2770)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2892)
            at android.app.ActivityThread.-wrap11(Unknown Source:0)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1593)
            at android.os.Handler.dispatchMessage(Handler.java:105)
            at android.os.Looper.loop(Looper.java:164)
            at android.app.ActivityThread.main(ActivityThread.java:6541)
            at java.lang.reflect.Method.invoke(Native Method)
            at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
    
[/code]


CC BY-SA 4.0
2019-07-12T06:52:16.847
56591
2019-07-13T08:05:05.483
32776
question
android fragment nullpointerexception
android開発で遷移と値の受け渡しがうまくいかない


> Input.javaに遷移するときになぜInput_2.javaが呼び出されるのか。

Spinnerって初期表示の時点で`OnItemSelectedListener`を呼び出します。

_< 参考>_  
\- <https://qiita.com/tomoima525/items/0ecaebd6ef61935eece0>  
\- <https://woodsmall.co.jp/android/spinner-onitemselected/>

> getStringメソッドでなぜNullPointerExceptionが発生するのか。

これは推測なんですが・・・Inputアクティビティのレイアウトファイル（input.xml）の中に、Input_2フラグメントを記述したりしていませんか？
`<fragment android:name="xxx.xxx.Input_2">`のような感じで。  
スタックトレースを見るに、xmlからViewをinlfateするときに例外が発生しているようです。

**追記**  
コメントに対する回答になりますが、、、ちょっと長くなるので、参考URLを貼っておきます。  
<http://www.ifelse.jp/blog/android-02>

このサイトになぞって言うと、本ケースは レイアウトxmlは「静的な方法」になっているのに、コードについては「動的な方法」になってる、ということです。  
静的な方法（レイアウトxmlにfragmentタグを記述）だと、特にコードを書かなくてもそのレイアウトが表示されるとき、つまり本ケースの場合はInputアクティビティが表示されるときに自動的にそのフラグメントが表示されます。

結果的に`setArguments`がされていない状態でInput_2フラグメントが起動するので、`getArguments`がnullになるのです。

なお、フラグメントの生成にはパラメータが必要になることが多いので、動的な方法を使用することの方が多いと思います。


CC BY-SA 4.0
2019-07-13T03:57:11.747
56609
2019-07-13T08:05:05.483
2019-07-13T08:05:05.483
9608
9608
56591
answer