Android App 〜画面作成を行う〜

画面作成

作成したのは、以下の機能です。

  1. 多言語化
  2. 画面に文字列を表示する

stringc.xmlを使う

下のように作成した*strings.xmlの中にある「android\:id="@+id\/top_title"」をアプリに反映するというところです。
次のファイルに以下の1行を追加しました。

android:id="@+id/top_title"

全体を記述すると下のようになります。

<activity_main.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/top_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/app_name"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintHorizontal_bias="0.534"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.05" />

</androidx.constraintlayout.widget.ConstraintLayout>

<strings.xml>

<resources>
    <string name="app_name">目標達成アプリ</string>
</resources>

これを実行した結果、下のように表示されました。

テキストのサイズ変更

したのようなプロパティ(属性)を設定することで、テキストのサイズを変更できました。

        android:layout_width="match_parent"
        android:layout_height="100dp"

そして、自動サイズ調整はしたのようにやるみたいです。

        android:autoSizeTextType="uniform"
        android:autoSizeMinTextSize="12sp"
        android:autoSizeMaxTextSize="100sp"

これを記述するとAndroid APIのレベル別のactivity_main.xmlが作成されるようです。
※Android Studioで「Override XXX」と表示されるのでそれをクリックしました。

最終的に、下のようなファイルが作成されました。

イメージの追加

説明を文言でするよりも、動画の方がよいと思いました。

サポートライブラリ追加

ここで、エラーが発生しています。これは、AppCompatというサポートライブラリが無いために起きているエラーです。
これをインストールするためには、Java11が必要になります。

JDK11インストール

WidnowsでのAndroid Studioが起動できなかったので、現在はMacで作業をしていますので、home brewを使用してインストールしました。参考サイトはこちらです。

下のコマンドでインストールできました。

brew install java11

しかし、次のようなエラーが出ました。

Invalid Gradle JDK configuration found

これは、プロジェクト構成(Project Structure) -> SDKLocation -> JDKの設定でJava11tを設定し、改めてビルドしたらなおりました。

Android Studioアップグレード

そして、初めのイメージを設定する部分ですが、次のようなエラーが出ました

Sets a drawable as the content of this ImageView. Allows the use of vector drawable when running on older versions of the platform.

これは、Android Studioをアップデートしてください。というものでした。。。

こちらのサイトを参考にAndroid Studioは下のようにConfigure -> Check for Updateを選択します。

しかし、選択肢が「Download」しかなかったので、結局新しいものをダウンロード、インストールすることになりました。
最終的に置き換えるという形で、アップグレードしました。

まだ、エラーが解消されません。。。

This view is not constrained. It only has designtime positions, so it will jump to (0,0) at runtime unless you add the constraints

ここのサイトを参考にすると設定を追加すると治るということなので、次のようにプロパティを追加しました。

    <ImageView
        android:id="@+id/imageView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:srcCompat="@drawable/ic_add_mokuhyo"
        tools:layout_editor_absoluteX="50dp"
        tools:layout_editor_absoluteY="222dp"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:ignore="VectorDrawableCompat" />

追加したのは、次の部分です。

        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"

そして、英語、日本語と多言語化した場合は、下の3つのファイルに文字列を追加する必要がありました。

  • strings.xml(default)
  • strings.xml(ja)
  • strings.xml(en)

イメージのレイアウト

結構手こずりました。下のサイトを参考に学習しました。

  1. Image Asset Studioを使用する

色々と試したけど結局実行するデバイスを>色々と試したけど結局実行するデバイスを 新しくして試すことにしました。。。

どうやらしているする属性が違うようでした。こちらのサイトでありました。

 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
     <ImageView
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:src="@drawable/my_image"
         android:contentDescription="@string/my_image_description"
         />
 </LinearLayout>
 android:src="@drawable/my_image"

この部分が自動生成したものと値が違う。。。

そして、レイアウトの設定も問題がありそうなので、本家のサイトを参考にレイアウトも学習します。

何かしら触っていると、わかってくるような感じで説明がうまくできないのですが、 各値を設定してやると、見た目も変更されるのでそれで、自分の思った通りに修正するのが、早いと思います。

画像が表示されいない問題

これの原因がわかりました。SDKのバージョン別にactivity_main.xmlが存在していました。

これが原因で、一向に画像が表示されなかった。。。というわけでした。。。

最終的に作成したactivity_main.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">

    <TableLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TableRow
            android:layout_width="178dp"
            android:layout_height="192dp">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical">

                <ImageView
                    android:id="@+id/imageView3"
                    android:layout_width="80dp"
                    android:layout_height="80dp"
                    android:layout_marginStart="40dp"
                    android:layout_marginTop="10dp"
                    android:contentDescription="目標追加・一覧"
                    android:src="@drawable/ic_add_mokuhyo"
                    android:visibility="visible"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toTopOf="parent"
                    tools:srcCompat="@drawable/ic_add_mokuhyo" />

                <TextView
                    android:id="@+id/textAddMokuhyo"
                    android:layout_width="180dp"
                    android:layout_height="wrap_content"
                    android:layout_marginStart="10dp"
                    android:layout_marginTop="10dp"
                    android:autoSizeMaxTextSize="40dp"
                    android:autoSizeMinTextSize="18dp"
                    android:text="目標追加・一覧"
                    android:textSize="20dp"
                    android:visibility="visible"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toBottomOf="@id/imageView3" />
            </LinearLayout>

        </TableRow>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent" >

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical"></LinearLayout>
        </TableRow>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent" >

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical"></LinearLayout>
        </TableRow>

        <TableRow
            android:layout_width="match_parent"
            android:layout_height="match_parent" >

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:orientation="vertical"></LinearLayout>
        </TableRow>

    </TableLayout>

</androidx.constraintlayout.widget.ConstraintLayout>

LinerLayoutを学ぶ

よく使用されるであろうレイアウトの1つとして「LinerLayout」があります。ドキュメントにも載っているので基本的なレイアウトなのであろうと思いこれを学ぶことにしました。

LinearLayout は、すべての子を垂直または水平の一方向に揃えるビューグループです。android\:orientation 属性でレイアウトの方向を指定できます。

とりあえずは、コンポーネント(ボタンなどの部品)を並べてみます。そして、プロパティ(android\:XXXX)の値を変えてどのような配置になるかみてみたいと思います。

ここで、着目するプロパティを以下に示します。

プロパティ名 内容 
android\:orientation レイアウトの方向を指定
android\:layout_weight 画面上で占めるスペースという観点で「重要度」を表す値をビューに指定します。この weight 値が大きいほど、親ビューの残りのスペースを埋めるように拡大されます。子ビューに weight 値を指定することで、ビューグループの残りのスペースを、宣言された weight の割合に応じて割り当てることができます。デフォルトの weight 値は 0 です。
android\:layout_height
android
:layout_width
android\:layout_weight
それぞれの値を0dp、0dp、1に設定することで均等配分することができます。

ちょっと試してみましたが、他のプリパティと組み合わせる必要があるので、色々やってみないと理解できません。

次は、合わせて出てきた、TextViewに関してもプロパティを見てみます。

感想

  1. レイアウトの使い方、センタリングなど、やり方を調べると色々出てくるので手が止まることは少なくなりそうだ。
  2. レイアウトマネージャー(動画にある画面)での操作はわかりやすいが、プロパティの場所を探すのが大変だった。

でわでわ。。。

Android App 作成 ~アプリの基礎を学ぶ~

Androidアプリの基礎

下のページにあるチュートリアルを行っていきます。
参考サイト:Android Developperのサイトです。

そして、Androidアプリを作成するうえで理解しておきたいのが、下のようなライフサイクルと呼ばれるものです。
LifeCycle

具体的には、「アクティビティのライフサイクル」ということです。

「初めてのアプリを作成する」という項目は飛ばします。以前やったので。。。

概要をつかむ

Androidアプリを作成するための材料(コンポーネント)として以下のものがあります。

  • アクティビティ
  • サービス
  • ブロードキャスト レシーバ
  • コンテンツ プロバイダ

つまりは、上のような「グループに分けられたクラスがありますよ」ということです。

これらのクラスがそれぞれ、次のように説明されています。

アクティビティ
アクティビティは、ユーザーとやり取りするためのエントリ ポイントです。これは、1 つのユーザー インターフェースを持つ 1 つの画面で表されます。たとえば、メールアプリには、新着メールの一覧を表示するアクティビティ、メールを作成するアクティビティ、そしてメールを閲覧するアクティビティがあります。メールアプリでは、これらの複数のアクティビティが一体となって 1 つのユーザー エクスペリエンスを形成しますが、それぞれのアクティビティは他のものから独立しています。したがって、これらのアクティビティのいずれかを、別のアプリから開始することができます(メールアプリが許可している場合)。たとえば、カメラアプリからメールアプリの新規メールを作成するアクティビティを開始できます。そのようにして、ユーザーが写真をメールで共有できるようにします。アクティビティは、システムとアプリ間における次の重要なインタラクションを行えるようにします。
アクティビティをホストしているプロセスを継続的に実行するために、ユーザーの現在の操作内容(画面の表示)を追跡。
以前に使用されたプロセス(停止されたアクティビティ)のうち、ユーザーが再度アクセスする可能性があるものを検知し、それらの優先順位を上げてプロセスを維持。
アプリがプロセスを強制終了した場合に、ユーザーが以前の状態を復元したアクティビティに戻れるように支援。
アプリ間でのユーザーフローをアプリが実装する手段と、システムがそれらのフローを連携させるための手段を提供(ここでは最も一般的な例を説明します)。
アクティビティは Activity クラスのサブクラスとして実装します。Activity クラスの詳細については、デベロッパー ガイドのアクティビティをご覧ください。

サービス
サービスは、さまざまな理由によりアプリをバックグラウンドで実行し続けるための汎用エントリ ポイントです。長期間の操作やリモート プロセスを処理するためにバックグラウンドで実行されるコンポーネントです。サービスにはユーザー インターフェースがありません。たとえば、サービスはユーザーが別のアプリを使用している間にバックグラウンドで音楽を再生したり、ユーザーが別のアクティビティを操作している間にそれを妨げることなくネットワークからデータを取得したりします。アクティビティなどの他のコンポーネントが、サービスを開始して実行したり、サービスとやり取りするためにサービスにバインドしたりすることができます。アプリの管理方法についてサービスがシステムに通知するセマンティクスは 2 つあり、それぞれ異なる意味を持っています。開始されたサービスが、作業が終了するまで自身の実行を維持するようシステムに指示します。これにより、ユーザーがアプリから離れても、バックグラウンドでデータを同期したり、音楽を再生したりできます。バックグラウンドでのデータの同期や音楽の再生は、開始されたサービスとしてはそれぞれ異なるタイプと認識され、システムがそれらのサービスに対して行う処理もそれぞれ異なります。
音楽の再生はユーザーが直接意識しているものなので、アプリはフォアグラウンドになりたいことをユーザーに通知で知らせることで、システムにそれを指示します。この場合、システムはそのサービス プロセスの実行を維持するよう最善を尽くします。このプロセスが終了するとユーザーが不満を覚えるからです。
通常のバックグラウンド サービスは、その実行をユーザーが直接意識していません。したがって、システムはより柔軟にそのプロセスを管理できます。ユーザーにとってより緊急な課題を処理するために RAM が必要となった場合には、プロセスを強制終了し、後から再開できます。
他のアプリ(またはシステム)がサービスを利用することを明示しているなら、バインドされたサービスが実行されます。これは基本的に、別のプロセスに API を提供するサービスです。これにより、これらのプロセス間に依存関係があることをシステムは認識します。プロセス A がプロセス B のサービスにバインドされている場合に、システムはプロセス B とそのサービスの実行を A のために維持する必要があることを認識します。さらに、プロセス A がユーザーにとって優先度が高い場合は、プロセス B もユーザーにとって重要であるとみなされます。サービスは良くも悪くもその柔軟性から、さまざまな上位レベルのシステム コンセプトにおいて、非常に有用な構成要素となってきました。ライブ壁紙、通知リスナー、スクリーン セーバー、入力方法、ユーザー補助機能サービス、その他多くの主要なシステム機能はすべて、アプリが実行するサービスとしてビルドされ、その実行時にシステムによりバインドされます。
サービスは Service のサブクラスとして実装されます。Service クラスの詳細については、デベロッパー ガイドのサービスをご覧ください。

ブロードキャスト レシーバ
ブロードキャスト レシーバは、通常のユーザーフローを外れて、システムがアプリにイベントを配信できるようにするコンポーネントです。これにより、アプリはシステム全体のブロードキャスト アナウンスに応答できます。ブロードキャスト レシーバは明確に定義されたアプリへのエントリであるため、システムは実行中でないアプリに対してもブロードキャストを配信できます。したがってアプリが、たとえば、近づいているイベントについてユーザーに知らせる通知を投稿するためのアラームをスケジューリングすることができます。アプリの BroadcastReceiver にアラームを配信することにより、そのアラームが作動するまでアプリの実行を維持する必要がなくなります。多くのブロードキャストの発信源はシステムです — たとえば、画面がオフになったことを通知するブロードキャスト、電池が残り少ないことを通知するブロードキャスト、画像がキャプチャされたことを通知するブロードキャストなどです。アプリから発信されるブロードキャストもあります — たとえば、端末にデータがダウンロードされ使用できることを他のアプリに知らせる場合などです。ブロードキャスト レシーバがユーザー インターフェースを表示することはありませんが、ステータスバー通知を作成して、ブロードキャスト イベントの発生時にユーザーにアラートできます。一般的には、ブロードキャスト レシーバは他のコンポーネントへの単なるゲートウェイであり、最小限の作業を行うことが前提となっています。たとえば、JobScheduler を使用してイベントに基づいた何らかの作業を実行する JobService をスケジュール設定する場合などです。
ブロードキャスト レシーバは BroadcastReceiver のサブクラスとして実装され、各ブロードキャストは Intent オブジェクトとして配信されます。詳細については、BroadcastReceiver クラスをご覧ください。

コンテンツプロバイダ
コンテンツ プロバイダは、ファイル システム、SQLite データベース、ウェブ、またはアプリからアクセス可能な他の永続的なストレージの場所に保存できるアプリデータの共有されている部分を管理します。コンテンツ プロバイダを介して、他のアプリがデータをクエリしたり、修正したりできます(コンテンツ プロバイダが許可している場合)。たとえば、Android システムはユーザーの連絡先情報を管理するコンテンツ プロバイダを提供しています。したがって、適切なパーミッションさえあれば、アプリからコンテンツ プロバイダに ContactsContract.Data などをクエリして、特定の人物に関する情報を読み取ったり書き込んだりできます。このような一般的なケースのために多くの API やサポートが組み込まれているため、コンテンツ プロバイダをデータベースの抽象化として考えたくなるかもしれません。しかし、システム設計の観点では、コンテンツ プロバイダには別の目的があります。システムから見て、コンテンツ プロバイダは、URI スキームにより識別される名前付きデータ項目を公開するための、アプリへのエントリ ポイントです。したがって、アプリは自身が保有するデータを URI 名前空間にどのようにマッピングし、その URI を他のエンティティに渡してデータにアクセスできるようにするかを決めることができます。アプリの管理に関して、システムでは以下が実行できます。
URI の割り当てはアプリが実行中であるかどうかには影響されないため、その URI を所有しているアプリが終了していても URI は維持されます。システムが確認する必要があるのは、該当 URI からアプリのデータを取得する必要があるときに、所有しているアプリが実行中であることだけです。
URI は重要で詳細なセキュリティ モデルも提供します。たとえば、アプリは画像の URI をクリップボードに配置することができますが、他のアプリが自由にアクセスできないようにコンテンツ プロバイダをロックしたままにできます。別のアプリがクリップボードのその URI にアクセスしようとした場合には、システムが一時的な URI パーミッションを付与して、その URI にあるデータのみにアクセスすることを許可します。その他のデータにはアクセスできません。
コンテンツ プロバイダは、アプリだけに公開されている、他で共有されていないデータを閲覧したり書き込んだりする場合にも役立ちます。
コンテンツ プロバイダは ContentProvider のサブクラスとして実装され、他のアプリがトランザクションを実行できるようにする API の標準セットを実装する必要があります。詳細については、デベロッパー ガイドのコンテンツ プロバイダをご覧ください。

これらを使って作る

上記のコンポーネント(部品)をしようしてAndroidアプリを作成します。この基礎になる部分をちゃんと理解すればほぼ極めたといってよいと思います。※勝手な想像です。なぜなら自分もこれから学習するので(笑)

なので、この基礎部分をしっかり学習したいと思います。

「概要をつかむ」のまとめ

Androidアプリを作るための基本的な材料(クラス)として次の4つがある。

  • アクティビティ
  • サービス
  • ブロードキャスト レシーバ
  • コンテンツ プロバイダ

そして、これらの材料を組み合わせてAndroidアプリを作成するということを理解。

次は、順番に「アクティビティ」を理解します。

アクティビティについて

アクティビティについて学習します。まずは、概要にある内容を抜粋を読みます。

main() メソッドで起動するアプリをプログラミングする際の枠組みとは異なり、Android システムでは、ライフサイクルのそれぞれの段階に対応するコールバック メソッドを呼び出すことにより、Activity インスタンス内のコードが開始されます。

つまるところは、以下の文言がキーポイントになります。

一般に、1 つのアクティビティがアプリ内の 1 つの画面を実装します。

例として、次のような説明があります。

アプリのアクティビティの 1 つが「設定」画面を実装し、他のアクティビティが「写真を選択」画面を実装します。

画面=アクティビティであり、このアクティビティの操作により様々な操作(処理)を実装するというわけです。

マニフェストで画面の設定

アプリでアクティビティを使用できるようにするには、マニフェストでアクティビティとその属性を宣言する必要があります。

    <manifest ... >
      <application ... >
          <activity android:name=".ExampleActivity" />
          ...
      </application ... >
      ...
    </manifest >

必須の属性は、アクティビティのクラス名を指定する android\:name だけです。

簡単ですね。つまりわかりやすい=使いやすいということだと思います。
続けて、そのほかの設定に関しては、次の部分にあります。

ラベル、アイコン、UI テーマなどのアクティビティの特性を定義する属性を追加することもできます。

こちらのページにアクティビティの詳細がありました。

構文は以下のようになっています。

<activity android:allowEmbedded=["true" | "false"]
          android:allowTaskReparenting=["true" | "false"]
          android:alwaysRetainTaskState=["true" | "false"]
          android:autoRemoveFromRecents=["true" | "false"]
          android:banner="drawable resource"
          android:clearTaskOnLaunch=["true" | "false"]
          android:colorMode=[ "hdr" | "wideColorGamut"]
          android:configChanges=["mcc", "mnc", "locale",
                                 "touchscreen", "keyboard", "keyboardHidden",
                                 "navigation", "screenLayout", "fontScale",
                                 "uiMode", "orientation", "density",
                                 "screenSize", "smallestScreenSize"]
          android:directBootAware=["true" | "false"]
          android:documentLaunchMode=["intoExisting" | "always" |
                                  "none" | "never"]
          android:enabled=["true" | "false"]
          android:excludeFromRecents=["true" | "false"]
          android:exported=["true" | "false"]
          android:finishOnTaskLaunch=["true" | "false"]
          android:hardwareAccelerated=["true" | "false"]
          android:icon="drawable resource"
          android:immersive=["true" | "false"]
          android:label="string resource"
          android:launchMode=["standard" | "singleTop" |
                              "singleTask" | "singleInstance"]
          android:lockTaskMode=["normal" | "never" |
                              "if_whitelisted" | "always"]
          android:maxRecents="integer"
          android:maxAspectRatio="float"
          android:multiprocess=["true" | "false"]
          android:name="string"
          android:noHistory=["true" | "false"]  
          android:parentActivityName="string" 
          android:persistableMode=["persistRootOnly" | 
                                   "persistAcrossReboots" | "persistNever"]
          android:permission="string"
          android:process="string"
          android:relinquishTaskIdentity=["true" | "false"]
          android:resizeableActivity=["true" | "false"]
          android:screenOrientation=["unspecified" | "behind" |
                                     "landscape" | "portrait" |
                                     "reverseLandscape" | "reversePortrait" |
                                     "sensorLandscape" | "sensorPortrait" |
                                     "userLandscape" | "userPortrait" |
                                     "sensor" | "fullSensor" | "nosensor" |
                                     "user" | "fullUser" | "locked"]
          android:showForAllUsers=["true" | "false"]
          android:stateNotNeeded=["true" | "false"]
          android:supportsPictureInPicture=["true" | "false"]
          android:taskAffinity="string"
          android:theme="resource or theme"
          android:uiOptions=["none" | "splitActionBarWhenNarrow"]
          android:windowSoftInputMode=["stateUnspecified",
                                       "stateUnchanged", "stateHidden",
                                       "stateAlwaysHidden", "stateVisible",
                                       "stateAlwaysVisible", "adjustUnspecified",
                                       "adjustResize", "adjustPan"] >
    . . .
</activity>
属性 説明
android\:allowEmbedded アクティビティを別のアクティビティの子として埋め込み、起動できることを示します。これは特に、別のアクティビティが所有するディスプレイなどのコンテナに子が存在する場合です。たとえば、Wear のカスタム通知に使用されるアクティビティは、Wear が別のプロセスに存在するコンテキスト ストリーム内でこのアクティビティを表示できるようにするため、この宣言が必要です。この属性のデフォルト値は false です。
android\:allowTaskReparenting タスクが次に前面に移動したとき、アクティビティを開始したタスクからアフィニティを持つタスクにアクティビティを移動できるかどうか。移動できる場合は "true"、アクティビティを開始したタスクに留まる必要がある場合は "false" を指定します。この属性が設定されていない場合、対応する 要素の allowTaskReparenting 属性によって設定された値がアクティビティに適用されます。デフォルト値は "false" です。通常、アクティビティを開始すると、アクティビティを開始したタスクにアクティビティが関連付けられ、アクティビティの生存期間中はそこに留まります。この属性を使用すると、現在のタスクが表示されなくなったときに、アフィニティを持つタスクをアクティビティの親として再割り当てすることができます。一般に、アプリに関連付けられたメインタスクにアプリのアクティビティを移動する場合に使用します。たとえば、メール メッセージにウェブページへのリンクが含まれている場合、リンクをクリックすると、そのウェブページを表示できるアクティビティが起動します。そのアクティビティはブラウザアプリで定義されていますが、メールタスクの一部として起動されます。ブラウザタスクをアクティビティの親として再割り当てすると、ブラウザが次に前面に移動したときにアクティビティが表示され、メールタスクが再び前面に移動したときにはそのアクティビティが表示されなくなります。アクティビティのアフィニティは、taskAffinity 属性で定義されます。タスクのアフィニティは、タスクのルート アクティビティのアフィニティを読み取って決定されます。したがって、定義上は、ルート アクティビティは常に、同じアフィニティを持つタスク内に存在します。起動モードに "singleTask" または "singleInstance" が設定されたアクティビティはタスクのルートにのみ存在できるため、親の再割り当ては "standard" モードと "singleTop" モードに限定されます。(launchMode 属性もご覧ください。)
android\:alwaysRetainTaskState アクティビティが割り当てられているタスクの状態を常にシステムで維持するかどうか。維持する場合は "true"、特定の状況でシステムがタスクを初期状態にリセットできるようにするには "false" を指定します。デフォルト値は "false" です。この属性が重要なのは、タスクのルート アクティビティのみです。その他すべてのアクティビティについては無視されます。通常は、ユーザーがホーム画面からタスクを選択し直したような状況で、システムはタスクをクリアします(ルート アクティビティ上のスタックからすべてのアクティビティを削除します)。一般に、ユーザーが特定の時間(たとえば 30 分間)、タスクにアクセスしなかった場合にこの処理が行われます。ただし、この属性が "true" の場合、ユーザーがどのような方法でタスクにアクセスしても、常に前回のタスクの状態に戻ります。これは、たとえば、ウェブブラウザのようなアプリで便利です。これにより、ユーザーは多くの状態(開いている複数のタブなど)をそのまま維持することができます。
android\:autoRemoveFromRecents この属性を指定したアクティビティによって開始されたタスクについて、タスク内の最後のアクティビティが完了するまでオーバービュー画面に表示し続けるかどうか。true の場合、タスクが自動的にオーバービュー画面から削除されます。これは、呼び出し元による FLAG_ACTIVITY_RETAIN_IN_RECENTS の使用よりも優先されます。"true" または "false" のブール値を指定する必要があります。
android\:banner 関連するアイテムに拡張されたグラフィック バナーを提供するドローアブル リソース。 タグで使用すると、特定のアクティビティにデフォルトのバナーを配置します。 タグで使用すると、アプリのすべてのアクティビティにバナーを配置します。Android TV のホーム画面では、システムがこのバナーを使用してアプリを表示します。バナーはホーム画面のみに表示されるため、CATEGORY_LEANBACK_LAUNCHER インテントを処理するアクティビティを持つアプリでのみ指定する必要があります。この属性は、画像を含むドローアブル リソースへの参照(たとえば "@drawable/banner")として設定する必要があります。デフォルトのバナーはありません。詳細については、TV アプリのビルドを開始するページのホーム スクリーンにバナーを配置するをご覧ください
android\:clearTaskOnLaunch タスクがホーム画面から再起動されたときに、ルート アクティビティを除くすべてのアクティビティをタスクから削除するかどうか。常にタスクのルート アクティビティ以外をクリアする場合は "true"、そうでない場合は "false" を指定します。デフォルト値は "false" です。この属性は、新しいタスクを開始するアクティビティ(ルート アクティビティ)にのみ影響します。タスクのその他すべてのアクティビティでは、この属性は無視されます。値が "true" の場合は、タスクの直前の操作や、タスクから離れるときに [戻る] ボタンまたは [ホーム] ボタンを押したかどうかにかかわらず、ユーザーが再びタスクを開始するたびにルート アクティビティから開始します。値が "false" の場合、状況によってはタスクのアクティビティがクリアされることがありますが、常にクリアされるわけではありません(alwaysRetainTaskState 属性をご覧ください)。たとえば、ホーム画面からアクティビティ P を起動し、そこからアクティビティ Q に移ったとします。ユーザーが [ホーム] を押して、再びアクティビティ P に戻りました。通常、ユーザーにはアクティビティ Q が表示されます。前回、P のタスクで Q を実行していたからです。ただし、P でこのフラグが "true" に設定されていると、P をベースにするすべてのアクティビティ(この場合は Q)は、ユーザーが [ホーム] を押したときに削除され、タスクはバックグラウンドに移動します。そのため、ユーザーがタスクに戻ると、P のみが表示されます。この属性と allowTaskReparenting の両方が "true" の場合、親の再割り当てが可能なアクティビティはすべて、アフィニティを共有するタスクに移動され、残りのアクティビティは上記のとおり削除されます。
android\:colorMode 対応端末でアクティビティを広色域モードで表示するようにリクエストします。広色域モードでは、SRGB よりも広い色域でウィンドウをレンダリングして、より鮮やかな色を表示できます。端末で広色域レンダリングがサポートされていない場合、この属性を指定しても効果はありません。ワイドカラー モードでのレンダリングの詳細については、ワイドカラー コンテンツによるグラフィックの拡張をご覧ください。
android\:configChanges アクティビティで処理する設定変更のリストを指定します。実行時に設定の変更が発生すると、デフォルトではアクティビティはシャットダウンおよび再起動されますが、この属性で設定を宣言しておくと、アクティビティの再起動を防止できます。代わりに、アクティビティは実行中のままになり、アクティビティの onConfigurationChanged() メソッドが呼び出されます。

ほかにもありますが、詳細は本家のページを参照ください。

このマニフェストで、各アクティビティの設定を行います。

次回は、画面(アクティビティ)から画面(アクティビティ)を呼び出す方法を学習します。>次回は、画面(アクティビティ)から画面(アクティビティ)を呼び出す方法を学習します。

アクティビティの作成

AndroidStudioでプロジェクトを作成すると、「MainActivity」クラスが出来上がっています。
このクラスが上記のアクティビティになります。

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

このアクティビティ(画面)を作成しているのは、
setContentView(R.layout.activity_main);の部分になります。
R.layout.activity_mainの部分は、下の図のように、「activity_main.xml」に定義(描かれて)されています。

「activity_main.xml」を開くと右上のほうにのようなボタンがあるので、「Design」を選択すると画面のイメージが表示されます。

ここで、テキスト「Hello World」が表示されています。この部品が「TextView」という部品です。
この部品を移動してタイトルとして使用しようと思っていますが、その前に。。。

パッケージの修正

デフォルトで作成されたパッケージは「com.example.プロジェクト名」になっていると思います。
これを自作のパッケージ名に修正したいと思いますが、ただ単に修正するとエラーになります。

これは、AndroidManifest.xmlの修正も必要なためです。
使用するパッケージ名を上のXMLに記述します。今回作成するパッケージ名は「jp.zenryoku.mokuhyotasseiap」としてます。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="jp.zenryoku.mokuhyotasseiap">

これで、エラーが解消され、Javaファイルも下のようにエラーが消えました。

多言語対応

作成するアプリは、多言語対応で作成したいと考えております。なので、こちらのページを参考に、多言語化を行います。

まとめると、下の図のように各言語に対応するXMLファイルを作成するというところです。

resを右クリックして、フォルダ名「values」の後ろに対応する言語を付けます。

  • 日本語(values-ja)
  • 英語(values-en)

そして、それぞれのstring.xmlに各言語に対応する文字列を記述します。

XMLの参照方法

多言語の文字列を設定することができたら、次は画面のコンポーネント(部品)にその値を設定します。
必要な処理ととしては、次のものになります。

  1. コンポーネントの取得
  2. 文字列の取得
  3. 値の設定
// コンポーネントの取得
TextView titleView = findViewById(R.id.appTitle);
// 値の設定
titleView.setText(R.string.app_name);

上のような実装で行けそうです。まだ起動確認していません。。。

バーチャルデバイスのインストール

実機がない場合は仮想デバイス(バーチャルデバイス)をインストールする必要があります。
動かしたときのイメージを見るためです。
これは、画面操作で簡単に行けます。

しかしエラーが!

Execution failed for task ':app:compressDebugAssets'.

上記のようなエラーが出ました。
こちらのサイトを参考にすると、Gradleのバージョンを下げてやればいけるというところで。。。

それぞれのバージョンを以下のように設定して再実行しました。
Android Gradle Plugin: 4.2.1
Gradle: 6.7.1

次のエラー

Caused by: org.gradle.internal.metaobject.AbstractDynamicObject$CustomMessageMissingMethodException: Could not find method dependencyResolutionManagement() for arguments

これもGradleのバージョンを次のように変えてやればよい感じでした。
Android Gradle Plugin: 7.0
Gradle: 7.0

しかし、使用しているPCの容量不足のため、AndroidStudioが落ちました。。。
Android開発は、十分にHDの要領があるPCを使用しないと駄目なようです。。。

でわでわ。。。

Android Studio App 作成1 〜プロジェクト作成〜

Android Studioの使い

Androidアプリを作成したいと思う人は多いと思います。自分もその一人です。
しかし、どこから着手してよいかわからないということが往々にしてありますので、まとめてみました。

  1. 開発ツールをインストール(Android Studioのインストール)

  2. プロジェクトの作成: Android Studioに作成するアプリのフォルダを作成する

  3. 仕様の作成: どんな操作で、どんな機能を持っているアプリなのか明確にする、資料を作る

  4. 画面イメージの作成(モック): 作成するアプリで使用する画面を機能の作成をしない状態で作成する

  5. 機能のテストケース作成: 各画面の操作を行ったときにどのような動きをするのが正しいか、リストアップする
    ※「〇〇〇と操作したときはXXXのように表示」のように「このように動く」ということをリストアップする

  6. 機能実装用テストケース作成: 5で作成したテストケースを確認するためのプログラムを作成します。これを作成しておくと、部分的に修正したいときに、ほかに影響がないことを確認するということが、自動で出来るようになります。

  7. 各種部品の実装とテスト: 6で作成したテストケース(プログラム)が全てOKになるようにプログラムを作成します。テストケースを網羅するので、実装とテストが一緒にできます。

プロジェクトの作成

Android Studioを使用して、Androidアプリを作成しようと思います。

上記と重複してしまいますが、全体的に下のような手順で作成していきます。

  1. プロジェクトの作成
  2. 仕様の作成
  3. 画面イメージの作成(モック)
  4. 機能のテストケース作成
  5. 機能実装用テストケース作成
  6. 各種部品の実装とテスト

上記のような形で実装していきます。

(余談)目標達成AP~タスク管理~

Gitに作成した仕様が本来のものですが、これを作成するのにはかなりの時間がかかるので、分解して実装していきます。
最終的には、人工知能処理も必要になるので、この部分は最後の方に回したいと思っています。

なので、Version1.0として、目標達成AP〜タスク管理〜バージョンとしてアプリの作成に着手しようと言う考えです。

ちなみに、この記事を書いてから大分時間が経っていますが、ようやく着手できるところまで来ました。

画面の作成に着手

初めに、Android Studioを起動すると下のような画面が見れます。

次へ(next)を押下すると、インストールタイプの選択がありますが、これはStandard(標準)でよいと思います。
※使い慣れていないんで。。。

そして画面のタイプを選択します。白系か黒系か。。。自分は白系を選択しました。

最後は、そのままFinish(完了)です。

すると、必要なライブラリなどをインストールし始めます。

結構長いです。。。ネットワークスピードが遅い環境なもので。。。

Android Stdioでプロジェクトの作成

Android Stdioを起動します。

そして、create new projectを選択します。

Emptyプロジェクトを選択します。


最後に、プロジェクト名としようする言語などを入力してFinishをクリックします。

そして、下のようにワークスペースが開きます。

アプリケーションを動かす

とりあえずは、動かしてみるのも良いでしょう。自動生成されたアプリを起動して動きを見て、どのような構造になっているかプログラムを眺めてみるのも1つです。こちらに詳細を記載しました。

今後

自分は、これからアプリケーションの実装に着手したいと考えております、が、Android Studioの使い方など学習することが多く時間がかかりそうです。。。

やはり、設計レベルである程度、形を作っておくと実装も楽になります。

そして、AndroidはGoogle製のOSなので当然TensorFlow(人工知能ライブラリ)などを併用することが可能です。ほかにも、いろいろなデバイスにインストールすることができるので作成したアプリをいろんなデバイスで実行することが可能になります。

Activityが表示できない

下の画像のように、文字が赤くなっている部分があるときは、エラーになっている状態です。

これを解決するのに、足りないものがあります。これらを追加するのに「Gradle sync failed:」というエラーメッセージがあります。これを解決するのにこちらのサイトを参考にしました。

エラーが出たとき

下のようなエラーが出ました。

Caused by: org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:

File → Project Structure(プロジェクトの構造)からProject(プロジェクト)を開き
解決できるかと思って下のようにAndroidGradle PluginとGradleのバージョンをそそろえてみたがダメでした。
しかし、Gradleのバージョン < AndroidGradle Pluginの関係を保ち、変更してやるとGradleがちゃんと走りました。
結局は、AndroidGradle Pluginのバージョンをそのままにして、Gradleのバージョンを下げていったらうまくいきました。。。が必要なパッケージをダウンロードしただけでした。。。

こちらのサイトを参考にするとJDKのバージョンとGradleのバージョンがあっていないということで、下のように修正しました。

またエラーが!

下のようなエラーが出ました。

The cache entry for initialization script 'C:\Users\XXX\AppData\Local\Temp\sync.studio.tooling278.gradle' appears to be corrupted.

  • Try:
    Run with --scan to get full insights

これは、chacheする場所を新たに指定したらなおりました。

The cache entry for initialization script 'C:\Users\XXX\AppData\Local\Temp\sync.studio.tooling472.gradle' appears to be corrupted.

これは、AppDataの場所を変更していたので、出たエラーと思われます。
こちらのサイトを参考に修正しました。
Files -> Settingsから

ほかにも

The cache entry for initialization script 'C:\Users\XXXX\AppData\Local\Temp\sync.studio.tooling336.gradle' appears to be corrupted.

というようなエラーがでました。

とりあえず不足していたのが、環境変数の設定でした。こちらのページに詳細があります。

これは、普通にWindowsの設定を開き環境変数を設定してやればOKです。
ただし、再起動が必要らしいです。

そして、gradleのディレクトリがCドライブになっていたのでそれをDドライブに変更します。
※筆者は、DドライブにAndroidStudioをインストールしました。。。

Gradle

File > Settings > Build Execution, Deployment > Gradle > Service directory path

の順でクリックります。しかし、Gradleがあったのは別の場所で、gradleホームをすでにDドライブに設定していました。

仕方ないので、コマンドでビルドを実行することにしました。画面の下のほうにある「Terminal」をクリックすると、コマンドラインの画面が見れますので、ここに以下のコマンドを入力します。

gradlew --info build

エラーログを見ると。。。

Initialized native services in: C:\Users\XXX.gradle\native

のようなメッセージがあり、つまりはワーキングディレクトリがCドライブになっているのが原因と判断しました。
だがしかし、結局解決ならず。。。

ここのページを参考にするとGradleキャッシュをクリアするとよいとあったので、キャッシュフォルダを削除して、今日はおしまいにしようと思います。。。
[ー2021-10-18]

Cドライブのキャッシュを削除してみたものの、エラーログに変化なし。。。

やはり、WindowsでAndroidStudioを使用するならば、デフォルトの場所にインストールするのが良いという判断になりました。

もともとインストールしていたAndroid Studioはアンインストールして、再度やり直すことにしました。
このパソコンは、Android開発用の端末となりました。※CドライブのHD容量が30GBしかないのです。。。

再インストール後

キャッシュが残っていました。
下のようなエラーが出ています。

Minimum supported Gradle version is 7.0.2. Current version is 6.9. If using the gradle wrapper, try editing the distributionUrl in

初めに、プロジェクトのディレクトリにあるbuid.gradleに追記した。

baseDir=D:/workspace

という文字を削除しました。これで、もとのCドライブを参照するようになります。

エラーメッセージ解決

こちらのGradleのサイトでエラーメッセージを検索すると解決策が見つけられそうです。※英語ですが。。。

結局、GradleとAndroid Gradle Pluginのバージョンを合わせて下げてやりました。
Android Gradle Plugin = 4.2.2
Gradle Version = 6.8
上記の設定で何とかビルド完了できました。

でわでわ。。。

Android Studio Tesseractの設定とエラー compileSdkVersion is not specified.

調査するときのポイント

実際に自分が調べていくときに「使えるな!」と思った方法です。

  1. エラーメッセージをコピって検索する
  2. エラーメッセージを翻訳して日本語にする

色々なサイト、ブログ記事を追いかけるように、みて、試して問題解決に向けて調べていきます。

しかし、途中で「根本的な仕組みを理解したほうが早い」場合もあるので、頭の片隅にそれを置いておくと良いかもしれません。

compileSdkVersion is not specified.

上記のようなエラーメッセージが出て、ビルドができない状態になりました。

調べてみるとこちらのページに下のような記述がありました。

プロジェクト下の build.gradle に以下を記載していますか?

allprojects {
repositories {
mavenLocal()
jcenter()
maven {
url "$rootDir/../node_modules/react-native/android"
}
google()
}
}

これは、プロジェクトのbuild.gradleを修正すると言うことを意味しているので下の図の「AndroidOpenCV」と書かれているものを修正しました。

最終的に下のようになりました。

allprojects {
    repositories {
        google()
        jcenter()
        maven {
            url 'https://maven.google.com/'
            name 'Google'
        }
    }
}

Could not find method maven() for arguments

次に出力されたエラーメッセージは上のものです。

mavenのホームディレクトリ(インストールした場所)を指定しなくてはいけないけど、全く違う場所を指定しているので出力されたエラーです。

Mavenプラグインを使用

参考サイトはこちらのAndroidドキュメントです。

しかし、これは必要ないと判断しました。

maven {
    url 'https://maven.google.com/'
    name 'Google'
}

そして、初めのエラー対応を考えます。

ふと気がつく

「compileSdkVersion is not specified.」このメッセージは日本語にすると「compileSdkVersionが指定されていません。」になります。

ここを中心に調べていくとGradleのページに着きました。
しかし、有益な情報は見つからず。。。

プロジェクトの設定を見てみる

ヘッダーメニューからFile -> Project Structureを選択

Gradleのバージョンを6.5に設定しました。

Could not find com.jfrog.bintray.gradle:gradle-bintray-plugin:1.2.

次に上のエラーが出ました。
こちらのページには次のような追記をしてください。とあったのでそのようにしました。

buildscript {
  repositories {
    maven {
      url "https://plugins.gradle.org/m2/"
    }
  }
  dependencies {
    classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.5"
  }
}

apply plugin: "com.jfrog.bintray"

Could not find org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.4.32.

さらに次のエラーが出ました。

ERROR: Could not find org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.4.32.
Searched in the following locations:
  - https://dl.google.com/dl/android/maven2/org/jetbrains/kotlin/kotlin-stdlib-jdk8/1.4.32/kotlin-stdlib-jdk8-1.4.32.pom
If the artifact you are trying to retrieve can be found in the repository but without metadata in 'Maven POM' format, you need to adjust the 'metadataSources { ... }' of the repository declaration.
Required by:
    project : > com.android.tools.build:gradle:7.0.0-alpha14

下の部分に注目

adjust the 'metadataSources { ... }' of the repository declaration.

次のように、プロジェクトのbuild.gradleを修正

buildscript {
    repositories {
        google()
        jcenter()
    }
    ・
    ・
    ・

下のようなエラーが出たので、「Fix Gradle wrapper and re-import project」をクリック

ダウンロードが始まり、「Could not find 〜」と言うようなエラーが出ます、対象になる場所を削除・コメントアウトしました。
<プロジェクトのbuild.gradle>

//apply plugin: 'com.github.dcendents.android-maven'
//apply plugin: 'com.jfrog.bintray'

そして、次の部分もコメントアウトしました。プル下フォルダのbuild.gradleです。

tess/tess-two/build.gradle

//install {
//    repositories.mavenInstaller {
//        pom.project {
//            name = 'tess-two'
//
//            packaging = 'aar'
//            groupId = 'com.rmtheis'
//            artifactId = 'tess-two'
//
//            developers {
//                developer {
//                    id = 'rmtheis'
//                    name = 'Robert Theis'
//                    email = 'robert.m.theis@gmail.com'
//                }
//            }
//            licenses {
//                license {
//                    name = 'The Apache Software License, Version 2.0'
//                    url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
//                    distribution = 'repo'
//                }
//            }
//            scm {
//                url 'https://github.com/rmtheis/tess-two'
//            }
//        }
//    }
//}
//
//bintray {
//    user = properties.getProperty("bintray.user")
//    key = properties.getProperty("bintray.apikey")
//    configurations = ['archives']
//    pkg {
//        repo = 'maven'
//        name = 'tess-two'
//        userOrg = user
//        publish = true
//    }
//}

Gradle DSL method not found: 'implementation()'

次のエラーです。Android Studioに下のようなエラーがあったので、「Open Gradle wrapper file」をクリックします。

すると、gradle.propertiesファイルが開くので、新しいものを設定します。gradleの新しいバージョンです。

distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-rc-1-all.zip

ここまできたらNDKの設定

ヘッダーメニューのTools -> SDK Managerをクリックします。
そして、「SDK Tools」タブを選択します。

そして、[NDK (Side by side)] と [CMake] のチェックボックスをオン
参考ページの内容は以下の通りです。

  1. プロジェクトを開いて、[Tools] > [SDK Manager] をクリックします。
  2. [SDK Tools] タブをクリックします。
  3. [NDK (Side by side)] と [CMake] のチェックボックスをオンにします。

Unable to find method 'org.gradle.api.artifacts.result.ComponentSelectionReason.getDescription()

これは、再起動したら通常通りにビルドが走り、同じエラーが出ました。

そして、Tesseract

こちらのページにある手順を実行します。

export ANDROID_HOME=/path/to/your/android-sdk
git clone git://github.com/rmtheis/tess-two tess
cd tess
./gradlew assemble

まとめると、TesseractをGitからプルしてコンパイルするということです。

このコマンドを実行するのに手間取ったのが、「path/to/your」の部分です。あらかじめNDKのインストール先を理解している必要があります。
NDKのインストール先

android-sdkのインストール先/ndk/ビルド番号?/

実際に自分の場合は下のようにコマンドを叩きました。

~/Android/sdk/ndk/22.1.7171670/ndk-build

結構な時間がかかります。

コンパイル終了後

アプリケーションのbuild.gradleにGradleのデーモン(裏側で動くプロセス)を終了するためにAndroid Studioを再起動します。

あと、Android Studioのアップグレードも行いました。

次のエラー

2つあります。それは、下のような形で出力されたエラーですので、メッセージも複数あります。

This version of the Android Support plugin for IntelliJ IDEA (or Android Studio) cannot open this project, please retry with version 2020.3.1 or newer.
Please remove usages of `jcenter()` Maven repository from your build scripts and migrate your build to other Maven repositories.
This repository is deprecated and it will be shut down in the future.
See http://developer.android.com/r/tools/jcenter-end-of-service for more information.
Currently detected usages in: root project 'AndroidOpenCV', project ':app', project ':eyes-two', ...

下の方のエラーを先に対応しました。プロジェクトのbuild.gradleを修正、しかしこれは意味がありませんでした。

    repositories {
        google()
        //jcenter()
    }

エラーが変わりました。

tried to access method sun.security.util.ECUtil.getECParameters(Ljava/security/Provider;)Ljava/security/AlgorithmParameters; from class sun.security.ec.ECKeyPairGenerator

これには、gradle.propertiesに以下のものを追加することで解決できそうです。がダメでした。。。

org.gradle.java.home=JDKへのパス

次の方法を試します。参考にしたサイトはこちらです。

そしたら次のエラーになりました。

Could not get unknown property 'Os' for task

tess-twoのbuild.gradleの以下の行です

def ndkBuildExt = Os.isFamily(Os.FAMILY_WINDOWS) ? ".cmd" : ""

結局のところ

GUIでは原因がわからなくなってきたので、コマンド実行に切り替えることにしいました。

実行するコマンドは「./gradlew clean」です。

しかし。。。

解決には至りませんでした。。。

諦める

考え方を変えることにしました。もともとOpenCVを動かしていたプロジェクトにTesseractを追加する形での設定を行なっていましたが、諦めて、TesseractプロジェクトにOpenCVを追加する形に変更します

つまりは、追加した部分を削除します。そして、新たにTeserractプロジェクトを作成する方向でやり直すことにします。

ビルドを動くようにする

build.gradle(プロジェクト用)を修正して下のようにします。Tesseractを依存関係から外します。
さらに、buildバージョンも修正して4.1.3にします。

buildscript {
    repositories {
        google()
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:4.1.3'
//        classpath 'com.android.tools.build:gradle:7.0.0-alpha14'
//        classpath 'com.android.tools.build:gradle:1.1.2'

        classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.2'
        //classpath 'com.github.dcendents:android-maven-plugin:1.2'
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        google()
        maven {
            url 'https://maven.google.com/'
            name 'Google'
        }
    }
}

ext {
    // The following are only a few examples of the types of properties you can define.
    compileSdkVersion = 30
    // You can also create properties to specify versions for dependencies.
    // Having consistent versions between modules can avoid conflicts with behavior.
    supportLibVersion = "30.0.2"
}

ここまできて、依存関係が解決しないエラーが起きました。なのでclasspathを追加して、repositoryも追加しました。

buildscript {
    repositories {
        google()
        maven { url 'https://maven.aliyun.com/nexus/content/groups/public' }
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:4.1.3'
        classpath 'com.android.tools.build:aaptcompiler:4.1.3'
        classpath 'com.android.tools.lint:lint-gradle-api:27.1.3'
        classpath 'com.android.tools.build:gradle-api:4.1.3'
        classpath 'com.android.tools:common:27.1.3'
        classpath 'com.android.tools.analytics-library:tracker:27.1.3'
        classpath 'com.android.tools.analytics-library:shared:27.1.3'
        classpath 'com.android.tools:repository:27.1.3'
        classpath 'com.android.tools.build.jetifier:jetifier-core:1.0.0-beta09'

        classpath 'com.android.tools.build:builder:4.1.3'
        classpath 'com.android.tools.build:bundletool:0.14.0'
        classpath 'androidx.databinding:databinding-compiler-common:4.1.3'
        classpath 'com.android.tools.analytics-library:crash:27.1.3'
        classpath 'com.android.tools:sdk-common:27.1.3'
        classpath 'com.android.tools.build:apkzlib:4.1.3'
        classpath 'com.android.tools:sdklib:27.1.3'
        classpath 'com.android.tools.layoutlib:layoutlib-api:27.1.3'
        classpath 'com.android.tools.build.jetifier:jetifier-processor:1.0.0-beta09'
        classpath 'org.ow2.asm:asm-commons:7.0'
        classpath 'org.jdom:jdom2:2.0.6'
        classpath 'com.android.tools:repository:27.1.3'
        classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.2'
        //classpath 'com.github.dcendents:android-maven-plugin:1.2'
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

compileSdkVersion is not specified. Please add it to build.gradle

こんなエラーも出ました。
そして、調べるとandroid{}を追加すればOKと言うところにたどり着き以下のようなbuild.gradleになりました。

// Top-level build file where you can add configuration options common to all sub-projects/modules.

apply plugin: 'com.android.application'

buildscript {
    repositories {
        google()
        maven { url 'https://maven.aliyun.com/nexus/content/groups/public' }
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:4.1.3'
        classpath 'com.android.tools.build:aaptcompiler:4.1.3'
        classpath 'com.android.tools.lint:lint-gradle-api:27.1.3'
        classpath 'com.android.tools.build:gradle-api:4.1.3'
        classpath 'com.android.tools:common:27.1.3'
        classpath 'com.android.tools.analytics-library:tracker:27.1.3'
        classpath 'com.android.tools.analytics-library:shared:27.1.3'
        classpath 'com.android.tools:repository:27.1.3'
        classpath 'com.android.tools.build.jetifier:jetifier-core:1.0.0-beta09'

        classpath 'com.android.tools.build:builder:4.1.3'
        classpath 'com.android.tools.build:bundletool:0.14.0'
        classpath 'androidx.databinding:databinding-compiler-common:4.1.3'
        classpath 'com.android.tools.analytics-library:crash:27.1.3'
        classpath 'com.android.tools:sdk-common:27.1.3'
        classpath 'com.android.tools.build:apkzlib:4.1.3'
        classpath 'com.android.tools:sdklib:27.1.3'
        classpath 'com.android.tools.layoutlib:layoutlib-api:27.1.3'
        classpath 'com.android.tools.build.jetifier:jetifier-processor:1.0.0-beta09'
        classpath 'org.ow2.asm:asm-commons:7.0'
        classpath 'org.jdom:jdom2:2.0.6'
        classpath 'com.android.tools:repository:27.1.3'
        classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.2'
        //classpath 'com.github.dcendents:android-maven-plugin:1.2'
        // NOTE: Do not place your application dependencies here; they belong
        // in the individual module build.gradle files
    }
}

allprojects {
    repositories {
        google()
//        jcenter()
//        maven {
//            url 'https://maven.google.com/'
//            name 'Google'
//        }
    }

}

ext {
    // The following are only a few examples of the types of properties you can define.
    compileSdkVersion = 30
    // You can also create properties to specify versions for dependencies.
    // Having consistent versions between modules can avoid conflicts with behavior.
    supportLibVersion = "30.0.2"
}
//task clean(type: Delete) {
//    delete rootProject.buildDir
//}

android {
    compileSdkVersion 30
    buildToolsVersion '30.0.2'

    defaultConfig {
        applicationId ""
        minSdkVersion 15
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

ビルドも通りました。

でわでわ。。。

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でコンソールアプリを作る



Java Android 5〜計算アプリを作る〜

今回は、簡単な計算を行うアプリを作成しようと思います。
前回は、入力部品を作成しましたのでここに入力した数字を計算して、計算結果を表示するプログラムを作成します。

計算アプリを作る

今までは、プログラムというほどのものは触りませんでした。XMLのプロパティをいじっただけです。「Javaじゃねぇーだろ?」と思った方もいると思います。
しかし、XMLはJavaアプリケーションを作成するときによく出てくるので触っておいて損はありません。
XMLに慣れておけば、大体のフレームワークに対峙しても、立ち向かうことができるでしょう。。。

設計をする

アプリケーションを作るときに、はじめに「設計」を行います、これをやらないと。。。例えるならば

料理を作っているときに、塩加減を間違えたまま作ってしまう。

作ろうとしたものと違うものができてしまう

うんコードができてしまう

上記のような事態に陥る可能性が高くなります。熟練のプログラマーでも、ある程度の規模のアプリになれば、必ず設計をしなくては「うんコード」ができてしまいます(笑)

今回の設計

テキストボックスを2つ作ります。。。
早い話が、下のように画面を作ります。サンプル動画もつけています。

下のような、イメージです。

ここのAとBに値を入力して「TextView」の部分に計算結果を表示するという設計にしようと思います。

まぁ、このレベルならば「設計なんて。。。」と思うかもしれませんが、このレベルから始めれば理解もできるし、理解できれば応用もできます。

なんとかできた

とりあえず動くレベルですが。。。

まぁこんな感じです。ひどいもんです。。。

とりあえずは、入力部品の作成と配置のみでいっぱいいっぱいなので今回はここまでにします。

でわでわ。。。

<<< 前回 次回 >>>