Androidプログラムの基本から

by K.I
2014/09/19~

Index


概要


[top]

アプリケーション起動時の動作

Activity

AndroidManifest.xml

参考: IntentFilterにDEFAULT_CATEGORYが必要な理由 →よく理解していないが、とりあえずメモ

Hello Android!

デフォルトのLayout?

Activityの追加と遷移

遷移先からの戻り方

引数を渡して遷移

遷移先からデータを返す

ActivityResultLauncherの使用例(250802)


1この例では、hm.orz.bluefish.helloandroidというパッケージを作って、その中に入れてやる必要がある。
2packageの記述は、パッケージを作ると自動的に追加されるようだ。
3Activityの名前は、大文字小文字含めて正しく指定しないと実行時に落ちる。

[top]

Layout

Layoutリソースの追加

ActivityにLayoutをセット

LayoutのWarning

文字列の定義

リソースの参照

ボタンの動作記述

→ボタンを押すと、しばらくの間、挨拶が表示される

Clickイベントのメモ(250820)

参考: クリックイベントの基本的な実装
4Eclipseは、よく分からないことが多い。。
5このやり方で、さらにViewBindingを使うのが一番スッキリしていると思う。
6XMLのandroid:onClickでメソッドを指定する方法は、非推奨らしい。

[top]

Layoutについて補足(250825追記)

LinerLayout

┏━┳━┳━┓───────┐
┃A┃B┃C┃       │
┣━╋━╋━┫       │
┃D┃E┃F┃       │
┣━╋━╋━┫       │
┃G┃H┃I┃       │
┗━┻━┻━┛       │
│             │
│             │
│             │
│             │
│             │
└────── ──────┘

RelativeLayout

┏━┓───┏━┓───┏━┓
┃A┃   ┃B┃   ┃C┃
┗━┛   ┗━┛   ┗━┛
│             │
│             │
┏━┓   ┏━┓   ┏━┓
┃D┃   ┃E┃   ┃F┃
┗━┛   ┗━┛   ┗━┛
│             │
│             │
┏━┓   ┏━┓   ┏━┓
┃G┃   ┃H┃   ┃I┃
┗━┛───┗━┛───┗━┛

ConstraintLayout

        Top
      ┏━━━━━┓
      ┃     ┃
 Start┃     ┃End
(Left)┃     ┃(Right)
      ┃     ┃
      ┗━━━━━┛
       Bottom
<androidx.constraintlayout.widget.ConstraintLayout>

    <TextView android:text="A"
        android:id="@+id/A"
        app:layout_constraintTop_toTopOf="parent"       ⇒AのTopを親のTopに合わせる
        app:layout_constraintStart_toStartOf="parent"   ⇒AのStartを親のStartに合わせる
        app:layout_constraintEnd_toStartOf="@id/B" />   ⇒AのEndをBのStartに合わせる

    <TextView android:text="B"
        android:id="@+id/B"
        app:layout_constraintTop_toTopOf="@+id/A"       ⇒BのTopを親のTopに合わせる
        app:layout_constraintStart_toEndOf="@+id/A"     ⇒BのStartをAのEndに合わせる
        app:layout_constraintEnd_toStartOf="@+id/C" />  ⇒BのEndをCのStartに合わせる

    <TextView android:text="C"
        android:id="@+id/C"
        app:layout_constraintTop_toTopOf="@+id/B"       ⇒CのTopを親のTopに合わせる
        app:layout_constraintStart_toEndOf="@+id/B"     ⇒CのStartをBのEndに合わせる
        app:layout_constraintEnd_toEndOf="parent" />    ⇒CのEndを親のEndに合わせる

</androidx.constraintlayout.widget.ConstraintLayout>
┌─┏━┓──┏━┓──┏━┓─┐
│ ┃A┃  ┃B┃  ┃C┃ │
│ ┗━┛  ┗━┛  ┗━┛ │
│               │
│               │
│               │
│               │
│               │
│               │
│               │
│               │
│               │
└─────── ───────┘

FrameLayout

include

xmlns記述について


7namespaceの指定とかね。
8これが出来ないとすると、あまり使い道が無いかも。何か方法があるんだろうか?
9Androidのxmlファイルでは、自分はこれ以外の物を多分見たことが無い。

[top]

ListView

セルのレイアウト

ListViewのレイアウト

ListViewにデータをセット

ListViewのクリック動作記述


10wrap_contentだと、一度仮想的に描画してサイズを確認したあと、改めて描画するというような操作をしているらしい。

[top]

ListViewのカスタマイズ

アニメーションのXML

Adapterのカスタマイズ

getViewについて

カスタムAdapterを使ってみる


11ListViewのカスタマイズということだけなら、このファイルは特に要らないけど。
12なんかシステムでやっても良い様なことまで、やらされてるんじゃないかなって気がする。

[top]

Holderを使わないListView

Layoutクラスのカスタマイズ

CustomLayoutクラスを使う

Holderを使わないカスタムAdapter

Holderを使わないListViewを使う


[top]

OverScrollListView

ListViewのカスタマイズ

OverScroll用のLayout

カスタムListViewを使う


[top]

グラフィックス

View

Viewに描画

View Group

カスタムのViewクラスの作成

カスタムViewクラスを使ってみる


13これって、けっこう凄いことだよね。

[top]

アクションバー

アクションバーを使う

Optionメニュー

menuリソースで

表示方法
ifRoom Barに表示できない場合は、Overflowメニューに表示
withText Textを表示
never 常にOverflawメニューに表示する
always 常にBar上に表示
collapseActionView android:actionViewLayoutで指定したActionViewと関連付ける

Optionメニュー選択時の処理

Optionメニューの無効化

onPrepareOptionsMenuが呼ばれない

参考: stackOverflow

サブメニューにアイコンを付ける

Spinnerのリソース

Spinnerを使う


14もしかすると、Theme使ってる所為かもしれないけど。
15MacとかWindowsでは、Menuは動的に変化することが前提なので、メニュー準備のイベントは必ず呼ばれるけど、Androidは何でこうなってるんだろう。。

[top]

Mouseの動きで描画

ViewにMouseで描画

プログラムによるレイアウト

LayoutInflaterを使う

LayoutInflaterについて

Databinding(250828追記)


16こんなのソース初見じゃ分からなかった。なんでこんな仕組みなんだろう?
17実体化というのは、自分のイメージであって、正しい表現では無いと思うけど。
18LayoutInflaterを使うのは同じみたいだけど。

[top]

オフスクリーン

オフスクリーンの生成

Bitmap.config 1ピクセルあたりの、byte数/定義内容
ARGB_8888 4byte/αチャネル(8bit)、R(8bit)、G(8bit)、B(8bit)
ARGB_4444 2byte/αチャネル(4bit)、R(4bit)、G(4bit)、B(4bit)
RGB_565 2byte/αチャネルなし、R(5bit)、G(6bit)、B(5bit)
ALPHA_8 1byte/αチャネル(8bit)のみ

オフスクリーンを使った描画

オフスクリーンを使ったCanvas

Viewのメソッド呼び出し

Viewの保存


[top]

ファイルアクセス(250803追記)

共有ストレージのファイルにアクセスする

標準ファイルピッカーによるURI取得2

    Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
    intent.addCategory(Intent.CATEGORY_OPENABLE);
    intent.setType("*/*");
    // 複数の画像ファイルを表示する場合
    // intent.setType("image/*");
    // 複数の画像とPDFファイルを表示する場合
    // String[] mimeTypes = {"image/*", "application/pdf"};
    // intent.putExtra(Intent.EXTRA_MIME_TYPES, mimeTypes);

    // ファイルの読み込み権限を付与します
    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

        // ファイルピッカーの開始と結果の受け取りを準備
    int PICK_FILE_REQUEST_CODE = 2;
    startActivityForResult(intent, PICK_FILE_REQUEST_CODE);


        @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == PICK_FILE_REQUEST_CODE && resultCode == Activity.RESULT_OK && data != null) {
            Uri uri = data.getData();
            // ここで uri を使ってファイルにアクセスします
            // 例:画像の表示やファイル内容の読み込みなど
        }
    }

import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import androidx.appcompat.app.AppCompatActivity;
import android.widget.Button;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {

    // ActivityResultLauncherを登録
    private ActivityResultLauncher<Intent> openDocumentLauncher;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main); // activity_main.xmlを配置していると仮定

        Button selectFileButton = findViewById(R.id.select_file_button); // R.id.select_file_button はボタンのID

        // ActivityResultLauncherの登録
        openDocumentLauncher = registerForActivityResult(
                new ActivityResultContracts.StartActivityForResult(), // ActivityResultContracts.StartActivityForResult()はファイルピッカーの戻り値を扱うために使用する
                result -> {
                    if (result.getResultCode() == RESULT_OK && result.getData() != null) {
                        // 選択されたファイルURIの取得
                        Uri selectedFileUri = result.getData().getData();
                        if (selectedFileUri != null) {
                            Toast.makeText(this, "選択されたファイル: " + selectedFileUri.toString(), Toast.LENGTH_SHORT).show();
                            // ここで選択されたファイルに対する処理を行う
                        }
                    }
                });

        selectFileButton.setOnClickListener(v -> {
            openDocumentFile();
        });
    }

    private void openDocumentFile() {
        // ファイル選択用インテントの作成
        Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);

        // 全てのファイルタイプを表示する場合
        // intent.setType("*/*"); または intent.setType(MIME_TYPE_ALL);
        //特定のMIMEタイプを表示する場合
        intent.setType("image/*"); // 画像ファイルのみを表示する場合
        // intent.setType("application/pdf"); // PDFファイルのみを表示する場合

        // 必要に応じて、複数ファイル選択を有効にする
        // intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);

        // ファイルピッカーを起動する
        openDocumentLauncher.launch(intent);
    }
}

URIの表示

ファイル削除

共有ストレージのフォルダを選択


[top]

現時点のファイルアクセスについて(250918)

作業フォルダについて

DocumentFile workDir = DocumentFile.fromTreeUri(getApplicationContext(), workUri);

ファイル書き込みについて

ファイル読み込みについて

過去に作ったファイルピッカーを直せないか検討


19Android15の時点では。あまりコロコロ変えないで欲しい。。
20SDカードのルートディレクトリや、Downloadディレクトリなどは、選択できない。
21アプリを再起動しても権限は保持される。
22フラグはいろいろあるみたいだが、永続化で指定した2つのフラグしか確認するメソッドが用意されていない。
23権限を与えたアプリをアンインストールすると、URIのリストは削除される。
24DocumentFileは、AndroidのStorageAccessFramework(SAF)で使用される高レベルに抽象化されたクラスらしい。しらんけど。
25MIMEタイプには、text/plain, image/jpeg, application/pdf, application/octet-stream 等がある。
26というか、何故、ファイル作成時にファイルタイプを決める必要があるんだろう?
27開発環境はEclipseだが、Lolipop~Marshmallow(Android5~6)ぐらいだったので、SAFは実装されているはずなんだけど、ネット上の情報が少し古かったのかも。
28ディレクトリの変更は、共有ストレージのフォルダ選択で代用するか。。

[top]

その他

Toast


29このやり方は、非推奨になったらしいが。。

[top]

まとめ


30XMLって、冗長な感じがして、どうもあまり好きじゃない。

[top]

エラーメッセージ

Error parsing XML: not well-formed (invalid token)

No speakable text present

ClassCastException

NullPointerException

No such file or directory

APK app-debug.apk is not compatible with 16 KB devices.

overridden method is final


31一度、このエラーが出ると、Eclipseの状態が少しおかしくなるのかもしれない。
32なかなか見つからないこともあるが、それでも単純なプログラムミス・考慮不足のことが多いので。

[top]

参考


[top] [プログラムの部屋に戻る]

 ⇒ Disqusの広告がうるさすぎるので基本は非表示にしました