Android アプリ開発時の Intellij IDEA の設定

EAPでも厳しい感じするのですが...。

一応、ビルド→ラウンチはできるけど。

右下にアラートが出る。

開くと以下ダイアログ。


Unexpected schema version 3
java.lang.AssertionError: Unexpected schema version 3
	at com.android.dvlib.DeviceSchema.getXsdStream(DeviceSchema.java:247)
	at com.android.dvlib.DeviceSchema.getSchema(DeviceSchema.java:331)
	at com.android.sdklib.devices.DeviceParser.getParser(DeviceParser.java:503)
	at com.android.sdklib.devices.DeviceParser.parseImpl(DeviceParser.java:489)
	at com.android.sdklib.devices.DeviceParser.parse(DeviceParser.java:464)
	at com.android.sdklib.devices.DeviceManager.initUserDevices(DeviceManager.java:444)
	at com.android.sdklib.devices.DeviceManager.initDevicesLists(DeviceManager.java:287)
	at com.android.sdklib.devices.DeviceManager.getDevice(DeviceManager.java:217)
	at com.android.sdklib.internal.avd.AvdManager.parseAvdInfo(AvdManager.java:1486)
	at com.android.sdklib.internal.avd.AvdManager.buildAvdList(AvdManager.java:1382)
	at com.android.sdklib.internal.avd.AvdManager.<init>(AvdManager.java:358)
	at com.android.sdklib.internal.avd.AvdManager.getInstance(AvdManager.java:403)
	at com.android.tools.idea.avdmanager.AvdManagerConnection.initIfNecessary(AvdManagerConnection.java:170)
	at com.android.tools.idea.avdmanager.AvdManagerConnection.getAvds(AvdManagerConnection.java:277)
	at com.android.tools.idea.run.editor.DevicePicker.lambda$refreshAvds$2(DevicePicker.java:186)
	at com.intellij.openapi.application.impl.ApplicationImpl$1.run(ApplicationImpl.java:315)
	at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
	at java.util.concurrent.FutureTask.run(FutureTask.java:266)
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
	at java.lang.Thread.run(Thread.java:745)

想像できるのは、android コマンドが利用できなくなったこと。2017年8月ぐらいからか。


$ ./android
*************************************************************************
The "android" command is deprecated.
For manual SDK, AVD, and project management, please use Android Studio.
For command-line tools, use tools/bin/sdkmanager and tools/bin/avdmanager
*************************************************************************

現在、最新版の 2017.3.3 なのですが。

GradleのバージョンやAndroidプラグインのバージョンなどに強く依存して頻繁な更新の影響を受けてるわけで。


This Gradle plugin requires a newer IDE able to request IDE model level 3. For Android Studio this means version 3.0+


$ adb push /projects/ExampleApp/app/build/outputs/apk/debug/app-debug.apk /data/local/tmp/com.example.app
$ adb shell pm install -r "/data/local/tmp/com.example.app"
Failure [INSTALL_FAILED_TEST_ONLY: installPackageLI]

$ adb shell pm uninstall com.example.app
Unknown failure (at android.os.Binder.execTransact(Binder.java:565))
Error while Installing APK

ある程度の対応策としては以下はあるが。


# gradle.properties
android.injected.build.model.only.versioned=3
android.injected.testOnly=false

とうとうGUI制限が入った Android Studio 3.0 Beta4 - exception think

環境だけでで振り回される外の人々。

中の人たちはそれなりの設定方法があるのだろうか。


Architecture Blueprints の非同期処理実装にみる Android SDK の方向性

MVP、MVVM、Clean Architecture、Dagger2、Data Binding、Archtecture Components などいろいろな組み合わせの実装例が ToDoアプリにて公開されています。

googlesamples/android-architecture: A collection of samples to discuss and showcase different architectural tools and patterns for Android apps.

非同期処理部分を見てみると現在はすべて(todo-mvp-rxjavaを除く)が以下の実装となり、非同期処理の主役であった AsyncTask/Loader API を利用した記述は消え去っています。

まず、java.util.concurrent.Executor(s) を使って、AppExecutors を作っておいて、


open class AppExecutors constructor(
    val diskIO: Executor = DiskIOThreadExecutor(),
    val networkIO: Executor = Executors.newFixedThreadPool(THREAD_COUNT),
    val mainThread: Executor = MainThreadExecutor()
) {

  private class MainThreadExecutor : Executor {

    private val mainThreadHandler = Handler(Looper.getMainLooper())

    override fun execute(command: Runnable) {
      mainThreadHandler.post(command)
    }
  }
}

AppExecutors.kt

それに対応するデータベースやストレージ向けのExecutorを作ります。


class DiskIOThreadExecutor : Executor {

  private val diskIO = Executors.newSingleThreadExecutor()

  override fun execute(command: Runnable) { diskIO.execute(command) }
}

DiskIOThreadExecutor.kt

これらを使って以下のようにして非同期処理を実装します。


appExecutors.diskIO.execute {

  // IOスレッドで実行する
  // ...

  appExecutors.mainThread.execute {

    // メインスレッドで実行する
    // ...

  }

}

実装例では、コールバックを使ってPresenterまで伝達しています。


override fun getTasks(callback: TasksDataSource.LoadTasksCallback) {

  appExecutors.diskIO.execute {

    // IOスレッドで実行する
    val tasks = tasksDao.getTasks()

    appExecutors.mainThread.execute {

      // メインスレッドで実行する
      if (tasks.isEmpty()) {
        callback.onDataNotAvailable()
      } else {
        callback.onTasksLoaded(tasks)
      }

    }

  }
}

TasksLocalDataSource.kt

AsyncTask/Loader APIs の排除の方向性は、「Deprecated(廃止予定) samples」に移動されたブランチからも認識できます。

googlesamples/android-architecture: A collection of samples to discuss and showcase different architectural tools and patterns for Android apps.

この流れについては、droidcon NYC 2017 - Android Architecture Round Table でも、話が挙がっていました。

it looks like Google is abandoning old API is like loaders and recommending patterns there are much less coupled with the framework, which is good but what happens with these API is are we abundant in then and I'm talking about classes like sync adapters loader async tasks etc

Google はLoaderのような古いAPI や フレームワークと関係の薄いパターンを推奨することをやめているように見えます。 それはいいことですが、それら古いAPIを捨てることは何を引き起こすか、AsyncAdapter や Loaderなどについて話したいと思います。

今後の、Android SDKは、フレームワークを意識したAPIが増えていくのでしょう。


すばやく理解する「Room x RxJava 」

いい記事があったので。

Room 🔗 RxJava – Google Developers – Medium

まずは、Room で Dao.


@Query(“SELECT * FROM Users WHERE id = :userId”)
User getUserById(String userId);

ここまでで問題なのは、

1. 同期呼び出しでブロッキング。
2. データ変更時に再度呼び出す必要がある。

ということで、RxJava を使いたくなります。

Room は RxJava2.x に対応しています。

Adding Components to your Project | Android Developers

どのように使うのか?

Maybe


@Query(“SELECT * FROM Users WHERE id = :userId”)
Maybe<User> getUserById(String userId);

1. 該当ユーザがなければ、何も返さずに complete。
2. 該当ユーザがあれば、onSuccess となり complete。
3. Maybe が complete されたあとにユーザー情報が更新されても何もしない。

Single


@Query(“SELECT * FROM Users WHERE id = :userId”)
Single<User> getUserById(String userId);

1. 該当ユーザがなければ、何も返さず onError(EmptyResultException)。
2. 該当ユーザがあれば、onSuccess。
3. Single が complete されたあとにユーザー情報が更新されても何もしない。

Flowable


@Query(“SELECT * FROM Users WHERE id = :userId”)
Flowable<User> getUserById(String userId);

1. 該当ユーザはなければ、何も返さず emit もされない。当然、onNext も onError も呼ばれない。
2. ユーザが存在すれば、onNext。
3. ユーザ情報が更新されるたびに、自動で emit されるので、UI上を最新データに更新させることが可能になる。

 

まとめ

これだけ数行でデータベース、非同期処理を簡潔明快に説明できる Room x RxJava の組み合わせ。

おまけに Observable から細分化された RxJava2.x の主役たちの使い方も理解することができます。

素晴らしいですよね。