Android OpenCV 〜サンプルアプリを動かす〜

イントロダクション

アンドロイドでのOpenCVアプリを作成しようと考えています。
そんなわけで、下のサイトを参照してプログラムを動かしてみました。

以下の記述は参考サイトを実行して見た内容です。

AndroidでOpenCV

参考サイト: Android Pub

Step 1: Download OpenCV Android Library

ライブラリのダウンロード

  1. OpenCV + Androidのチュートリアルページを開きます。

  2. そして、OpenCV-android-sdkをダウンロードします。ZIPファイルをAndroid開発用のフォルダに展開します。

Step 2: Setup project

プロジェクトの作成

  1. Android Studioを開き、Emptyプロジェクトを作成する
    activity1

  2. プロジェクトの名前などを設定する

Step 3: Import OpenCV Module

OpenCVの取り込み

  1. 作成したプロジェクトを開いた状態で、File -> New -> Import Moduleを選択する

  2. プロジェクトの作成でダウンロード、展開した、ZIPファイルから「sdk/java」を指定する

  1. モジュールをインポートしたらビルドが始まるがエラーになる

Step 4: Fixing Gradle Sync Errors

build.gradleファイルを修正する


使用する実機がバージョン4.XだったのでminSdkVersion、targetSdkVersionを4に修正します。

Step 5: Add the OpenCV Dependency

OpenCVの依存性追加

  1. OpenCVライブラリの追加、ProjectStructure->Dependencies

Step 6: Add Native Libraries

ネイティブライブラリをコピーする

  1. OpenCVライブラリからAndroidプロジェクトのmainフォルダにペースト
  2. ペーストしたフォルダの名前を「jniLibs」に修正

Step 7: Add Required Permissions

AndroidManifest.xmlの修正

作成するプロジェクトのappフォルダにあるAndroidManifest.xmlに以下のコードを追記する

<uses-permission android:name="android.permission.CAMERA"/>

<uses-feature android:name="android.hardware.camera" android:required="false"/>
<uses-feature android:name="android.hardware.camera.autofocus" android:required="false"/>
<uses-feature android:name="android.hardware.camera.front" android:required="false"/>
<uses-feature android:name="android.hardware.camera.front.autofocus" android:required="false"/>

最終的に下のようなファイルになる

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="jp.zenryokuservice.androidopencv">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

    <uses-permission android:name="android.permission.CAMERA"/>

    <uses-feature android:name="android.hardware.camera" android:required="false"/>
    <uses-feature android:name="android.hardware.camera.autofocus" android:required="false"/>
    <uses-feature android:name="android.hardware.camera.front" android:required="false"/>
    <uses-feature android:name="android.hardware.camera.front.autofocus" android:required="false"/>
</manifest>

adbコマンド準備

  1. AndroidSDKのインストール場所を確認する
    • File -> androidOtherSettings -> DefaultProjectStructure...
      DefaultProjectStructure!
  2. ターミナルを立ち上げて、パスを通す
    • viコマンドで「.bash_profile」を開く
    • sdk/platform-toolsを追加する

サンプルソースを読む

起動している、コードは参考サイトにあるコード(MainActivity.java)です。
アンドロイドアプリの実装では、準備処理と起動時の処理でメソッドが分かれているので、主要な部分を見ます。

public boolean onTouch(View v, MotionEvent event) {
        int cols = mRgba.cols();
        int rows = mRgba.rows();

        int xOffset = (mOpenCvCameraView.getWidth() - cols) / 2;
        int yOffset = (mOpenCvCameraView.getHeight() - rows) / 2;

        int x = (int)event.getX() - xOffset;
        int y = (int)event.getY() - yOffset;

        Log.i(TAG, "Touch image coordinates: (" + x + ", " + y + ")");

        if ((x < 0) || (y < 0) || (x > cols) || (y > rows)) return false;

        Rect touchedRect = new Rect();

        touchedRect.x = (x>4) ? x-4 : 0;
        touchedRect.y = (y>4) ? y-4 : 0;

        touchedRect.width = (x+4 < cols) ? x + 4 - touchedRect.x : cols - touchedRect.x;
        touchedRect.height = (y+4 < rows) ? y + 4 - touchedRect.y : rows - touchedRect.y;

        Mat touchedRegionRgba = mRgba.submat(touchedRect);

        Mat touchedRegionHsv = new Mat();
        Imgproc.cvtColor(touchedRegionRgba, touchedRegionHsv, Imgproc.COLOR_RGB2HSV_FULL);

        // Calculate average color of touched region
        mBlobColorHsv = Core.sumElems(touchedRegionHsv);
        int pointCount = touchedRect.width*touchedRect.height;
        for (int i = 0; i < mBlobColorHsv.val.length; i++)
            mBlobColorHsv.val[i] /= pointCount;

        mBlobColorRgba = converScalarHsv2Rgba(mBlobColorHsv);

        Log.i(TAG, "Touched rgba color: (" + mBlobColorRgba.val[0] + ", " + mBlobColorRgba.val[1] +
                ", " + mBlobColorRgba.val[2] + ", " + mBlobColorRgba.val[3] + ")");

        mDetector.setHsvColor(mBlobColorHsv);

        Imgproc.resize(mDetector.getSpectrum(), mSpectrum, SPECTRUM_SIZE, 0, 0, Imgproc.INTER_LINEAR);

        mIsColorSelected = true;

        touchedRegionRgba.release();
        touchedRegionHsv.release();

        return false; // don't need subsequent touch events
    }

このコードで注目したいのは、「赤い線をつけている部分」です。

結論、下の部分で画面に表示している情報を更新しているように思います。
<MainActivity.java>

// Calculate average color of touched region
mBlobColorHsv = Core.sumElems(touchedRegionHsv);
int pointCount = touchedRect.width * touchedRect.height;
for (int i = 0; i < mBlobColorHsv.val.length; i++)
    mBlobColorHsv.val[i] /= pointCount;

mBlobColorRgba = converScalarHsv2Rgba(mBlobColorHsv);

Log.i(TAG, "Touched rgba color: (" + mBlobColorRgba.val[0] + ", " + mBlobColorRgba.val[1] +
        ", " + mBlobColorRgba.val[2] + ", " + mBlobColorRgba.val[3] + ")");

mDetector.setHsvColor(mBlobColorHsv);

Imgproc.resize(mDetector.getSpectrum(), mSpectrum, SPECTRUM_SIZE, 0, 0, Imgproc.INTER_LINEAR);

動かして見たところ、上記のメソッドで画面をタッチしたときの色を取得しているようです。

そして、その色の輪郭部分を描画している。。。ように見えます。
その部分が以下のコードです。
<MainActivity.java>

if (mIsColorSelected) {
    mDetector.process(mRgba);
    List<MatOfPoint> contours = mDetector.getContours();
    Log.e(TAG, "Contours count: " + contours.size());
    Imgproc.drawContours(mRgba, contours, -1, CONTOUR_COLOR);

    Mat colorLabel = mRgba.submat(4, 68, 4, 68);
    colorLabel.setTo(mBlobColorRgba);

    Mat spectrumLabel = mRgba.submat(4, 4 + mSpectrum.rows(), 70, 70 + mSpectrum.cols());
    mSpectrum.copyTo(spectrumLabel);
}

mDetectorはサンプルコードにあるクラスで輪郭部分の描画を行なっているように見えます。

ちょっと自信がないので、「〜のように見えます」と記載しています。

輪郭部分を塗りつぶす

サンプルの実行では下の通りです。

あとは、コードを弄り確認することにします。

でわでわ。。。

次回 >>>

Java デザインパターン 〜Factory Method パターン〜

今回は、Androidアプリ作成のヒントとしてデザインパターンに関して記載します。

大まかに、Androidアプリのフレームワーク(アーキテクチャ)として下のような図が描けます。(Androidのサイト参照)

そして、このフレームワーウを理解するために「デザインパターン」の理解がいちばんの近道だと思うので記載します。MVCモデル(参考)の理解にも近いです。

基本はオブジェクト指向

オブジェクト指向と一言で言いますが、「ポリモーフィズム」のことです。「?」が頭に浮かんだ方は気にしなくて結構です。重要ではありません。イメージがつきやすいであろうと思い記載しました。

ポイント

オブジェクト指向の考え方に従い、色々考えていくと「デザインパターン」にたどり着きます。
早い話が、「こう設計すると、綺麗なデザインになります」というものです。

Factory Methodパターン

今回は、このパターンから入ります。
Factoet Methodパターンの理解から入りたいと思います。

親クラスをカスタムするパターン

このFactory Methodパターンは、すでに出来上がっている親子関係を使って新しい機能を実装する時に便利なパターンです。

具体的に

実装するクラスで「First Program is ...」という文言を出力するところを変更して、好きな文言を出力するプログラムを作ろうとした時、以下のような形で実装できます。
<親クラス>

class Parent {
  public Parent() {
  }

  public void sayHello() {
     System.out.println("First Program is ...);
  }

  public static void main(String[] args) {
      sayHello();
  }

<子クラス>

class Child {
  public Child() {
  }

  @Override
  public void sayHello() {
      System.out.println("Hello World!");
  }
}

これで、親クラスのメインメソッドを実行した時には「First Program is ..」と表示されますが、子クラスからメインメソッドを実行すると「Hello World」と表示されます。

ちょっと簡単でしたが、こんな感じです。

Androidアプリを作成する時には、一度作成したクラスの一部を変更したい時に使える方法と言えます。

Springframeworkでもこのデザインパターを使用しているようです。

BeanFactoryというクラスがそれのようです。

このクラスは、XMLでロードしたクラスを取得するときに使用するクラスだったと思います。

詳細に関しては、こちらのリンクを参照ください。

上のリンクは、SpringframeworkのJavaDocへのリンクになります。

java apiで使用しているもの

これらは、上記のフレームワークに必要なオブジェクトのインスタンスを生成するようなファクトリクラスのようです。

でわでわ。。。



Java Android アーキテクチャ 〜デザインパターンを見る〜

題名にあるようにデザインパターンに関して記載していきます。
参考にするのはアンドロイド・デベロッパーサイトです

事の発端

前回、Java Basicと称して、Androidアプリの開発に使用するJavaの基本に関して記載し始めることにしました。
しかし、フレームワークとしてAndroidを見て見るとどうしても「デザインパターン」というものに出くわしてしまいます。なのでここら辺を穿って行こうと思いました。

デザインパターンとは?

「こんな感じで実装するとクールだ!」というものが「〜パターン」という形で表現されています。

代表的なものにGOFのデザインパターンというものがあります。早い話が以下のようなものです。

クラスの継承をうまく使ってこのデザインパターンという実装方法を行うことで、余計な処理を作成しなくてよくなります。

このデザインパターンを理解するとAndroidの開発も楽になります。というかすでに使用されているのでどんなデザインパターンを使用しているのか?を明確にするとあとが楽です。

推奨されるデザインパターン

依存性の注入(DI)インタンスを「new」演算子を使用しないで取得します。
サービスロケータ・パターン: これは DIと似たようなものらしいですが、DIより簡単らしいです。

調べた結果

結局のところはMVCモデルと同じような形で作成されているようです。
ここに「どのデザインパターンを使おうか?」という疑問が出てきて、「どれを使おうか?」と話を進めていくようになりそうです。

つまり、アーキテクチャは下のようになっているのでそこにどのようなデザインパターンを使用するか?というところがキモになりそうです。

Androidのアーキテクチャ

  1. Activity(Fragment)を基準(スタート地点)にして
  2. 読み込む画面(ViewModel)のデータ(layout.xmlに書いたデータ)を表示してから
  3. Repository(データアクセスモジュール)で必要なデータをデータソース(DBなど)から取得する

こんな感じで実装するようです。「アーキテクチャ」というのは実装するときの「思想」とか「概要(フレームワーク)」という意味です。

このアーキテクチャにこのパターン

早い話が、上記のように考えると答えが見つけやすいであろうというところです。
次回からは具体的にデザインパターンを使用する方向でコードを書きたいと思います。

でわでわ。。。。



Eclipse セットアップ

  1. Java Install Eclipse〜開発ツールのインストール〜
  2. TensorFlow C++環境〜EclipseCDTをインストール〜
  3. Setup OpenGL with JavaJOGLを使う準備 for Eclipse
  4. Eclipse Meven 開発手順〜プロジェクトの作成〜
  5. Java OpenCV 環境セットアップ(on Mac)
  6. Eclipse SceneBuilderを追加する
  7. JavaFX SceneBuilder EclipseSceneBuilder連携~

Java Basic一覧

  1. Java Basic Level 1 〜Hello Java〜
  2. Java Basic Level2 〜Arithmetic Calculate〜
  3. Java Basic Level3 〜About String class〜
  4. Java Basic Level 4〜Boolean〜
  5. Java Basic Level 5〜If Statement〜
  6. Java Basic Summary from Level1 to 5
  7. Java Basic Level 6 〜Traning of If statement〜
  8. Java Basic Level8 〜How to use for statement〜
  9. Java Basic Level 8.5 〜Array〜
  10. Java Basic Level 9〜Training of for statement〜
  11. Java Basic Level 10 〜While statement 〜
  12. Java Basic Swing〜オブジェクト指向〜
  13. Java Basic Swing Level 2〜オブジェクト指向2〜
  14. サンプル実装〜コンソールゲーム〜
  15. Java Basic インターフェース・抽象クラスの作り方
  16. Java Basic クラスとは〜Step2_1〜
  17. Java Basic JUnit 〜テストスイートの作り方〜

Git関連

  1. Java Git clone in Eclipse 〜サンプルの取得〜
  2. Eclipse Gitリポジトリの取得 GitからソースをPullしよう〜
  3. IntelliJ IDEA GitGitリポジトリからクローン〜

Java Basic for Android 〜Android実装でのJavaベーシック〜

毎度おなじみ?のJavaBasicコーナーです。
今回は、Android実装で使用するJavaの考え方を中心に記載します。
ちなみに今までのJavaBasicはイチから全部を作成するためのもの。。。低レベルな実装からおこなっております。Androidでちょっと複雑なこと、例えば3Dモデルを描画するとか、。。。、をやろうとするときに使えるものです。つまり文法とファイル入出力などです。
キホンですね。よかったらどうぞ。

  1. Java Basic その1
  2. Java Basic その2

AndroidでのJava Basic

Androidでの実装は、Javaで作成される画面、アクション、通信などの実装が行われています。
いわゆる「フレームワーク」としての実装があるので前回作成した「MainActivity」クラスのみの実装でHello Worldが表示できます。

このフレームワークに関しては、こちらのページも参照して欲しいのですが、大まかに必要な部分のみを実装すれば動く便利アイテムというイメージです。

具体的に

Android Studioでプロジェクトを作成したときに自動生成されたファイルがたくさんあります。
主要な部分としては以下の通りです。

  1. activity_main.xml
  2. MainActivity.java
  3. AndroidManifest.xml

他にもありますが、フレームワークの中身を見るのが目的ではないので、この3ファイルに着目します。

1のactivity_main.xmlは以前記載した記事でHello Worldの文言を変更するときに触りました。

  1. 見た目の作りについて
  2. 見た目の変更

Androidフレームワークでは、このXMLファイルにかいたプロパティを読み込んでJava側で表示するものを作成しています。
そして、XMLを読み込む処理は下の部分です。

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        // 親クラスのonCreateを実行する
        super.onCreate(savedInstanceState);
        // activity_main.xmlを読み込む
        setContentView(R.layout.activity_main);
    }

なので、画面の見た目を作成する方法としては2通りあるということになります。

  1. XMLで作成する
  2. Javaコードで作成する

自分はJavaコードで作成する方に慣れているのでXMLはあまり使用しませんでしたが、ちょうど良い機会なので使ってみました。
設定するプロパティは変わらないのでXMLから入ってもJavaコードから入っても良いと思います。

しかし、世の中「GUIで実装する」ということもあるので。。。なんともいいがたし。。。

とりあえずはコードとXMLの関係がわかれば問題ないと思います。

クラスの継承関連

自動生成されたコードを見てみます。

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

こんな感じだったと思います。
注目して欲しいのはextends AppCompatActivityの部分です。
フレームワークたる部分になるのでプログラミング初心者にはちょっと難しいかもですが、簡単にいうと『「extends」すると細かい処理は全部フレームワークがやってくれる』というところです。

クラスを継承する

ちなみに「extends」というのは日本語で「継承」と言います。クラスを継承するというのは、わかりづらい概念だと思います。自分は理解するのに結構時間がかかりました。

理解するポイントとしては、以下の通りです。

  1. 関係性を見て見る
  2. 実装して動かして見る
  3. どこがどのようになっているのか整理する

というわけで、簡単なアプリを作成して見るのが一番早いというわけです。
参考程度ですが、継承に関してOracleDocを引用して継承についてコードを交えて記載した記事があるので、それもよかったらどうぞ。

参考に下にリンクをつけておきます。

  1. オブジェクト指向の概念1〜OracleDocのチュートリアル1〜
  2. オブジェクト指向の概念3〜継承とは〜
  3. オブジェクト指向の概念4〜インターフェースとは〜

サンプル実装

ちょっと作成して見ました。
<親クラス>

public class ParentCls {
    private String parentName;
    protected int parentId;
    public String parentFunc;

    public ParentCls() {
        System.out.println("ParentCls is here");
    }

    private void say() {
        System.out.println("private: say parent");
    }

    protected void say(String message) {
        System.out.println("protected: " + message);
    }

    public void say(String message, int num) {
        System.out.println("public: " + message + " in " + num);
    }
}

<子クラス>

public class ChildCls extends ParentCls{
    public void sayChild() {
        say("Hello Parent");
    }
}

<実行したテストコード>

public class ExampleUnitTest {
    @Test
    public void testPrentChild() {
        ChildCls child = new ChildCls();
        // 子クラスから親クラスのメソッド
        child.say("Java Basic");
        // 子クラスのメソッド
        child.sayChild();
    }
}

実行結果

今回作成したのはAndroidでのテスト実行クラスです。
テスト実行処理は下のようなコードで実行しました。

public class ExampleUnitTest {
    @Test
    public void testPrentChild() {
        ChildCls child = new ChildCls();
        // 子クラスから親クラスのメソッド
        child.say("Java Basic");
        // 子クラスのメソッド
        child.sayChild();
    }
}

今回はここら辺で失礼します。

でわでわ。。。

関連ページ

Java学習フロー(こんなのどうでしょう?)

Javaでコンソールアプリを作る

Eclipse セットアップ

  1. Java Install Eclipse〜開発ツールのインストール〜
  2. TensorFlow C++環境〜EclipseCDTをインストール〜
  3. Setup OpenGL with JavaJOGLを使う準備 for Eclipse
  4. Eclipse Meven 開発手順〜プロジェクトの作成〜
  5. Java OpenCV 環境セットアップ(on Mac)
  6. Eclipse SceneBuilderを追加する
  7. JavaFX SceneBuilder EclipseSceneBuilder連携~

Java Basic一覧

  1. Java Basic Level 1 〜Hello Java〜
  2. Java Basic Level2 〜Arithmetic Calculate〜
  3. Java Basic Level3 〜About String class〜
  4. Java Basic Level 4〜Boolean〜
  5. Java Basic Level 5〜If Statement〜
  6. Java Basic Summary from Level1 to 5
  7. Java Basic Level 6 〜Traning of If statement〜
  8. Java Basic Level8 〜How to use for statement〜
  9. Java Basic Level 8.5 〜Array〜
  10. Java Basic Level 9〜Training of for statement〜
  11. Java Basic Level 10 〜While statement 〜
  12. Java Basic Swing〜オブジェクト指向〜
  13. Java Basic Swing Level 2〜オブジェクト指向2〜
  14. サンプル実装〜コンソールゲーム〜
  15. Java Basic インターフェース・抽象クラスの作り方
  16. Java Basic クラスとは〜Step2_1〜
  17. Java Basic JUnit 〜テストスイートの作り方〜

Git関連

  1. Java Git clone in Eclipse 〜サンプルの取得〜
  2. Eclipse Gitリポジトリの取得 GitからソースをPullしよう〜
  3. IntelliJ IDEA GitGitリポジトリからクローン〜


Java Android 6〜計算アプリのJavaコードを書く〜

今回は、Javaコードで計算処理を作ります。
ちなみに前回は、計算アプリの画面を作成しました。

Javaコードを書く

前回作成した画面は下のようなものです。

そして、今回はJavaでプログラミングを行います。
一番初めのHello Worldを思い出します。

実装してあるのは下のようなコードでした。

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }
}

このコードに、作成したXMLの内容から画面の部品を取得するコードを追加します。

// 画面のコンポーネントを取得
TextView title = (TextView) findViewById(R.id.textView);
EditText firstData = (EditText) findViewById(R.id.editText1);
EditText secondData = (EditText) findViewById(R.id.editText2);
TextView answer = (TextView) findViewById(R.id.textView4);
// ボタンをクリックした時の動作
Button execute = (Button) findViewById(R.id.button);
execute.setOnClickListener(this);

そして「ボタンをクリックした時の動作」を実装します。
手順は以下の通りです。

  1. View.OnClickListenerをimplementsする
  2. OnClick()をオーバーライドする

実装したコードで下のような実装があります。

// ボタンをクリックした時の動作
Button execute = (Button) findViewById(R.id.button);
execute.setOnClickListener(this);

この実装は、「MainActivityクラスをOnClickListenerとして使用します」という意味です。

早い話が、OnClickListener#onClick()がクリックしたときに動くわけです。
なので下のように実装してみました。
今回は起動の確認を行いたいので、仮実装になります。

@Override
public void onClick(View textView4) {
    String text = ((TextView) textView4).getText().toString();
    System.out.println("Value: " + text);
}

この引数にある「textView4」というのは、XMLで定義した画面の部品(TextView)です。
自分は、ボタンが謳歌された時の引数には「textView4」が渡されると思ったからこのような名前にしました。
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"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

        <TextView
            android:id="@+id/textView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/hello"
            android:textSize="30sp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintTop_toTopOf="parent" >

        </TextView>

        <EditText
            android:id="@+id/editText1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:ems="2"
            android:inputType="textPersonName"
            android:text="A"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintHorizontal_bias="0.02"
            app:layout_constraintTop_toTopOf="@+id/textView"
            app:layout_constraintLeft_toLeftOf="@+id/textView"
            app:layout_constraintRight_toRightOf="@+id/textView"
            app:layout_constraintVertical_bias="0.521"
            />

        <TextView
            android:id="@+id/textView2"
            android:layout_width="10dp"
            android:layout_height="20dp"
            android:text="+"
            app:layout_constraintTop_toTopOf="@+id/editText1"
            app:layout_constraintLeft_toRightOf="@+id/editText1"
            android:layout_margin="15dp"
            />

        <EditText
            android:id="@+id/editText2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="28dp"
            android:ems="2"
            android:inputType="textPersonName"
            android:text="B"
            app:layout_constraintTop_toTopOf="@+id/editText1"
            app:layout_constraintLeft_toRightOf="@+id/textView2"
            />

        <TextView
            android:id="@+id/textView3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text=" = "
            app:layout_constraintTop_toTopOf="@+id/editText1"
            app:layout_constraintLeft_toRightOf="@+id/editText2"
            android:layout_margin="15dp"
            />

        <TextView
            android:id="@+id/textView4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="TextView"
            app:layout_constraintTop_toTopOf="@+id/editText1"
            app:layout_constraintLeft_toRightOf="@+id/textView3"
            android:layout_margin="15dp"
            />

        <Button
            android:id="@+id/button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="80dp"
            android:layout_marginLeft="76dp"
            android:text="計算"
            app:layout_constraintBottom_toBottomOf="@+id/textView2"
            app:layout_constraintLeft_toRightOf="@+id/editText1" />

</androidx.constraintlayout.widget.ConstraintLayout>

そして、実行してみます。
OnClickの実装は下の通りです。

@Override
public void onClick(View textView4) {
    String text = ((TextView) textView4).getText().toString();
    System.out.println("Value: " + text);
}

引数の文字列をコンソールに表示します。

それでは実行してみます。

色々と問題があります。が、今回はボタンをクリックした時の引数はなんなのか?を確かめるのが目的なので、ここに注力します。

実行した時のログで下のような文言が出力されていました。
com.zenryokuservice.myapplication I/System.out: Value: 計算
上のコードのSystem.out.println("Value: " + text);の部分がコンソール(Logcat)に出力されます。

そして、「計算」という文字の入った画面の部品があります。そーです。「ボタン」です。
なので、引数のViewは「Button」が入ってくるのです。

クラスが別?

「ViewとButtonは別クラスでわ?」と疑問に思った方、素晴らしい!
基本的には、別クラスなのでViewで受け取ることはできないのです。
ただし、インターフェースを実装していれば話は別になります。
ここで、ButtonクラスのJavaDocAPIをみてみます。

上のようにクラスの継承ツリーが書いてあります。
察しの良い方は気がついたと思いますが、「Button」クラスは「View」クラスの子供に当たるのです。
つまり、Viewクラスとして使用することができます。

(View) findViewById(R.id.button);

これでビルドエラーは出ません。ボタンとして使用できませんが。。。

とりあえずは、ここまでにします。
ここからちょっと複雑な話になります。

でわでわ。。。

<<< [前回](http://zenryokuservice.com/wp/2020/02/26/java-android-5%e3%80%9c%e8%a8%88%e7%ae%97%e3%82%a2%e3%83%97%e3%83%aa%e3%82%92%e4%bd%9c%e3%82%8b%e3%80%9c/) ## 関連ページ ・ カテゴリ別記事一覧
Java学習フロー(自分の提案するものです)
Javaでコンソールアプリを作る