20200227のAndroidに関する記事は14件です。

androidのtargetSdkVersionを'R'に変更する

はじめに

探すの戸惑ったのでここにメモしておきます。

参考

https://developer.android.com/preview/setup-sdk?hl=ja

解決サンプル

build.gradle
android {
    compileSdkVersion 'android-R'

    defaultConfig {
        targetSdkVersion 'R'
    }
}

targetSdkVersionについて少し

対応する最大のバージョン

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

DroidKaigi2020アプリで使われているInjectableについて

DroidKaigi2020公式アプリで使われているInjectableが良さげだったので記事にします。

Injectable

当該のプルリクエストはこちらです。

InjectableはDaggerのInjectを便利にするためのInterfaceです。
元々はGoogleのarchitecture-components-samplesにあるGithubBrowserSampleで使われているコードです。
イメージとしては、DaggerFragment = Fragment + Injectableです。

Injectable.kt
interface Injectable
SearchSessionsFragment.kt
class SearchSessionsFragment : Fragment(R.layout.fragment_search_sessions), Injectable {
    ....
}

Injectableそのものは空のInterfaceで、実際のInjection周りの処理はAppInjectorが受け持っています。

AppInjector.kt
object AppInjector {
    fun initialize(application: Application) {
        application.registerActivityLifecycleCallbacks(
            object : Application.ActivityLifecycleCallbacks {

                override fun onActivityCreated(
                    activity: Activity,
                    savedInstanceState: Bundle?
                ) {
                    handleActivity(activity)
                }

                override fun onActivityStarted(activity: Activity) {
                }

                override fun onActivityResumed(activity: Activity) {
                }

                override fun onActivityPaused(activity: Activity) {
                }

                override fun onActivityStopped(activity: Activity) {
                }

                override fun onActivitySaveInstanceState(
                    activity: Activity,
                    outState: Bundle?
                ) {
                }

                override fun onActivityDestroyed(activity: Activity) {
                }
            })
    }

    private fun handleActivity(activity: Activity) {
        if (activity is HasAndroidInjector) {
            AndroidInjection.inject(activity)
        }
        if (activity is FragmentActivity) {
            activity.supportFragmentManager.registerFragmentLifecycleCallbacks(
                object : FragmentManager.FragmentLifecycleCallbacks() {
                    override fun onFragmentPreAttached(
                        fm: FragmentManager,
                        f: Fragment,
                        context: Context
                    ) {
                        if (f is Injectable || f is HasAndroidInjector) {
                            AndroidSupportInjection.inject(f)
                        }
                    }
                }, true
            )
        }
    }
}

これをApplicationクラスでAppInjector.initialize(this)することによって、自動でFragmentにInjectしてくれるようになります。
DaggerFragmentを使った場合と変わらないように見えるかもしれませんが、色々と便利になります。

1. FragmentのコンストラクタにレイアウトIdを渡せる

上のコードでも書かれていますが、FragmentのコンストラクタにレイアウトIdを渡すことによってレイアウトのViewをinflateできます。
これにより、onCreateViewでinflateの処理を書く必要がなくなります。

ExampleFragment.kt
class ExampleFragmentWithDagger : DaggerFragment() {
    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                              savedInstanceState: Bundle?): View? {
        val view = inflater.inflate(R.layout.fragment_example, container, false)
        return view
    }
}

class ExampleFragmentWithInjectable : Fragment(R.layout.fragment_example), Injectable {
}

2. テストが書きやすくなる

おそらくGithubBrowserSampleの方ではこちらが目的だったのではないかなと思います。
例えば、以下のようにViewModelFactoryをInjectしているFragmentのテストを書くとします。

ExampleFragment.kt
class ExampleFragmentWithDagger : DaggerFragment() {
    @Inject lateinit var viewModelFactory: ViewModelProvider.Factory
    ...
}

テストコードは以下の通り。

ExampleFragmentWithDaggerTest.kt
@RunWith(AndroidJUnit4::class)
class ExampleFragmentWithDaggerTest {
    @Test
    fun test() {
        val scenario = launchFragmentInContainer<ExampleFragmentWithDagger>()
        scenario.onFragment { fragment ->
            // write fragment test
        }
    }
}

このテストを実行するのは結構面倒です。
特に、ViewModelFactoryをモックにする場合はModuleやComponentを別に作成する必要が出てきそうです。
また、マルチモジュールのアプリだとモジュール間の依存関係がネックになったりしてさらに面倒です。

そこで、Injectableを使用したらどうでしょうか。

ExampleFragment.kt
class ExampleFragmentWithInjectable : Fragment(R.layout.fragment_example), Injectable {
    @Inject lateinit var viewModelFactory: ViewModelProvider.Factory
    ...
}
ExampleFragmentWithInjectableTest.kt
@RunWith(AndroidJUnit4::class)
class ExampleFragmentWithInjectableTest {
    @Test
    fun test() {
        val scenario = launchFragmentInContainer<ExampleFragmentWithInjectable>() {
            ExampleFragmentWithInjectable().apply {
                // Inject here
                viewModelFactory = mockViewModelFactory
            }
        }
        scenario.onFragment { fragment ->
            // write fragment test
        }
    }
}

Injectableを使うとテストではDaggerのdependencyを定義する必要がなくなります。(AndroidSupportInjection.injectを実行するのはApplicationクラスなので)
したがって、FragmentScenarioをlaunchする際に自分でInjectすることができます。
これならDIしているものをモックするのも簡単ですし、テストが書きやすいです。
ちなみに、GithubBrowserSampleではテスト用のViewModelFactoryを作成するUtilがあったり、Fragmentのテストを書く際にとても参考になります。

さいごに

Fragmentテストの解説はrnakanoさんの「Jetpack時代のFragment再入門」が非常に分かりやすくおすすめです。
参考にさせていただきました。
https://youtu.be/IwHw7vrFwSE

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Docker を用いた AOSP Android10 のビルド時間の測定結果

はじめに

AOSP Android10 全体のビルド時間を測定したので、結果を共有します。
ビルド環境には Docker (Ubuntu 18.04) を用いました。
ビルド時間短縮のポイントは、これまで AOSP のワークスペースに組み込まれてきた
ccacheAndroid10 からはサポートされなくなった事 を受けて、

Our binary was rather old, and for a variety of reasons we haven't kept
it updated.

ビルド環境に ccache をインストールし、有効化する必要がありました。

but if you still want to use ccache, continue setting USE_CCACHE
and also set CCACHE_EXEC to the path of your ccache executable.

実行結果

クリーンビルド ビルド時間(分)
ccache なし 245m
ccache あり 81m
インクリメンタルビルド ビルド時間(分)
ccache なし 212m
ccache あり 33m

実行環境

  • Azure D8 v3
    • vCPU = 8 / Memory = 32GiB / Disk = 200GiB
  • Docker 19.03.6
    • ベースイメージは ubuntu:18.04
    • ccache 3.4.1

環境構築

ホストについて

ホスト OS は Ubuntu 18.04.4 LTS とします。また、Android のビルドには必要なパッケージが多いため、ホストに直接インストールする代わりに Docker を活用します。Ubuntu に Docker をインストールする手順やインストール後の便利な設定は、こちらをご確認ください。

Dockerfile

AOSP がサポートしている(と言っても少々古い) build/tools/docker を参考にしながら、
ベースイメージ ubuntu:18.04 で Android10 がビルドできるように少し修正を加えました。

Dockerfile
FROM ubuntu:18.04
ARG userid
ARG groupid
ARG username

RUN apt-get update && apt-get install -y \
    git-core \
    gnupg \
    flex \
    bison \
    gperf \
    build-essential \
    zip \
    curl \
    zlib1g-dev \
    gcc-multilib \
    g++-multilib \
    libc6-dev-i386 \
    lib32ncurses5-dev \
    x11proto-core-dev \
    libx11-dev \
    lib32z-dev \
    ccache \
    libgl1-mesa-dev \
    libxml2-utils \
    xsltproc \
    unzip \
    python \
    python3-minimal \
    rsync \
 && apt-get clean \
 && rm -rf /var/lib/apt/lists/*

RUN curl -o /usr/local/bin/repo https://storage.googleapis.com/git-repo-downloads/repo \
 && chmod a+x /usr/local/bin/repo

RUN groupadd -g $groupid $username \
 && useradd -m -u $userid -g $groupid $username \
 && echo $username >/root/username \
 && echo "export USER="$username >>/home/$username/.gitconfig
COPY gitconfig /home/$username/.gitconfig
RUN chown $userid:$groupid /home/$username/.gitconfig
ENV HOME=/home/$username

ENTRYPOINT chroot --userspec=$(cat /root/username):$(cat /root/username) / /bin/bash -i

元 Dockerfile との差分をハイライトすると、次のようになります。

build/tools/docker/Dockerfileとの差分
-FROM ubuntu:14.04
+FROM ubuntu:18.04

RUN apt-get update && apt-get install -y \
-    openjdk-7-jdk
+    python3-minimal \
+    rsync \
+ && apt-get clean \
+ && rm -rf /var/lib/apt/lists/*


- RUN curl -o jdk8.tgz https://android.googlesource.com/platform/prebuilts/jdk/jdk8/+archive/master.tar.gz \
- && tar -zxf jdk8.tgz linux-x86 \
- && mv linux-x86 /usr/lib/jvm/java-8-openjdk-amd64 \
- && rm -rf jdk8.tgz

RUN curl -o /usr/local/bin/repo https://storage.googleapis.com/git-repo-download
- && echo "e147f0392686c40cfd7d5e6f332c6ee74c4eab4d24e2694b3b0a0c037bf51dc5  /usr/local/bin/repo" | sha256sum --strict -c - \

修正箇所について補足します。

  • openjdk-7-jdk / jdk8.tgz 削除
    • Software requirements >> JDK によると、ビルド済 OpenJDK は既にワークスペースに組み込まれているため、古いバージョンの Android のために必要な JDK は削除しました
  • python3-minimal 追加
    • python3.x がないと AssertionError: Could not find python binary: python3 とエラーになるため追加しました
  • rsync 追加
    • rsync がないと FAILED: out/target/product/generic/ramdisk-debug.img とエラーになるため追加しました(ベースイメージ ubuntu:18.04 に含まれていませんでした)
  • repo のチェックサムの確認の省略
    • 元コードでは repo の正真性をハッシュ値で確認していましたが e147f039 は古いため削除しました
    • その代わりに現時点の repo 2.4.1 のハッシュ値 d2e17c4b としても良かったのですが git-repo を読む限り、ここ最近頻繁に更新されていることを受け、今回はチェックそのものをやめておきます

ただし、十分にメンテナンスされていないように見える AOSP の Dockerfile を起点として作業をしているため、他にも既に不要なパッケージが含まれているかもしれません。今後 AOSP から新しい世代向けの Dockerfile が公開されたら、そちらに移行した方が無難です。

Docker イメ―ジのビルド

build/tools/docker/README.md を参考に Docker イメージをビルドします。

# Copy your host gitconfig, or create a stripped down version
$ cp ~/.gitconfig gitconfig
$ docker build --build-arg userid=$(id -u) --build-arg groupid=$(id -g) --build-arg username=$(id -un) -t android-build-bionic .

ビルドされたイメージを確認します。

$ docker image list
REPOSITORY             TAG                 IMAGE ID            CREATED              SIZE
android-build-bionic   latest              ff2cb9986cd7        About a minute ago   612MB

ソースコード取得

今回は Android10 Release revision 14 を題材としてビルド時間の測定することにします。

# /mnt/work/aosp をワークスペースとします
$ sudo chown -R $USER:$USER /mnt
$ mkdir -p /mnt/work/aosp
$ cd /mnt/work/aosp
$ repo init -u https://android.googlesource.com/platform/manifest -b android-10.0.0_r14 
$ time repo sync -j8

repo sync has finished successfully.

real    51m0.159s
user    133m47.445s
sys     13m13.264s

構築されたワークスぺースを確認します。

$ repo list | wc -l 
745

$ du -sh . 
90G . 

このように、745 もの Git リポジトリからワークスペースが構成され、ビルド前にも関わらず 90GB もディスクを使用していることが確認できました。相変わらず巨大なプロジェクトです。

ビルド

さて、いよいよビルドします。
build/tools/docker/README.md を参考に、少し手直ししながら Docker コンテナを起動します。

docker-run.sh
# Docker 用のキャッシュディレクトリを用意します
$ mkdir -p /mnt/.cache /mnt/.ccache

$ docker run -it --rm \
    -v /mnt/work/aosp:/src \
    -v /mnt/.cache:/mnt/.cache \
    -v /mnt/.ccache:/mnt/.ccache \
    -e XDG_CACHE_HOME=/mnt/.cache \ # Docker 用キャッシュディレクトリを参照します
    -e CCACHE_DIR=/mnt/.ccache \ # Docker 用キャッシュディレクトリを参照します
    -e CCACHE_COMPRESS=1 \ # キャッシュサイズの圧縮のため
    -e CCACHE_EXEC=/usr/bin/ccache \ # 後述
    -e USE_CCACHE=1 \ # 後述
    android-build-bionic

こちら のコミットログによると、ccache を有効化するためには
-e USE_CCACHE=1-e CCACHE_EXEC=/usr/bin/ccache の設定が必要でした。

So if you still want to use ccache, continue setting USE_CCACHE, but also set
the CCACHE_EXEC environment variable to the path to your ccache executable.

これでビルド用 Docker コンテナが起動できたはずです。
続いて ccache の有無やビルド方式の違いについて比較していきます。
なお、以降のコマンドはすべて Docker コンテナ上で実行します。

クリーンビルド

中間生成物やビルド成果物を削除して、イチからビルドする方式となります。
リリースビルドの場合は、こちらになると思います。
コンフィギュレーションやビルドターゲットについては以下の公式手順を参考にしています。

クリーンビルド(ccache なし)

Docker
$ rm -rf out

$ source build/envsetup.sh
$ lunch aosp_arm-userdebug
$ unset USE_CCACHE # 実験的に ccache を無効化するため
$ time m

#### build completed successfully (04:05:56 (hh:mm:ss)) ####
real    245m55.990s
user    1790m50.629s
sys     97m4.830s

クリーンビルド(ccache あり)

キャッシュが保存されていない環境では、以下のビルド手順を 2 回 実行して計測する必要があります。( 1 回目のビルドはキャッシュを蓄えるため )

Docker
$ rm -rf out
$ ccache -z # キャッシュ統計情報のクリア

$ source build/envsetup.sh
$ lunch aosp_arm-userdebug
$ time m

#### build completed successfully (01:21:53 (hh:mm:ss)) ####
real    81m52.620s
user    557m28.541s
sys     39m36.687s

ccache が効果的に作用したことで ビルド時間が約 1/3 に短縮されました。:tada:
この状態で、キャッシュのヒット数やヒット率などの統計情報を見てみます。

ccache_統計情報の表示
$ ccache -s

cache directory                     /mnt/.ccache
primary config                      /mnt/.ccache/ccache.conf
secondary config      (readonly)    /etc/ccache.conf
stats zero time                     Thu Feb 27 00:55:12 2020
cache hit (direct)                 33652
cache hit (preprocessed)             325
cache miss                             0
cache hit rate                    100.00 %
called for link                       77
called for preprocessing              18
unsupported code directive             2
cleanups performed                     0
files in cache                    101488
cache size                           3.9 GB
max cache size                       5.0 GB

期待通り cache hit rate 100.00 % となっていることが確認できました。

cache hit (direct) 33652

このヒット数が妥当な数値であるかについては、ビルド対象となった C/C++ ファイルの数を調べるなどして、検証する必要があると感じています。(今回は調べ切れていません)

インクリメンタルビルド

インクリメンタルビルド(差分ビルド)は、依存関係が正しく書かれたビルドシステムを前提として、変更されたファイルとその依存ファイルがビルドされる方式です。したがって、通常クリーンビルドと比べて処理数が少なくなるため、その分高速になります。開発者がローカル環境でビルドするときは、多くの場合がこちらになると思います。

何も更新されていない場合

Docker
$ ccache -z

$ source build/envsetup.sh
$ lunch aosp_arm-userdebug
$ time m

#### build completed successfully (5 seconds) ####
real    0m5.080s
user    0m11.956s
sys     0m3.644s

Android のビルドシステムは依存関係の記述が正しくメンテナンスされているため、差分がまったくない状態でインクリメンタルビルドをすると、あっという間に完了します。なお、このケースではコンパイルもされないため cache hit rate 0.00 % のままとなっていました。

インクリメンタルビルド(ccache なし)

さて、今度はソースコードの更新をシミュレーションするため AOSP の一部のファイルのタイムスタンプを更新します。それによって変更されたファイルとその依存ファイルの再ビルドが実行されます。

Docker
$ ccache -z
$ touch external/protobuf/src/google/protobuf/*

$ source build/envsetup.sh
$ lunch aosp_arm-userdebug
$ unset USE_CCACHE # 実験的に ccache を無効化するため
$ time m

#### build completed successfully (03:32:32 (hh:mm:ss)) ####
real    212m31.772s
user    1586m36.813s
sys     69m56.492s

前回の クリーンビルド(ccache なし)と比べて、わずかに短縮されていたものの、かなり時間がかかってしまいました。

インクリメンタルビルド(ccache あり)

Docker
$ ccache -z
$ touch external/protobuf/src/google/protobuf/*

$ source build/envsetup.sh
$ lunch aosp_arm-userdebug
$ time m

#### build completed successfully (33:53 (mm:ss)) ####
real    33m53.000s
user    237m48.218s
sys     10m31.486s

インクリメンタルビルドのおいてもやはり ccache は効果的で、無効時と比べて ビルド時間が約 1/6 ~ 1/7 に短縮されました。ただし、どのファイルが更新されたかで依存関係やビルド対象となるファイル数は大きく変わるため、これはあくまで一例となります。この状態で、キャッシュのヒット数やヒット率などの統計情報を見てみます。

キャッシュ統計情報の表示
$ ccache -s

cache directory                     /mnt/.ccache
primary config                      /mnt/.ccache/ccache.conf
secondary config      (readonly)    /etc/ccache.conf
stats zero time                     Thu Feb 27 04:28:46 2020
cache hit (direct)                  1737
cache hit (preprocessed)              35
cache miss                             0
cache hit rate                    100.00 %
called for link                        8
cleanups performed                     0
files in cache                    101503
cache size                           3.9 GB
max cache size                       5.0 GB

今回も期待通り cache hit rate 100.00 % となっていることが確認出来ました。

cache hit (direct) 1737

クリーンビルド(ccache あり)の時と比べて、再コンパイルの必要なファイルが少ないため、このようにヒット数自体が下がることは妥当だと思います。

おわりに

今回は Docker を用いた AOSP Android10 のビルド方法とビルド時間の測定結果についてまとめました。今後、更にビルド時間を短縮化するために、

  • 更に高パフォーマンスなホストを試してみる
  • より新しい https://ccache.dev (例えば 3.7+) を試してみる

などのチャレンジをしてみても面白いと思います。

補足資料

ベンチマークが Android 4.x なので少し古い資料になりますが、Core 数や ccache と Android のビルド時間の関係について調査しているので、こちらも参考になると思います。
Accelerating Android Builds

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Android-Codelabs】10/36 〜 Fragmentの使い方 〜

2019年にGoogleから,Web上でAndroidを学べるコースが提供されました.(Android Kotlin Fundamentals Course)
この記事では,そのコースを実際にやってみてアウトプットしてみるといった内容です.
何かツッコミなどあれば編集リクエストかコメントかTwitterでいただければ修正いたします

今回学ぶこと

・Fragmentをアプリに追加する方法

目指す成果物

今回は,このようなクイズアプリを作っていきます.

3-1-1.png

アプリの仕様
・左のスクリーンショットのタイトル画面で,ゲームを開始します.
・真ん中のスクリーンショットのゲーム画面で,解答を送信します.
・右のスクリーンショットの画面で,navigationドロワーメニューは,アプリの横からスライドすると出てきます.

ステップ

1. スタータープロジェクトをダウンロードする

今回は,アプリに必要なテンプレートコードとFragmentクラスをダウンロードした状態から進めます.

  1. AndroidTrivia-Starter Android Studioプロジェクトをダウンロードします.
  2. Android Studioでプロジェクトを開き,アプリを実行します.アプリを開くと,アプリ名と空白の画面を表示する以外は何もしません.

3-1-2.png

2. Fragmentを追加する

Fragmentは,アクティビティの動作やUIの一部のことをいいます.
一つのアクティビティで,複数のFragmentを組み合わせてmulti-pane UIを構築し,複数のアクティビティでFragmentを再利用できます.

Fragmentは,サブアクティビティのようなものです.

・Fragmentには,独自のライフサイクルがあり,独自の入力イベントを受け取る
・Fragmentは,アクティビティの実行中に追加や削除ができる
・Fragmentは,Kotlinクラスで定義される
・FragmentのUIは,XMLレイアウトファイルで定義される

今回のアプリには,MainActivityといつくかのFragmentがあります.
ここのステップでは,Fragmentを作成し,そのFragmentをアプリのMainActivityに追加していきます.

まず,空のTitileFragmentクラスを作成します.
[File]>[New]>[Fragment]>[Fragment(blank)]

Nameを,TitleFragmentにして,チェックアウトをすべて外しFragmentを作成します.

TitleFragment.ktを開くと,onCreateView()メソッドが含まれていて,これはFragmentのライフサイクル中に呼び出されるメソッドの一つです.

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
                         savedInstanceState: Bundle?): View? {
}

次にバインディングオブジェクトを作成します.
Fragmentは現在コンパイルされません.Fragmentをコンパイルするには,バインディングオブジェクトを作成し,Fragmentのビューをinflateさせる必要があります.

まず,onCreateView()メソッド内で,変数bindingを作成します.
そしてFragmentのビューをinflateさせるには,DataBindingUtil.inflate()メソッドを呼び出します.

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
   val binding = DataBindingUtil.inflate<FragmentTitleBinding>(inflater, R.layout.fragment_title,container,false)
   return binding.root
}

ここでメソッドには,4つのパラメーターを渡します.
・inflater: バインディングレイアウトをinflateさせるため 
・R.layout.fragment_title: 展開するレイアウトのXMLレイアウトリソースを指定
・container: 親のViewGroupのために指定
・false: attachToParentのために指定

変数bindingに,DataBindingUtil.inflate()を割り当てます.

戻り値はbinding.rootを返します.

3. Fragmentをメインレイアウトファイルに追加する.

ここでは,FragmentのTitleFragment.ktを,レイアウトファイルのactivity_main.xmlに追加します.

LinearLayout要素内に,fragment要素を追加し,idを指定します.

Fragmentのnameを,Fragmentクラスのフルパスに設定します.
(ここではcom.example.android.navigation.TitleFragmentとします.)

そしてレイアウトファイルactivity_main.xmlはこのようになります.

activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical">
            <fragment
                android:id="@+id/titleFragment"
                android:name="com.example.android.navigation.TitleFragment"
                android:layout_width="match_parent"
                android:layout_height="match_parent"/>
        </LinearLayout>
</layout>

アプリを実行して,Fragmentがメイン画面に追加せれたことを確認してください.

3-1-3.png

まとめ

・Fragmentには独自のライフサイクルがあり,独自の入力イベントを受け取る
・Fragmentのレイアウトを定義するには,XMLレイアウトでタグを使う
・Fragmentは,アクティビティの実行中に追加や削除ができる
・inflateは,onCreateView()内で,Fragmentのレイアウトを拡張します

クイズ

1問目
FragmentとActivityの違いはなんですか? 正しいものをすべて選んでください

・Fragmentを作成するとき,onCreateView()メソッドのレイアウトをinflateします.Activityを作成するときonCreateViewメソッドでレイアウトをinflateします.
・Activiyには独自のレイアウトがありますが,Fragmentには独自のレイアウトを設定できません.
・Activityには独自のライフサイクルがありますが,Fragmentにはありません.
・FragmentまたはActivityのいずれかのレイアウトをinflateする場合,レイアウトをとしてR.layout.layoutnameを参照する.

2問目
Fragmentに関する次の記述のうち,正しいものをすべて選んでください

・Fragmentを複数のActivityで使用できる
・複数のFragmentを一つのActivityに含めることができる
・FragmentをKotlinクラスで定義すると,自動的にFragmentはactivity_main.xmlのレイアウトファイルに追加される
・Fragmentを挿入する場所は,タグを使って定義する

クイズの正解

1問目

・Fragmentを作成するとき,onCreateView()メソッドのレイアウトをinflateします.Activityを作成するときonCreateViewメソッドでレイアウトをinflateします.
・Activityには独自のライフサイクルがありますが,Fragmentにはありません.
・FragmentまたはActivityのいずれかのレイアウトをinflateする場合,レイアウトをとしてR.layout.layoutnameを参照する.

2問目

・Fragmentを複数のActivityで使用できる
・複数のFragmentを一つのActivityに含めることができる
・Fragmentを挿入する場所は,タグを使って定義する

ソースコード

Github:
https://github.com/syuheifujita/android-codeLab-fundamental-3-1

言葉の定義

・Fragment
アクティビティの動作やUIの一部のことをいいます.

参考資料

CodeLabs by Google

https://codelabs.developers.google.com/android-kotlin-fundamentals/
スクリーンショット 2020-02-05 4.07.59.png

おわりに:他にもっとわかりやすい方法あれば教えてください

僕は「Codelabs」をやることでFragmentの使い方をまとめてみました.

もしかすると,情報が古かったり間違っていたり,他にもっとわかりやすい方法があるのかもしれません.

皆さんの中で上手にFragmentの使い方をまとめている方がいれば,ぜひ教えてください!
Twitterやコメントなどでお待ちしています.
質問でもお気軽に!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Android StudioでUsageStatsManagerを使う方法(他のアプリの起動時間を調べる方法)

前提

Windows 10
Android Studio最新版
Java

この方法は、2020/02/27時点では私のスマートフォンのおいては正常に動作しました。
仕様変更があるかもしれないので、コピペしてうまく行かない場合は公式ドキュメントを参考にしましょう。

やりたいこと

他のアプリがその日どれくらい起動していたかを取得する必要がありました。
例えば、下の画像はActionDashというアプリで、他のアプリの起動時間を表示しています。

結論から言うと、UsageStatsManagerを使えば良いです。

UsageStatsManager

権限関係

まず、下のようにAndroidManifest.xmlに記載してください。

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

    <!-- 下の二行を追加 -->
    <uses-permission android:name="android.permission.PACKAGE_USAGE_STATS"
        tools:ignore="ProtectedPermissions" />

    <application>
         <!-- 省略 -->
    </application>

</manifest>

次に、permission checkを行います。
普通のpermissionの方法ではなく、特別な方法を使用します。

private boolean checkReadStatsPermission() {
  // AppOpsManagerを取得
  AppOpsManager aom = (AppOpsManager) getSystemService(Context.APP_OPS_SERVICE);
  // GET_USAGE_STATSのステータスを取得
  int mode = aom.checkOp(AppOpsManager.OPSTR_GET_USAGE_STATS, android.os.Process.myUid(), getPackageName());
  if (mode == AppOpsManager.MODE_DEFAULT) {
    // AppOpsの状態がデフォルトなら通常のpermissionチェックを行う。
    // 普通のアプリならfalse
    return checkPermission("android.permission.PACKAGE_USAGE_STATS", android.os.Process.myPid(), android.os.Process.myUid()) == PackageManager.PERMISSION_GRANTED;
  }
  // AppOpsの状態がデフォルトでないならallowedのみtrue
  return mode == AppOpsManager.MODE_ALLOWED;
}

最後に、permissionのリクエストです。
これも、通常の方法と違うので注意が必要です。

if (!checkReadStatsPermission()) {
  startActivity(new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS));
}

UsageStatsManagerを使う

ソースコードの中で解説を入れています。
このソースコードは、その日のアプリの使用時間を取得します。

public class UsageStatsClass {
  // Log.d()で、このクラスが出力したものだと識別するための名前
  private static final String TAG = UsageStatsClass.class.getSimpleName();
  // MainActivityのContextを代入
  private Context context;

  public UsageStatsClass(Context mContext) {
    // contextを代入
    context = mContext;
  }

  // UsageStatsというObjectは、一つのアプリの情報(アプリの使用時間など)が入っている
  // つまり、1つアプリにつき1つのUsageStatsが割り当てられる
  private List<UsageStats> getUsageStatsObject() {
    // getSystemService()で、UsageStatsManagerを取得する
    // UsageStatsManagerは、アプリの使用情報を取得するためのもの
    UsageStatsManager usageStatsManager =
            (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE);

    // 現在時刻をCalendarオブジェクトとして取得する
    Calendar calendar = Calendar.getInstance();
    // calendarの時刻を午前0時に設定する
    // これにより、calendarが内包している時刻情報は、現在時刻から本日の午前0時となる
    calendar.set(Calendar.HOUR_OF_DAY, 0);

    // queryUsageStats(取得する時間の単位, 取得する時間の始まり、取得する時間の終わり)
    // 取得する時間の単位 : 日単位(INTERVAL_DAILY)、週単位(INTERVAL_WEEKLY)、月単位(INTERVAL_MONTHLY)、
    //                    年単位(INTERVAL_YEARLY)、自動選択(INTERVAL_BEST)がある
    // 
    // 取得する時間の始まり : 取得したいデータの時間帯のスタート地点。今回は、その日の午前0時。
    // 取得する時間の終わり : 取得したいデータの時間帯の終わり。今回は、現在時刻。
    return usageStatsManager.queryUsageStats(
            UsageStatsManager.INTERVAL_DAILY,
            calendar.getTimeInMillis(),
            System.currentTimeMillis());
  }

  // 外部から実行するための関数
  public void readOneDayUsageStats() {
    // アプリごとの使用情報をListとして取得
    List<UsageStats> usageStats = getUsageStatsObject();

    // for文を使用することで、usageStatに一つのアプリの使用情報を取得する
    for (UsageStats usageStat : usageStats) {
      // もし、そのアプリを一度も使用していない場合は、スキップする
      if (usageStat.getTotalTimeInForeground() == 0) {
        continue;
      }

      // Logcatで、取得した情報を出力する
      // package name : getPackageName() : そのアプリ固有のID
      // total time displayed : getTotalTimeInForeground() : そのアプリが画面上に表示された合計時間
      // first time : getFirstTimeStamp() : 取得したデータの始まりの時間をミリ秒で返す
      // getStringDate()を使ってミリ秒を人間にわかりやすい形に変換している
      // end time : getLastTimeUsed() : 取得したデータの終わりの時間をミリ秒で返す
      // getStringDate()を使ってミリ秒を、人間にわかりやすい形に変換している
      Log.d(TAG, "packageName: " + usageStat.getPackageName() + "\ttotalTimeDisplayed: " + usageStat.getTotalTimeInForeground()
          + "\tfirstTime: " + getStringDate(usageStat.getFirstTimeStamp()) + "\tlastTime: " + getStringDate(usageStat.getLastTimeUsed()));
    }
  }

  // long型のミリ秒をString型の人間がわかりやすい形に変換する
  private String getStringDate(long milliseconds) {
    final DateFormat df = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss", Locale.JAPANESE);
    final Date date = new Date(milliseconds);
    return df.format(date);
  }
}

実行結果

アプリごとの、時間が表示されています。
やったね!

D/UsageStatsClass: packageName: com.huawei.android.launcher totalTimeDisplayed: 3769989 firstTime: 2020/02/27 00:00:02  lastTime: 2020/02/27 15:59:00
D/UsageStatsClass: packageName: jp.naver.line.android   totalTimeDisplayed: 805413  firstTime: 2020/02/27 00:00:02  lastTime: 2020/02/27 15:34:36
D/UsageStatsClass: packageName: com.discord totalTimeDisplayed: 4247    firstTime: 2020/02/27 00:00:02  lastTime: 2020/02/27 15:43:05
D/UsageStatsClass: packageName: com.microsoft.office.outlook    totalTimeDisplayed: 43011   firstTime: 2020/02/27 00:00:02  lastTime: 2020/02/27 14:19:16
D/UsageStatsClass: packageName: com.google.android.packageinstaller totalTimeDisplayed: 2444    firstTime: 2020/02/27 00:00:02  lastTime: 2020/02/27 15:59:02
D/UsageStatsClass: packageName: com.google.android.apps.photos  totalTimeDisplayed: 283917  firstTime: 2020/02/27 00:00:02  lastTime: 2020/02/27 13:38:33
D/UsageStatsClass: packageName: com.spotify.music   totalTimeDisplayed: 6267989 firstTime: 2020/02/27 00:00:02  lastTime: 2020/02/27 13:56:21
D/UsageStatsClass: packageName: jp.mineo.app.phone  totalTimeDisplayed: 70175   firstTime: 2020/02/27 00:00:02  lastTime: 2020/02/27 13:59:50
D/UsageStatsClass: packageName: com.google.android.apps.translate   totalTimeDisplayed: 8170    firstTime: 2020/02/27 00:00:02  lastTime: 2020/02/27 15:04:14
D/UsageStatsClass: packageName: ch.bitspin.timely   totalTimeDisplayed: 798142  firstTime: 2020/02/27 00:00:02  lastTime: 2020/02/27 11:17:25
D/UsageStatsClass: packageName: com.android.settings    totalTimeDisplayed: 21715   firstTime: 2020/02/27 00:00:02  lastTime: 2020/02/27 14:32:32

参考文献

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

51歳からの(現52)プログラミング 備忘 3行 android ボタンにフォーカスを移動する

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

btn.setFocusable(true);
btn.setFocusableInTouchMode(true);
btn.requestFocusFromTouch();
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

余ったPCをVPNサーバにしてAndroidでPCゲームをしてみる

はじめに

AndroidでPCゲームがしたい!!
そんな夢を叶えてくれるのがSteamLink

しかしSteamLinkは同一ネットワーク内,所謂ローカルIPの末尾以外が同じ相手でしか使用できません.
そこで外部ネットワーク(自宅以外のWiFiなど)から接続するためにVPN(Virtual Private Network)を使います.

家に昔使っていたデスクトップPCが余っていたので今回はUbuntu18.04をインストールしてサーバとしました.

本記事は下記の記事を参考に躓いた点を追記していきます.

使用環境

サーバ用PC ゲーム実行用PC Android
OS Ubuntu18.04LTS Windows10 Android 9
CPU i7-4770 Ryzen 3900X Snapdragon845
RAM 24GB 32GB 6GB

+ これらを繋ぐルータ(LAN)

使用ソフト・アプリケーション

  • サーバ
  • ゲーム実行用PC
    • Steam
  • Android
    • SteamLink

導入方法

VPNサーバの導入は自分だけのVPNサーバを作る!Ubuntu 18.04 に SoftEther VPN Serverをインストールを元に追記したいと思います。

makeの追記

参考記事のとおりコピペしてしまうとvpnserverというファイルができてしまい,困惑するかもしれません.一度上の階層に移動し,解凍したフォルダを直接移動するという点が注意です.

$ cd vpnserver/
$ make
 ライセンスを読んで、同意するなら `1` と `Enter` を数回入力
$ cd ..
 --追記 解凍したフォルダごと移動することに注意
$ sudo mv vpnserver /usr/local
$ cd /usr/local/vpnserver/
$ sudo chmod 600 *
$ sudo chmod 700 vpncmd
$ sudo chmod 700 vpnserver

Port開放の追記

参考記事内ではファイアウォールの設定とPort開放が混同されていると感じましたので,ここでは分けて説明します.

  • Port
    • LAN内のプロトコル(ルール)を制御する門のようなもの.ネットワークに作用する.
    • 本記事においてはルータの設定に関係する.
  • ファイアウォール
    • コンピュータを守るための門のようなもの.自身(コンピュータ)に作用する.
    • 本記事においてはVPNサーバに関係する.

参考記事に記載されているufw(Uncomplicated FireWall)コマンドはファイアウォールの設定です.
VPNを実現するためには,ファイアウォールの設定とルータのポート開放も必要になります.ルータのポート開放については各ルータによって異なるため,ご自身で調べていただけると幸いです.ポート開放をするにあたってVPNサーバのローカルIPを固定する必要があることにご注意ください.

開放するPort番号

  • TCP
    • 5555 : デフォルトのリスナーポート
    • 443 : デフォルトのリスナーポート
    • 992 : デフォルトのリスナーポート
  • UDP
    • 1194 : OpenVPNを使う場合
    • 500 : L2TP/IPsecを使う場合
    • 4500 : L2TP/IPsecを使う場合

以降は参考記事のとおり導入してください.

Deamonの登録

Linuxでは常駐プロセスのことをデーモン(deamon)といいます.

$ sudo /usr/local/vpnserver/vpnserver stop
$ sudo vi /etc/systemd/system/vpnserver.service

viエディタが起動するのでaキーで入力モードにし,以下を入力します.

[Unit]
Description=SoftEther VPN Server
After=network.target
[Service]
Type=forking
ExecStart=/usr/local/vpnserver/vpnserver start
ExecStop=/usr/local/vpnserver/vpnserver stop
[Install]
WantedBy=multi-user.target

ESCを押した後:wqで保存します.

$ sudo systemctl daemon-reload
$ sudo systemctl enable vpnserver.service
$ sudo systemctl start vpnserver.service

AndroidからVPNサーバへ繋ぐ

  1. 設定からVPNの設定を探す.
  2. VPNの設定を追加し名前を適当につける.
  3. タイプをL2TP/IPSec PSKにする.
  4. サーバアドレスはグローバルIPを入力
  5. IPsec事前共有キーはVPNサーバで設定した共通キーを入力
  6. 登録したユーザ名とパスワードをそれぞれ入力
  7. 接続

繋がらないときはPort開放やVPNサーバのファイアウォール設定,入力間違いなどを確認してみてください.
繋がった場合,通常どおりSteamLinkを起動すると同一LAN内のゲーム実行用PCが認識されるはずです.

まとめ

SoftEther VPNを使ってUbuntu18.04でVPNサーバを建てました.
VPNサーバを利用するためにはPort開放とファイアウォール設定の二つが必要です.
Port開放を行う前にVPNサーバのローカルIPを固定する必要があります.
接続にはグローバルIPを使います.

これでAndroidでいつでもPCゲームができるようになりました!
もちろんPCゲーム以外の用途でも利用可能です.
最後にもう一度参考にした記事を記載します.

参考記事

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[AndroidStudio]仮想端末が起動しない件と対応(adbコマンドのログファイル)[ANDROID_SDK_ROOT]

概要

Androidアプリの開発欲が再燃したので放置していたAndroidStudioを起動し、最新にアップデートをしたが
仮想端末が起動しないため、その原因の確認と対応をした。
紆余曲折あったがADVマネージャーのログが見つかったので確認。

結果としては「C:\Users」の配下にあるユーザ名のフォルダが日本語であったため、仮想端末の起動に必要なファイルが読み込めなかった。
そのため、仮想端末が起動できなかった。
該当フォルダ名とユーザ名をアルファベット表記にすることで起動できることが確認できた。

備忘録として以下に今回の内容を記載します。

環境

今回使用した環境は以下になります。

  • メインマシン
    • Intel Core i7-6700k
    • Windows10 Home
    • AndroidStudio 3.5(後に3.6にアップグレード)
  • サブマシン
    • Intel Core i7-2600k
    • Windows10 Pro
    • AndroidStudio 3.5(後に3.6にアップグレード)

事象

AndroidStudioを起動し、バージョン3.5へアップグレード。
ADVマネージャーを起動。以前作成した仮想端末を起動ボタンをクリックするがイベントログに以下のエラーが表示し起動しない。

エミュレーター: PANIC: Cannot find AVD system path. Please define ANDROID_SDK_ROOT
エミュレーター: プロセスは終了コード1で終了しました

2行目は定型文だが、1行目はググったところ、「ANDROID_SDK_ROOT」のパスが設定されていないので発生するエラー部分なので、自分で環境変数を設定した。
設定場所はAndroidStudio上に設定されているAndroid SDKロケーションのパスを設定。
(ロケーションのパス自体が設定されていない場合はSDKマネージャーからAndroid SDKをインストールして下さい)

設定後に再度ADVマネージャーから仮想端末を起動させると以下のエラー文に変わった。

エミュレーター: panic: broken avd system path. check your android_sdk_root value [(SDKロケーションのフォルダパス)]!
エミュレーター: プロセスは終了コード1で終了しました

上記のエラー文で再度ググると、ADVのシステムが壊れている、もしくは見つからないので起動に失敗している。
調べた限りのOS側の環境変数を設定するかSDKをAndroidStudioからインストールすれば直るとある。
色々手を尽くしたが上記のエラーが解消されずに仮想端末が起動できなかった。


ここまでの事象を環境の項目で記載したメインマシンで確認。
サブマシンにAndroidStudioを新規でインストール。
JDKすらインストールせずにそのまま仮想端末を起動すると無事に起動できたので、
メインとサブの環境の差異から原因を推測。

調査

今回のエラーの調査の内容を以下に箇条書きで書き出します。

  1. システム環境変数に「ANDROID_SDK_ROOT」を追加。パスはAndroid SDKロケーション
  2. システム環境変数に「ANDROID_HOME」を追加。
  3. JAVA_HOMEと関連のシステム環境変数を削除
  4. JDKを削除して、AndoroidStudioのデフォルトプロジェクト構造のjdkロケーションをAndoroidStudioの内蔵のものに変更。
  5. CPUがIntel VTへ対応しているか確認(メインサブ共に対応していました)
  6. Hyper-Vが関係しているかの確認。(HAXMがインストールされているならば有効でも無効でも問題ありませんでした)
  7. AndoroidStudioとSDKを削除して再インストール。

内容は長いのと関係のない部分が多かったので
以下に要点を記載します。内容は解決までの逆順です。


ログファイル

紆余曲折ありましたが、以下のユーザの一時フォルダに
adbコマンドのログファイルが置かれるのが分かったので内容を確認

C:\Users\(ユーザ名)\AppData\Local\Temp\adb.log

AndroidStudio上のイベントログに表示されていないエラー内容があり

--- adb starting (pid 40640) ---
adb I 02-26 15:38:02 40640 40364 main.cpp:60] Android Debug Bridge version 1.0.41
adb I 02-26 15:38:02 40640 40364 main.cpp:60] Version 29.0.6-6198805
adb I 02-26 15:38:02 40640 40364 main.cpp:60] Installed as D:\Android\sdk\platform-tools\adb.exe
adb I 02-26 15:38:02 40640 40364 main.cpp:60] 
adb I 02-26 15:38:02 40640 40364 auth.cpp:437] adb_auth_init...
adb I 02-26 15:38:02 40640 40364 auth.cpp:262] User key 'C:\Users\(ユーザー名)\.android\adbkey' does not exist...
adb I 02-26 15:38:02 40640 40364 auth.cpp:97] generate_key(C:\Users\(ユーザー名)\.android\adbkey)...
adb server killed by remote request

上記のログの中で上から7行目が「adbkey」が存在しないと出ているため
実際にフォルダを確認し該当ファイルが存在するか確認。
ファイルは存在していたので何らかの原因で読み込めないと理解。


フォルダの日本語名について

サブマシンにて仮想端末が起動できたことでメインマシンとの差分を確認し、
SDKが読み込めていないのが原因と予測し、サブマシンと同じ位置に移動しようとするが
メインマシンで同じフォルダにインストールしようと該当フォルダを選択するとエラーでインストールができなかった。

Your SDK location cantains non-ASCII characters.

ググるとパスに日本語が入っていると上記のエラーが発生する。
今回はメインマシンのユーザ名が日本語のためインストールができない模様。


これと同様に仮想端末を起動するときに「adbkey」が読み込めなかったのはファイルまでのパスに日本語が入っているため
読み込めずに仮想端末が起動しなかった模様。

対応

フォルダ名のユーザ名が日本語なので仮想端末が起動しないことが分かったので

  1. アルファベット表記のアカウントを新しく作成しそちらに移る。
  2. アカウントのユーザ名、フォルダ名、レジストリを全て変更する。

1.をするために新しくアカウントを作成しましたが、ユーザの再設定、アカウント毎のアプリケーションの再インストールがかなり大変そうなので
2.を採用。

以下、参考サイトになります。

  1. Adoministratorアカウントをコマンドから使用できるように設定を変更し、
  2. 「netplwiz」をユーザーアカウントの変更画面を呼び出し、ユーザ名をアルファベット表記に変更。
  3. 更にレジストリの 「HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList」を参照し、変更前のユーザ名をアルファベット表記に変更。
  4. Adoministratorアカウントにログインし、ユーザフォルダのフォルダ名をアルファベット表記に変更。
  5. 再起動後、レジストリの変更前のユーザ名で記載されている個所を全てアルファベット表記に変更。

最後のレジストリ修正が100か所を超えてたいのでとても大変でした。
作業時間は1時間~2時間くらいかかりました。
ですが、再設定、再インストール作業をせずにフォルダ名が変更できたことが確認でき、各アプリケーションも問題なく動作しました。

しかし、今回はレジストリ修正前にブラウザを立ち上げてしまったので一部のブックマークとログが消えてしまったのでバックアップの取得はしておくべきと反省する。

後書き

一通り書き終わってみると、原因はユーザが日本語名であった一点につきましたが色々と調べてかなり遠回りしました。

パスに日本語が入っているとエラーが出るというのは割と初歩的なミスであるが発見できるまで随分時間がかかってしまった。
時間がかかった理由は、SDKをCまたはDドライブの直下に置いていたのと、イベントログに詳しいログが出力されなかったのがある。

とりあえず、adbのログファイルが見つけられたので、そこは今後の開発作業に活かしたい。

また、同じような内容で困っている人がいるなら今回の体験が解決の糸口になることを祈ります。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Pixel3a_Android開発ーAOSP環境構築フレームワークビルド、カーネルビルド、ROM焼くまで

はじめ

忘れないように記録しただけ、参考は慎重に。
色々を試しながらやって成功したので、分かっていない部分もある。
とりあえずできたからよし。

ソースコードは先にエミュレータでやってみた。
そして、実際の端末に応じたバージョンでやった。
本編もそのタイムラインに添って記録。

参考したサイト:
AOSP環境構築 [備忘録]

環境

OS:ubuntu18.04-LTS
NDK:r17
端末:Pixel3aのエミュレータ
フレームワークバージョン :android-9.0.0_r42
カーネルバージョン : android-msm-bonito-4.9-pie-b4s4

環境

OS:ubuntu18.04-LTS
NDK:17
端末:Pixel3a
フレームワークバージョン : PQ3B.190705.003 android-9.0.0_r45
カーネルバージョン : android-msm-bonito-4.9-pie-b4s4

上記のバージョンにした理由:
  端末に焼くため、変なことがないように念のため、既存バージョンと統一した。

注意:フレームワークとカーネルが対象端末に適用していることを確認すること。

参考:
コード名、タグ、ビルド番号
カーネルのビルド

AOSP環境構築

参考したサイト:
AOSP環境構築 [備忘録]
android源码编译

JDKインストール

sudo apt-get update
sudo apt-get install openjdk-8-jdk

環境インストール

ここはよくわからないけど、とりあえず全部やっといた。
sudo apt-get install -y git flex bison gperf build-essential libncurses5-dev:i386
sudo apt-get install libx11-dev:i386 libreadline6-dev:i386 libgl1-mesa-dev g++-multilib
sudo apt-get install tofrodos python-markdown libxml2-utils xsltproc zlib1g-dev:i386
sudo apt-get install dpkg-dev libsdl1.2-dev libesd0-dev
sudo apt-get install git-core gnupg flex bison gperf build-essential
sudo apt-get install zip curl zlib1g-dev gcc-multilib g++-multilib
sudo apt-get install libc6-dev-i386
sudo apt-get install lib32ncurses5-dev x11proto-core-dev libx11-dev
sudo apt-get install lib32z-dev ccache
sudo apt-get install libgl1-mesa-dev libxml2-utils xsltproc unzip m4
sudo apt-get install libswitch-perl
sudo apt-get install git-core gawk

NDKインストール

NDK のダウンロード
r19以上だとソースコードをコンパイルに使うgccを対応していないので、r17を使用した。
https://dl.google.com/android/repository/android-ndk-r17-linux-x86_64.zip

/home/Android/Android_NDKまで圧縮し、.bashrcに以下のコードを追加する。
export NDK_HOME=/home/eimin/Android/Android_NDK/android-ndk-r17
export PATH=$NDK_HOME:$PATH

source ~/.bashrc
で保存する。
テスト:
$ echo $NDK
$ ndk-build -v

GNU Make 3.81
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
これが出たら大丈夫。

エミュレータのKVMの設定

これは多分エミュレータを使用する場合のものなので、端末だといらないと思う。
sudo apt install -y qemu-kvm libvirt0 libvirt-bin virt-manager bridge-utils
sudo adduser username kvm

AOSPソースコードダウンロード

mkdir ~/bin
cd ~/bin/
PATH=~/bin:$PATH
echo "PATH=~/bin:\$PATH" >> ~/.bashrc
source ~/.bashrc
curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
chmod a+x ~/bin/repo

フォルダを作る
mkdir android-9.0.0_r42
cd android-9.0.0_r42

usernameとemailの登録
git config --global user.email "emailaddress"
git config --global user.name "username"
repo init -u https://android.googlesource.com/platform/manifest -b android-9.0.0_r42
repo sync -j8

j8はマルチスレッドのこと、CPUは4コアだったのでかける2で8にした。処理が速くなる。ここの数字は必ず入れる、何も入れないとたまに壊れる。ここでCPUフルで数時間処理するから、寝る前にやったほうがいい。

ここまではソースコードの同期が終了。

ビルド

source build/envsetup.sh
lunch aosp_x86_64-eng

毎回エミュレータで開くときや、OSが新しく起動した後は、必ずandroid-9.0.0_r42フォルダにsourceを実行する。
lunchだけを打つとリスト一覧が出る。これは対象端末に合わせる必要がある。エミュレータの場合は上記で大丈夫です。例えばPixel3aに焼くためだと、aosp_sargo-userdebugを選ばなければいけない

注意:
 emulator -avd Pixel_3a_noAPI \
-show-kernel -kernel kernel/goldfish/arch/x86/boot/bzImage \
-system /home/eimin/android-9.0.0_r42/out/target/product/generic_x86_64/system.img \
-ramdisk /home/eimin/android-9.0.0_r42/out/target/product/generic_x86_64/ramdisk.img \
-data /home/eimin/android-9.0.0_r42/out/target/product/generic_x86_64/userdata.img

参考:
ビルド構成

エミュレータ実行

cd android-9.0.0_r42
source build/envsetup.sh
lunch aosp_x86_64-eng
emulator -gpu off

emulatorのコマンドを使うにはAndroid Studioの仮想エミュレータのツールとkitの環境が必要。あらかじめインストールすること。
gpu offは2562 MB > 800 MBこのような問題を解決するためにつけたもの。

Android Studioを用いてソースコードを導入する

参考:
使用Android Studio导入Android系统源码

ccacheの設置

ccacheは大きく設定することで導入が速くなる効果があるみたいですが、
実際そんなに実感しなかった。

sudo apt-get install ccache
cd android-9.0.0_r42
(ccache -s これでccacheの状態確認)

/home/wonder/.bashrcに
export USE_CCACHE=1 保存してsource .bashrc
そして
cd android-9.0.0_r42
prebuilts/misc/linux-x86/ccache/ccache -M 50G
ccache -sで50Gになってることが確認できる

導入開始

主に参考サイト通りにやれば大丈夫。

source build/envsetup.sh
lunch aosp_x86_64-eng
make idegen -j4
sudo development/tools/idegen/idegen.sh

ここで少し時間かかる。壊れてないから待つぞ。
終わったら、フォルダに新しく android.iml,android.ipr,android.iws が生成される。
多分only readでロックされているので、それを解錠する。
sudo chmod 777 android.iml
sudo chmod 777 android.ipr

そして
Android Studioを開いて、
open an existing Android Studio projectを選択し、
android.iprを選ぶ。
このままだと、android.imlに記載してあるすべてのファイルをimportすることになるので、かなり時間がかかる。
もしすべてのものがいらないのであれば、android.imlを編集し、必要なものだけを残す。

やり方:

android.imlを開いて、orderEntryを検索し、

</content>
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="inheritedJdk" />
<orderEntryProperties />
</component>
</module>

この三行だけを残して、他は全部消す。

excludeFolderを検索し、必要なものだけを残す、他はコメントアウトする。
ここもかなりの量だったので、万が一のため、俺はここでいじらなく、Android Studioの中で設定した。

設定方法:
iprを開いて、File->Project Structure
Modules->androidのフォルダを選択する。
中のsourceを選択し、いらないフォルダを選択し、excludeを選択すればこれらが排除される。この時フォルダはorange色になる。
excludeしたフォルダをincludeするために、対象フォルダを選択し青色のsourceを選択すればblue色になる。これはincludeされている。
俺はexternalとframeworkだけをincludeした。他を全部excludeした。

他にprojectなどいろいろな設定が必要。図を載せておく。

2020-02-06 20-00-05 的屏幕截图.png
2020-02-06 20-01-00 的屏幕截图.png
2020-02-06 20-01-24 的屏幕截图.png
2020-02-06 20-01-36 的屏幕截图.png
2020-02-06 20-01-46 的屏幕截图.png
2020-02-06 20-02-18 的屏幕截图.png

SDKの設定

2020-02-06 20-04-05 的屏幕截图.png
2020-02-06 20-04-12 的屏幕截图.png

以上でAndroid Studioにソースコードの導入が終わる。

Android Studioの使い方

ファイル保存したか をわかるための点の設定。ファイル数を20に設定した。
2020-02-06 20-11-18 的屏幕截图.png

二回shiftを押すとファイル名検索。
ctrl+shift+fは全ファイル内容の検索。

これでframeworkをいじって保存することを簡単にできる。

framework編集後のビルド

ここは大事。
android studio上だとビルドができない、コマンドでビルドする。
いつも通り、source lunchして

make update-api
mmm frameworks/base
make -j4   ここのj4は必要、何も書かないと問題があるかもしれない。

これでビルドを行う。

説明:
make update-apiは必ず必要ではない、ビルド通らない時にupdate-apiのエラー文が提示してくれるので、提示されたらこれを加えれば大丈夫。
mmm frameworks/baseというものについて、baseの下にandroid.bp,android.mkというファイルが存在する。これらは何をビルドするのかを記録してあるファイル、いわゆるルールみたいなもの。
mmmすると、これらのルールに沿ってファイルたちをpackageする。新しく加えたファイルはpackageされる。
make -j4ではandroidソースコードを全部ビルドする意味。
mmmしないとmake -j4だけでは、新しく編集したものは反映されない。コンパイルされていないからだ。

ビルド後に生成されたファイル

/android-9.0.0_r42/out/target/product/generic_x86_64 この下にある。
知っておくといいものはsystem ramdisk userdataぐらい。

imgをエミュレータで開く

ここは重要。
makeした後に上記のフォルダにimgが生成される。
エミュレターで開く時では
emulator -gpu offを使うだが、開いても今生成されたimgが読みこまれない。
which emulator で調べればどこのemulatorなのかはわかる。

これはAndroid/Sdk/system-images/android-28/google_apis/x86_64 したのsystem.imgを読みこんでるからだ。
生成されたファイルを読むために、
android-9.0.0下のsystem-qemu.imgを上記x86_64フォルダの下にコピペーして、
system-qemu.imgをsystem.imgに名前を変更し、本来x86_64のsystem.imgと置き換える。
こうすれば、emulator -gpu off すると生成されたimgが読みこまれる。

ここは必ずsystem-qemu.imgをコピペーする、他のimgは変更しなくても大丈夫。

ここまではソースコードをASに導入し、エミュレータで開く方法だ。

カーネルのビルド

以下では実機のカーネルのビルドのしかた、エミュレータ用はまた違う。
https://source.android.com/setup/start/build-numbers#source-code-tags-and-builds
https://source.android.com/setup/build/building-kernels
このサイトを見て、どの実機のどのバージョンを調べてやり方に沿ってやれば大丈夫。
https://developers.google.com/android/drivers
このサイトにドライバをダウンロードし、フレームワークフォルダに入れてビルドしなければいけない。

ドライバを入れたら、
make -j4 clean し、前までビルドしたものを全部消す。
そして全体をmake -j4 こうすれば、入れたドライバvendorがビルドされる。

注意:フレームワークをgitする時にrepoを使ったので、
カーネルのフォルダはフレームワークのフォルダと別にする。
そうすればrepo二回で被らなく余計なミスが生じない。

そして、フレームワークとカーネルを実機にflashする。

ここで私の場合ではflash成功したが、画面のtouchscreenが反応しなかった。これはカーネルをビルドするときに、touchscreenのドライバが一緒にflashできなかったから。
https://groups.google.com/forum/#!msg/android-building/ou630PviyDc/hrVc8dv2DwAJ
このサイトを参考し、
adb push /home/eimin/arm_kernel/out/android-msm-bonito-4.9/dist/*.ko /vendor/lib/modules
で、画面がタッチできるようになった。再起動したらまた消えるが。

GMSを入れるために、twrpを用いてgappsを入れた。
twrpとgappsのzipをadb pushで/sdcardのしたに置き、
fastboot boot twrp-3.3.1-1-sargo.imgでtwrpに入る。(twrpの入り方はこれしかないみたい)
そして、install gappsのzip
clean davilk
reboot
すごく待ったら問題なく開けた。

GMSが止まる、使えない場合:
https://stackoverflow.com/questions/5486694/getting-android-device-identifier-from-adb-and-android-sdk
https://www.google.com/android/uncertified/
実機のDevice IDが登録する必要がある。登録すれば使えるはず。

以上でandroidをromし、Gappsを入れるまででした。

自分用に書いたので、思った分を書いた。また時間があったら整理する。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Androidフレームワークビルド、カーネルビルド、ROM焼くまで-Pixel3aを用いた

はじめ

忘れないように記録しただけ、参考は慎重に。
色々を試しながらやって成功したので、分かっていない部分もある。
とりあえずできたからよし。

ソースコードは先にエミュレータでやってみた。
そして、実際の端末に応じたバージョンでやった。
本編もそのタイムラインに添って記録。

参考したサイト:
AOSP環境構築 [備忘録]

環境

OS:ubuntu18.04-LTS
NDK:r17
端末:Pixel3aのエミュレータ
フレームワークバージョン :android-9.0.0_r42
カーネルバージョン : android-msm-bonito-4.9-pie-b4s4

環境

OS:ubuntu18.04-LTS
NDK:17
端末:Pixel3a
フレームワークバージョン : PQ3B.190705.003 android-9.0.0_r45
カーネルバージョン : android-msm-bonito-4.9-pie-b4s4

上記のバージョンにした理由:
  端末に焼くため、変なことがないように念のため、既存バージョンと統一した。

注意:フレームワークとカーネルが対象端末に適用していることを確認すること。

参考:
コード名、タグ、ビルド番号
カーネルのビルド

AOSP環境構築

参考したサイト:
AOSP環境構築 [備忘録]
android源码编译

JDKインストール

sudo apt-get update
sudo apt-get install openjdk-8-jdk

環境インストール

ここはよくわからないけど、とりあえず全部やっといた。
sudo apt-get install -y git flex bison gperf build-essential libncurses5-dev:i386
sudo apt-get install libx11-dev:i386 libreadline6-dev:i386 libgl1-mesa-dev g++-multilib
sudo apt-get install tofrodos python-markdown libxml2-utils xsltproc zlib1g-dev:i386
sudo apt-get install dpkg-dev libsdl1.2-dev libesd0-dev
sudo apt-get install git-core gnupg flex bison gperf build-essential
sudo apt-get install zip curl zlib1g-dev gcc-multilib g++-multilib
sudo apt-get install libc6-dev-i386
sudo apt-get install lib32ncurses5-dev x11proto-core-dev libx11-dev
sudo apt-get install lib32z-dev ccache
sudo apt-get install libgl1-mesa-dev libxml2-utils xsltproc unzip m4
sudo apt-get install libswitch-perl
sudo apt-get install git-core gawk

NDKインストール

NDK のダウンロード
r19以上だとソースコードをコンパイルに使うgccを対応していないので、r17を使用した。
https://dl.google.com/android/repository/android-ndk-r17-linux-x86_64.zip

/home/Android/Android_NDKまで圧縮し、.bashrcに以下のコードを追加する。
export NDK_HOME=/home/eimin/Android/Android_NDK/android-ndk-r17
export PATH=$NDK_HOME:$PATH

source ~/.bashrc
で保存する。
テスト:
$ echo $NDK
$ ndk-build -v

GNU Make 3.81
Copyright (C) 2006 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.
There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE.
これが出たら大丈夫。

エミュレータのKVMの設定

これは多分エミュレータを使用する場合のものなので、端末だといらないと思う。
sudo apt install -y qemu-kvm libvirt0 libvirt-bin virt-manager bridge-utils
sudo adduser username kvm

AOSPソースコードダウンロード

mkdir ~/bin
cd ~/bin/
PATH=~/bin:$PATH
echo "PATH=~/bin:\$PATH" >> ~/.bashrc
source ~/.bashrc
curl https://storage.googleapis.com/git-repo-downloads/repo > ~/bin/repo
chmod a+x ~/bin/repo

フォルダを作る
mkdir android-9.0.0_r42
cd android-9.0.0_r42

usernameとemailの登録
git config --global user.email "emailaddress"
git config --global user.name "username"
repo init -u https://android.googlesource.com/platform/manifest -b android-9.0.0_r42
repo sync -j8

j8はマルチスレッドのこと、CPUは4コアだったのでかける2で8にした。処理が速くなる。ここの数字は必ず入れる、何も入れないとたまに壊れる。ここでCPUフルで数時間処理するから、寝る前にやったほうがいい。

ここまではソースコードの同期が終了。

ビルド

source build/envsetup.sh
lunch aosp_x86_64-eng

毎回エミュレータで開くときや、OSが新しく起動した後は、必ずandroid-9.0.0_r42フォルダにsourceを実行する。
lunchだけを打つとリスト一覧が出る。これは対象端末に合わせる必要がある。エミュレータの場合は上記で大丈夫です。例えばPixel3aに焼くためだと、aosp_sargo-userdebugを選ばなければいけない

注意:
 emulator -avd Pixel_3a_noAPI \
-show-kernel -kernel kernel/goldfish/arch/x86/boot/bzImage \
-system /home/eimin/android-9.0.0_r42/out/target/product/generic_x86_64/system.img \
-ramdisk /home/eimin/android-9.0.0_r42/out/target/product/generic_x86_64/ramdisk.img \
-data /home/eimin/android-9.0.0_r42/out/target/product/generic_x86_64/userdata.img

参考:
ビルド構成

エミュレータ実行

cd android-9.0.0_r42
source build/envsetup.sh
lunch aosp_x86_64-eng
emulator -gpu off

emulatorのコマンドを使うにはAndroid Studioの仮想エミュレータのツールとkitの環境が必要。あらかじめインストールすること。
gpu offは2562 MB > 800 MBこのような問題を解決するためにつけたもの。

Android Studioを用いてソースコードを導入する

参考:
使用Android Studio导入Android系统源码

ccacheの設置

ccacheは大きく設定することで導入が速くなる効果があるみたいですが、
実際そんなに実感しなかった。

sudo apt-get install ccache
cd android-9.0.0_r42
(ccache -s これでccacheの状態確認)

/home/wonder/.bashrcに
export USE_CCACHE=1 保存してsource .bashrc
そして
cd android-9.0.0_r42
prebuilts/misc/linux-x86/ccache/ccache -M 50G
ccache -sで50Gになってることが確認できる

導入開始

主に参考サイト通りにやれば大丈夫。

source build/envsetup.sh
lunch aosp_x86_64-eng
make idegen -j4
sudo development/tools/idegen/idegen.sh

ここで少し時間かかる。壊れてないから待つぞ。
終わったら、フォルダに新しく android.iml,android.ipr,android.iws が生成される。
多分only readでロックされているので、それを解錠する。
sudo chmod 777 android.iml
sudo chmod 777 android.ipr

そして
Android Studioを開いて、
open an existing Android Studio projectを選択し、
android.iprを選ぶ。
このままだと、android.imlに記載してあるすべてのファイルをimportすることになるので、かなり時間がかかる。
もしすべてのものがいらないのであれば、android.imlを編集し、必要なものだけを残す。

やり方:

android.imlを開いて、orderEntryを検索し、

</content>
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="inheritedJdk" />
<orderEntryProperties />
</component>
</module>

この三行だけを残して、他は全部消す。

excludeFolderを検索し、必要なものだけを残す、他はコメントアウトする。
ここもかなりの量だったので、万が一のため、俺はここでいじらなく、Android Studioの中で設定した。

設定方法:
iprを開いて、File->Project Structure
Modules->androidのフォルダを選択する。
中のsourceを選択し、いらないフォルダを選択し、excludeを選択すればこれらが排除される。この時フォルダはorange色になる。
excludeしたフォルダをincludeするために、対象フォルダを選択し青色のsourceを選択すればblue色になる。これはincludeされている。
俺はexternalとframeworkだけをincludeした。他を全部excludeした。

他にprojectなどいろいろな設定が必要。図を載せておく。

2020-02-06 20-00-05 的屏幕截图.png
2020-02-06 20-01-00 的屏幕截图.png
2020-02-06 20-01-24 的屏幕截图.png
2020-02-06 20-01-36 的屏幕截图.png
2020-02-06 20-01-46 的屏幕截图.png
2020-02-06 20-02-18 的屏幕截图.png

SDKの設定

2020-02-06 20-04-05 的屏幕截图.png
2020-02-06 20-04-12 的屏幕截图.png

以上でAndroid Studioにソースコードの導入が終わる。

Android Studioの使い方

ファイル保存したか をわかるための点の設定。ファイル数を20に設定した。
2020-02-06 20-11-18 的屏幕截图.png

二回shiftを押すとファイル名検索。
ctrl+shift+fは全ファイル内容の検索。

これでframeworkをいじって保存することを簡単にできる。

framework編集後のビルド

ここは大事。
android studio上だとビルドができない、コマンドでビルドする。
いつも通り、source lunchして

make update-api
mmm frameworks/base
make -j4   ここのj4は必要、何も書かないと問題があるかもしれない。

これでビルドを行う。

説明:
make update-apiは必ず必要ではない、ビルド通らない時にupdate-apiのエラー文が提示してくれるので、提示されたらこれを加えれば大丈夫。
mmm frameworks/baseというものについて、baseの下にandroid.bp,android.mkというファイルが存在する。これらは何をビルドするのかを記録してあるファイル、いわゆるルールみたいなもの。
mmmすると、これらのルールに沿ってファイルたちをpackageする。新しく加えたファイルはpackageされる。
make -j4ではandroidソースコードを全部ビルドする意味。
mmmしないとmake -j4だけでは、新しく編集したものは反映されない。コンパイルされていないからだ。

ビルド後に生成されたファイル

/android-9.0.0_r42/out/target/product/generic_x86_64 この下にある。
知っておくといいものはsystem ramdisk userdataぐらい。

imgをエミュレータで開く

ここは重要。
makeした後に上記のフォルダにimgが生成される。
エミュレターで開く時では
emulator -gpu offを使うだが、開いても今生成されたimgが読みこまれない。
which emulator で調べればどこのemulatorなのかはわかる。

これはAndroid/Sdk/system-images/android-28/google_apis/x86_64 したのsystem.imgを読みこんでるからだ。
生成されたファイルを読むために、
android-9.0.0下のsystem-qemu.imgを上記x86_64フォルダの下にコピペーして、
system-qemu.imgをsystem.imgに名前を変更し、本来x86_64のsystem.imgと置き換える。
こうすれば、emulator -gpu off すると生成されたimgが読みこまれる。

ここは必ずsystem-qemu.imgをコピペーする、他のimgは変更しなくても大丈夫。

ここまではソースコードをASに導入し、エミュレータで開く方法だ。

カーネルのビルド

以下では実機のカーネルのビルドのしかた、エミュレータ用はまた違う。
https://source.android.com/setup/start/build-numbers#source-code-tags-and-builds
https://source.android.com/setup/build/building-kernels
このサイトを見て、どの実機のどのバージョンを調べてやり方に沿ってやれば大丈夫。
https://developers.google.com/android/drivers
このサイトにドライバをダウンロードし、フレームワークフォルダに入れてビルドしなければいけない。

ドライバを入れたら、
make -j4 clean し、前までビルドしたものを全部消す。
そして全体をmake -j4 こうすれば、入れたドライバvendorがビルドされる。

注意:フレームワークをgitする時にrepoを使ったので、
カーネルのフォルダはフレームワークのフォルダと別にする。
そうすればrepo二回で被らなく余計なミスが生じない。

そして、フレームワークとカーネルを実機にflashする。

ここで私の場合ではflash成功したが、画面のtouchscreenが反応しなかった。これはカーネルをビルドするときに、touchscreenのドライバが一緒にflashできなかったから。
https://groups.google.com/forum/#!msg/android-building/ou630PviyDc/hrVc8dv2DwAJ
このサイトを参考し、
adb push /home/eimin/arm_kernel/out/android-msm-bonito-4.9/dist/*.ko /vendor/lib/modules
で、画面がタッチできるようになった。再起動したらまた消えるが。

GMSを入れるために、twrpを用いてgappsを入れた。
twrpとgappsのzipをadb pushで/sdcardのしたに置き、
fastboot boot twrp-3.3.1-1-sargo.imgでtwrpに入る。(twrpの入り方はこれしかないみたい)
そして、install gappsのzip
clean davilk
reboot
すごく待ったら問題なく開けた。

GMSが止まる、使えない場合:
https://stackoverflow.com/questions/5486694/getting-android-device-identifier-from-adb-and-android-sdk
https://www.google.com/android/uncertified/
実機のDevice IDが登録する必要がある。登録すれば使えるはず。

以上でandroidをromし、Gappsを入れるまででした。

自分用に書いたので、思った分を書いた。また時間があったら整理する。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ViewModelにLiveDataとMutableLiveDataを同時に宣言しなくていいようにする

MainViewModelからMutableLiveDataのみを扱い、LiveDataの宣言をしなくていいようにします。

変更前のコード

class MainViewModel() : ViewModel() {
    private val _param = MutableLiveData<MainViewParam>()
    val param: LiveData<MainViewParam>
        get() = _param

    fun load() {
        viewModelScope.launch {
            delay(1000L)
            _param.value = MainViewParam(
                nickname = "タロー",
                firstName = "太郎",
                lastName = "山田",
                age = 22,
                birthMonthOfYear = "11",
                birthDayOfMonth = "12",
                address = "東京都世田谷区",
                isPremium = false
            )
        }
    }
}

data class MainViewParam (
    val nickname: String,
    val firstName: String,
    val lastName: String,
    val age: Int,
    val birthMonthOfYear: String,
    val birthDayOfMonth: String,
    val address: String,
    val isPremium: Boolean
)
<?xml version="1.0" encoding="utf-8"?>
<layout
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>
        <variable
            name="viewmodel"
            type="com.example.mvvmlab.MainViewModel" />
    </data>


    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@{viewmodel.param.nickname}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

LiveDataを追い出す解決策

interfaceを利用すればすぐにできます。なおレイアウトXMLの変更は不要です。

interface MainViewModel {
    val param: LiveData<MainViewParam>
    fun load()
}

class MainViewModelImpl : ViewModel(), MainViewModel {
    override val param = MutableLiveData<MainViewParam>()
    override fun load() {
        viewModelScope.launch {
            delay(1000L)
            param.value = MainViewParam(
                nickname = "タロー",
                firstName = "太郎",
                lastName = "山田",
                age = 22,
                birthMonthOfYear = "11",
                birthDayOfMonth = "12",
                address = "東京都世田谷区",
                isPremium = false
            )
        }
    }
}

data class MainViewParam (
    val nickname: String,
    val firstName: String,
    val lastName: String,
    val age: Int,
    val birthMonthOfYear: String,
    val birthDayOfMonth: String,
    val address: String,
    val isPremium: Boolean
)

正直どっちでもいいのですが、ViewModelにLiveData/MutableLiveDataの宣言数が増えてちょっと嫌だなーって思って作って意外と悪くなかったので、もし同じ課題を抱えているのであれば一つの選択肢としてみてはどうでしょうか?
interface増やす必要あるの?みたいな増えるのが嫌そーな反応があればむりにねじ込むようなものではないと思います。

それ以外のコード

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.*
import com.example.mvvmlab.databinding.ActivityMainBinding
import kotlinx.coroutines.delay
import kotlinx.coroutines.launch

class MainActivity : AppCompatActivity() {

    private val viewModel :MainViewModel by lazy {
        ViewModelProvider.NewInstanceFactory().create(MainViewModelImpl::class.java)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        val binding: ActivityMainBinding =
            DataBindingUtil.setContentView(this, R.layout.activity_main)
        binding.viewmodel = viewModel
        binding.lifecycleOwner = this
        viewModel.loadUser()
    }
}

今回のコードに不要な物も入れていますが、よしなに対応してください。

apply plugin: 'com.android.application'

apply plugin: 'kotlin-android'

apply plugin: 'kotlin-android-extensions'

android {
    compileSdkVersion 29
    buildToolsVersion "29.0.2"
    defaultConfig {
        applicationId "com.example.mvvmlab"
        minSdkVersion 28
        targetSdkVersion 29
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    dataBinding {
        enabled = true
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation"org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"

    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.3'
    implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.3"

    implementation 'androidx.appcompat:appcompat:1.1.0'
    implementation 'androidx.core:core-ktx:1.2.0'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    // https://mvnrepository.com/artifact/androidx.lifecycle/lifecycle-livedata
    implementation 'androidx.lifecycle:lifecycle-livedata:2.2.0'
    implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0'
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0"
    implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
    implementation 'androidx.activity:activity-ktx:1.1.0'

    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MacのPCからADBコマンドを利用できるようにする(すでにJavaがPCに入っている人向け)

目的

  • Android Debug Bridge(以後ADBと呼称する)のコマンドを使用できるようにする方法をまとめる

実施方法概要

  1. Android Studioのインストール
  2. コマンドのパス通し

実施方法詳細

  1. Android Studioのインストール
    1. 下記のリンク先にアクセスする。
    2. 画面中央の「DOWNLOAD ANDROID STUDIO」をクリックしてダウンロードを行う。 スクリーンショット 2020-02-26 23.03.35.png
    3. 利用規約に目を通し「上記の利用規約を読んだうえで利用規約に同意します。」にちぇっくを入れて「ダウンロードする: ANDROID STUDIO(MAC用)」をクリックする。 スクリーンショット 2020-02-26 23.06.08(2).png
    4. ダウンロードが開始されるので完了するまで待機する。 スクリーンショット 2020-02-26 23.07.49.png
    5. ダウンロードしたインストーラーをダブルクリックで起動する。 スクリーンショット 2020-02-26 23.29.55.png
    6. 下記のウインドウが開いたらウインドウ内の「Android Studio.app」のアイコンをウインドウ内の「Applications」にドラックする。 スクリーンショット 2020-02-26 23.31.24.png
    7. アプリケーションフォルダを開き「Android Studio.app」をダブルクリックで起動する。 スクリーンショット 2020-02-26 23.36.09.png
    8. 下記ウインドウが出たら「開く」をクリックする。 スクリーンショット 2020-02-26 23.37.18.png
    9. 設定ファイルをインポートする。設定ファイルを所持していないのであれば「Do not import settings」 を選択して「OK」をクリックする。 スクリーンショット 2020-02-26 23.38.29.png
    10. Googleに情報を送信するか、しないかを問われます。送信しても良い方は「Send usage statistics to Google」を、送信したくない方は「Don't send」をクリックする。 スクリーンショット 2020-02-26 23.40.10.png
    11. 下記画面が出たら「Next」をクリックする。 スクリーンショット 2020-02-26 23.43.26.png
    12. セットアップタイプを指定する。特にこだわりがなければ「Standard」を選択し「Next」をクリックする。 スクリーンショット 2020-02-26 23.45.30.png
    13. ウインドウイメージの選択画面が表示される。お好みのものを選んで「Next」をクリックする。 スクリーンショット 2020-02-26 23.51.47.png
    14. 設定の確認画面が表示されるのでざっと確認する。確認後「Finish」をクリックする。(筆者はイメージDracleにしているのでウインドウがダークカラーになっている。) スクリーンショット 2020-02-26 23.54.32.png
    15. 画面が切り替わりインストールが開始されるので完了するまで待機する。 スクリーンショット 2020-02-26 23.56.14.png
    16. インストール中でパスワード入力を求められたら入力する。 スクリーンショット 2020-02-26 23.59.22.png
    17. 下記ウインドウが開いたら「OK」をクリックする。 スクリーンショット 2020-02-27 0.00.33.png
    18. 下記の画面になったらインストールは完了しているので「Finish」をクリックする。 スクリーンショット 2020-02-27 0.01.41.png
    19. 下記画面が出ればAndroid Studioのインストールは完了している。 スクリーンショット 2020-02-27 0.02.30.png
  2. コマンドのパス通し

    1. 下記の画面で「Start a new Android Studio project」をクリックする。 スクリーンショット 2020-02-27 0.02.30.png
    2. 下記の画面になったら「Next」をクリックする。 スクリーンショット 2020-02-27 0.07.07.png
    3. 下記の画面になったら「Finish」をクリックする。 スクリーンショット 2020-02-27 0.08.56.png
    4. 下記の画面が出たら「Close」をクリックする。 スクリーンショット 2020-02-27 0.11.42.png
    5. Android Studioのウインドウをアクティブにした時の画面上の帯の「File」をクリックする。 スクリーンショット 2020-02-27 0.13.15(2).png
    6. 「Ohter Settings」の「Default Project Structure…」をクリックする。 スクリーンショット 2020-02-27 0.17.26(2).png
    7. 開いたウインドウのAndrodi ADK locationのファイルパスをコピーする。 スクリーンショット 2020-02-27 0.18.29.png
    8. ターミナルで下記コマンドを実行して.bash_profileを開く。

      $ vi ~/.bash_profile
      
    9. 下記の内容を.bash_profileファイルに追記する。(先にコピーしたファイルパスの末尾に/platform-toolsを追記したもの)

      export PATH=$PATH:先にコピーしたSDKのファイルパス/platform-tools
      
    10. 下記コマンドを実行して.bash_profileを読み込む

      $ source ~/.bash_profile
      
    11. 下記コマンドを実行して「adb command not found」と出力されなければ導入成功である。

      $ adb
      
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

MacのPCからADBを利用できるようにする(すでにJavaがPCに入っている人向け)

目的

  • Android Debug Bridge(以後ADBと呼称する)を使用できるようにする方法をまとめる

実施方法概要

  1. Android Studioのインストール
  2. コマンドのパス通し

実施方法詳細

  1. Android Studioのインストール
    1. 下記のリンク先にアクセスする。
    2. 画面中央の「DOWNLOAD ANDROID STUDIO」をクリックしてダウンロードを行う。 スクリーンショット 2020-02-26 23.03.35.png
    3. 利用規約に目を通し「上記の利用規約を読んだうえで利用規約に同意します。」にちぇっくを入れて「ダウンロードする: ANDROID STUDIO(MAC用)」をクリックする。 スクリーンショット 2020-02-26 23.06.08(2).png
    4. ダウンロードが開始されるので完了するまで待機する。 スクリーンショット 2020-02-26 23.07.49.png
    5. ダウンロードしたインストーラーをダブルクリックで起動する。 スクリーンショット 2020-02-26 23.29.55.png
    6. 下記のウインドウが開いたらウインドウ内の「Android Studio.app」のアイコンをウインドウ内の「Applications」にドラックする。 スクリーンショット 2020-02-26 23.31.24.png
    7. アプリケーションフォルダを開き「Android Studio.app」をダブルクリックで起動する。 スクリーンショット 2020-02-26 23.36.09.png
    8. 下記ウインドウが出たら「開く」をクリックする。 スクリーンショット 2020-02-26 23.37.18.png
    9. 設定ファイルをインポートする。設定ファイルを所持していないのであれば「Do not import settings」 を選択して「OK」をクリックする。 スクリーンショット 2020-02-26 23.38.29.png
    10. Googleに情報を送信するか、しないかを問われます。送信しても良い方は「Send usage statistics to Google」を、送信したくない方は「Don't send」をクリックする。 スクリーンショット 2020-02-26 23.40.10.png
    11. 下記画面が出たら「Next」をクリックする。 スクリーンショット 2020-02-26 23.43.26.png
    12. セットアップタイプを指定する。特にこだわりがなければ「Standard」を選択し「Next」をクリックする。 スクリーンショット 2020-02-26 23.45.30.png
    13. ウインドウイメージの選択画面が表示される。お好みのものを選んで「Next」をクリックする。 スクリーンショット 2020-02-26 23.51.47.png
    14. 設定の確認画面が表示されるのでざっと確認する。確認後「Finish」をクリックする。(筆者はイメージDracleにしているのでウインドウがダークカラーになっている。) スクリーンショット 2020-02-26 23.54.32.png
    15. 画面が切り替わりインストールが開始されるので完了するまで待機する。 スクリーンショット 2020-02-26 23.56.14.png
    16. インストール中でパスワード入力を求められたら入力する。 スクリーンショット 2020-02-26 23.59.22.png
    17. 下記ウインドウが開いたら「OK」をクリックする。 スクリーンショット 2020-02-27 0.00.33.png
    18. 下記の画面になったらインストールは完了しているので「Finish」をクリックする。 スクリーンショット 2020-02-27 0.01.41.png
    19. 下記画面が出ればAndroid Studioのインストールは完了している。 スクリーンショット 2020-02-27 0.02.30.png
  2. コマンドのパス通し

    1. 下記の画面で「Start a new Android Studio project」をクリックする。 スクリーンショット 2020-02-27 0.02.30.png
    2. 下記の画面になったら「Next」をクリックする。 スクリーンショット 2020-02-27 0.07.07.png
    3. 下記の画面になったら「Finish」をクリックする。 スクリーンショット 2020-02-27 0.08.56.png
    4. 下記の画面が出たら「Close」をクリックする。 スクリーンショット 2020-02-27 0.11.42.png
    5. Android Studioのウインドウをアクティブにした時の画面上の帯の「File」をクリックする。 スクリーンショット 2020-02-27 0.13.15(2).png
    6. 「Ohter Settings」の「Default Project Structure…」をクリックする。 スクリーンショット 2020-02-27 0.17.26(2).png
    7. 開いたウインドウのAndrodi ADK locationのファイルパスをコピーする。 スクリーンショット 2020-02-27 0.18.29.png
    8. ターミナルで下記コマンドを実行して.bash_profileを開く。

      $ vi ~/.bash_profile
      
    9. 下記の内容を.bash_profileファイルに追記する。(先にコピーしたファイルパスの末尾に/platform-toolsを追記したもの)

      export PATH=$PATH:先にコピーしたSDKのファイルパス/platform-tools
      
    10. 下記コマンドを実行して「adb command not found」と出力されなければ導入成功である。

      $ adb
      
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Android Studio 3.6] Android Studioを再インストールしたのに起動しないとき

どうもこんばんわ。ニコ生できんいろモザイク一挙見ました。あややー

本題

なぜか起動しなくなってしまった。
昨日までは使えたのに。
わざわざ再インストールまでしたのに起動しない。
exeダブルクリックしてもマウスカーソルの隣にクルクルすら出ない。

環境

なまえ あたい
OS Windows 10 Pro 1909
Android Studio 3.6

解決策

C:\Users\ユーザー名\.AndroidStudio3.6

を消す。消すと起動できる。
ちなみにこのフォルダは隠しフォルダなので設定を変えないと一覧に表示されない。

隠しフォルダを表示させるには

image.png

リボンの表示を押して端にあるオプションを選び、表示タブへ移動して、
「隠しファイル、隠しフォルダ、および隠しドライブを表示する」のラジオボタンを押します。

これで表示されるようになります。

削除後の起動

image.png
一番上選んでもエラーがでちゃったので一番下でいいんじゃないかな。

あとはセットアップウイザードが起動します。
image.png

おわりに

Android端末をつなぐとUSBデバッグ許可していい?のダイアログが表示されます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む