うきっとラボ~中卒から始めるプログラミング~

中卒のポンコツ太郎が立派なプログラマになるまでの道のり

初心者がJavaでシューティングゲームアプリ作ってみる その3

〜Part.3:タイトル画面からバトル画面へ遷移させる〜

さ、今日はタイトル画面の処理をつくりますぞえ~~~!


※ちょっとその前に※

前回のコードのちょっとした訂正をしました

前回までは、
ビューに表示するテキストをtext属性に「直接」かきこんでいましたが、
これは「strings.xml」に書き込んで使用する方がいろいろとメリットがあるそうです!

実際にやってみましょう!
app/res/values/strings.xml」に以下の文字を追加していきます

<resources>
    <string name="app_name">ShootStar</string>
    <string name="tv_title">★ShootStar★</string>  //これと
    <string name="btn_start">スタート</string>  //これ
</resources>

次に、activity_title.xmlを編集していきます。
text属性に、さっき記述した@string/〇〇と指定します。

    <TextView
        ~省略~
        android:text="@string/tv_title"
        ~省略~
     />

    <Button
        ~省略~
        android:text="@string/btn_start"
        ~省略~
     />

string.xmlを使用すると、
・同じ文字を表示したいときに楽
・リストを表示したいときに文字列配列リソースとして管理できる
ローカライズにも便利

というメリットがあるようですΣ(゚Д゚)
ローカライズのやり方についてはまたまとめますね!

さ、それでは始めましょう!


どんな処理にするか

これは簡単です!!!

スタートボタンを押したらactivity_battleに遷移する」

以上!!(ドン!!!)


自動生成されたコードを観察

TitleActivity自動生成されたコードがありますね~

ちょっと観察してみましょう。

~パッケージ・インポートは省略~
public class TitleActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }
}

ふむ。AppCompatActivityを継承して、onCreate()メソッドをオーバーライドしていますね(そのまま)

どうやらアクティビティとして扱うためには、このAppCompatActivtyクラスを継承しないといけないようです!

では、onCreate()メソッドについて。これはアクティビティのライフサイクルメソッドですね。
ライフサイクルメソッドについては、まとめて記事にする予定です!

簡単に言うと、アクティビティの状態が変わることによって呼ばれるメソッドです!
onCreate()の場合、「停止状態のアプリが初めて起動したとき」に1度だけ呼ばれます!
このメソッドの中に、実行したい処理を書き入れていきます。


コンテンツビューの設定

まず、アクティビティ自体を表す「activity_title.xml」と、
その処理を表す「TitleActivity.java」を関連付けます。

onCreate()メソッド内でsetContentView()を呼び出し、アクティビティを設定します。

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_title);  //追加

    }

これでTitleActivity内からactivity_titleビューを取得することができるようになります!(/・ω・)/

ビューの取得

今回取得したいビューは「スタートボタン」だけですね。

ビューの取得にはfindViewById()メソッドを使用します。
引数にビューを表すIDを渡し、ビューオブジェクトとして取得します(^_^)v

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_title);

        Button btn_start = findViewById(R.id.btn_start);  //追加

    }

ButtonというのはViewのサブクラスで、取得したButtonオブジェクトに処理を追加していくことで、実際のアクティビティで動作するようになります。


クリックリスナーを設定

btn_start変数に「クリックリスナー(クリック時の処理)」をセットしていきます
クリックリスナーの設定は、「setOnClickListener()」を呼び出します。
引数には、OnClickListenerインタフェースを実装しonClick()メソッドをオーバーライドしたクラスを渡します

別でクラスを作ってもいいのですが、特に必要ないので匿名クラスで実装します。

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_title);

        Button btn_start = findViewById(R.id.btn_start);

        btn_start.setOnClickListener(new View.OnClickListener() {  //匿名クラスで実装
            @Override
            public void onClick(View v) {
                //ここにクリック時の処理を記述
            }
        });
    }

画面を遷移する処理

処理はこうなりました

        btn_start.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent();  //Intentオブジェクト生成
                intent.setClassName(getPackageName(), getPackageName()+ ".BattleActivity");  //遷移先クラスの指定
                startActivity(intent);  //遷移スタート
            }
        });

これでBattleActivityに画面が遷移するようになりました。
画面の遷移はあるアクティビティから別のアクティビティへとインテントを送ることで行われます。
それを表すのがIntentオブジェクトです。


コードをスマートにする

画面を遷移するコードの記述は終わりましたが、コードが少し冗長な気がします。
そのため、スマートに整理していきます

整理前のコード↓

public class TitleActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_title);

        Button btn_start = findViewById(R.id.btn_start);
        btn_start.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent();
                intent.setClassName(getPackageName(), getPackageName()+ ".BattleActivity");
                startActivity(intent);
            }
        });
    }
}

①onClick()はOnClickListenerのSAMなのでラムダ式で実装可
②onClick()内でIntentを生成すると、クリックするたびにオブジェクトが生成される(無駄)
③同じくクリック毎にgetPackageName()も呼ばれる(Intentのコンストラクタに遷移先を指定して生成可能)

整理後のコード↓

public class TitleActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_title);

        //Intentオブジェクト生成&遷移先アクティビティ指定
        Intent intent = new Intent(TitleActivity.this, BattleActivity.class);

        Button btn_start = findViewById(R.id.btn_start);

        //ラムダ式でリスナー実装
        btn_start.setOnClickListener(v -> startActivity(intent));
    }
}

かなりすっきりしたコードになりました。


さぁ、次はバトル画面を作っていきます!!


追記:整理後のコード、「Intentオブジェクト」生成コードにて

コンストラクタに引数に渡すコンテキストがさらにスマートに書けるとご指摘をいただきました!

Intent intent = new Intent(this, BattleActivity.class);
//コンテキストを渡せばいいので"TitleActivity"は冗長

もしくは

Intent intent = new Intent(getApplication(), BattleActivity.class);
//複数回の画面遷移する場合、強参照によるOut Of Memoryの可能性があるため

とできるようです!