「スピード」と「精度」がどんなものなのか。

ホリエモンのトークで試してみます。
うん。十分使えると思います。
なんとなくやっていたのですが。
なんかおかしいとは思っていたのですが。
インポートするとなんかディレクトリ構成がグダクダ。
2つあるはずの build.gradle が1つだったり、見えなかったり。

あれこれ他の設定をいじったり、不要なディレクトリを消したり、
インポートのたびにストレスとなってました。
プロジェクトのソース指定時に、
「ディレクトリ」
を選択ではうまくいかない。


しかし、
「プロジェクトルートのbuild.gradle ファイル」
までを選択するとその後もスムーズに進んでいく。

きちんと表示されました。

また、ひとつスッキリできました。
Android内に、
ただ、これだけのテーブルを作って、
CREATE TABLE player (
id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
number INTEGER NOT NULL,
name TEXT NOT NULL,
UNIQUE (number, name)
);
これだけのデータを入れて、
[
{ "number": 1, "name": "柴田勲" },
{ "number": 2, "name": "土井正三" },
{ "number": 3, "name": "張本勲" },
{ "number": 4, "name": "王貞治" },
{ "number": 5, "name": "シピン" },
{ "number": 6, "name": "高田繁" },
{ "number": 7, "name": "河埜和正" },
{ "number": 8, "name": "福嶋智春" },
{ "number": 9, "name": "新浦壽夫" }
]
で、実際にきちんと格納されているかどうか。
みんなはどうやって見てます?
selectAll() など書いてログに出力する。

うん、見づらい。
Flip Tables で List を見やすくログに表示する
.dbファイルをPC上にコピーして、それをそれらで開く。
$ sqlite3 test.db
SQLite version 3.24.0 2018-06-04 14:10:15
Enter ".help" for usage hints.
sqlite> select * from player;
id number name
---------- ---------- ----------
1 1 柴田勲
2 2 土井正三
3 3 張本勲
4 4 王貞治
5 5 シピン
6 6 高田繁
7 7 河埜和正
8 8 福嶋智春
9 9 新浦壽夫
はい、いちいちPC上にコピーするのが面倒。

dbファイルパーミッションの厳格化でIDEから直接見ることはできない。
ので、いちいち、PC上にコピー。
毎回、ビューアの設定やパスの指定や同期の確認。
はい、操作多すぎ。
Stetho - A debug bridge for Android applications
デバッグコードを多少埋め込む。
dependencies {
compile 'com.facebook.stetho:stetho:1.5.0'
}
public class MyApplication extends Application {
public void onCreate() {
super.onCreate();
Stetho.initializeWithDefaults(this);
}
}
埋め込んだら、Chromeで開く。
chrome://inspect/#devices

なんで、ID列が2列あるんだよっ!?
リードオンリー。

一行のみ。
debugImplementation 'com.amitshekhar.android:debug-db:1.0.4'
ログに出力されるURLをクリック。

ブラウザに表示される。

クエリー実行や行ごとの編集もブラウザから可能。
これにしよう。
「Make Debugging Great Again」ですね!
しかし、Room で見れない。
「room」 - Issues · amitshekhariitbhu/Android-Debug-Database
どうにも、「File Explorer」を使ってのファイルコピー操作がだるい。
確認のたびに、接続や同期、ファイル上書き確認が必要。
しかも、コピーするファイルって、
data/data/your-application-package/databases 以下
your-database-name
your-database-name-shm
your-database-name-wal
の3つが必要なんじゃね?
しらんけど。
これ。

The New Toolbox App 1.13 with Android Studio inside! | JetBrains Blog
Jakeも何か言っています。
Installing stable, beta, and/or canary side-by-side? Prevent beta from constantly wanting to upgrade into canary by clicking the… uh… nut (I guess?), going to settings, and enabling "stay on version". https://t.co/VNSBF9ui2i pic.twitter.com/dmgQtP9NUs
— Jake Wharton (@JakeWharton) January 17, 2019
JetBrains のIDEのパッケージ群を管理したり起動できるランチャーのようです。
それに、新たに AndroidStudio も使えるようになった。ということでしょうか。
インストールしてみます。
そして、それをChrome上のGitHub画面から起動できるChromeエクステンションも登場しています。

JetBrains Toolbox Extension - Chrome ウェブストア
GitHubページに表示されるアイコンをクリックすると、ソースをダウンロードして、ローカルで起動しようとします。

アドビのパッケージ管理のウィジェットにも似た雰囲気です。
OS画面上部の常駐のバー(?)にアイコンが表示されるのでそれから起動します。


ローカル内のプロジェクトの選択してのIDEの起動と、それぞれのIDEパッケージのバージョン管理が可能になります。
アドビのパッケージマネージャ的なやつと思ったらいいでしょう。
Android Studio/Intellij は、複数のバージョンが並行利用できそうです。

無料です。
👉 AndroidStudio 利用する Java (JDK) の選択・設定の方法
👉 Android Studio Chipmunk の起動時がかわいい件
少し古いですが、ふと思い出した記事です。
ネットワークを使ったすべてのアプリに必須な考え方だと思います。
Loading data from multiple sources with RxJava
ネットワーク経由で問い合わせするデータがある場合、必要なときにそのまま取得することができますが、ディスクやメモリにキャッシュするほうが効率的です。
1. たまにネットワーク経由で新鮮なデータを取得する。
2. それ以外は、その結果をキャッシュしてできるだけ早く取得する。
RxJava を使ってこの実装をすると良いです。
Observable を使って、ネットワーク、ディスク、メモリーのそれぞれから取得します。
シンプルに2つのオペレーター concat() と first() を使います。
concat() は、複数の Observable を並び順に合成して、first() はその並び順から最初のものを実行します。よって、concat().first() とすると、複数のソースから最初のものが取得されます。
// Our sources (left as an exercise for the reader)
Observable<Data> memory = ...;
Observable<Data> disk = ...;
Observable<Data> network = ...;
// Retrieve the first source with data
Observable<Data> source = Observable
.concat(memory, disk, network)
.first();
このパターンの鍵となるのは、concat() が 必要なときにだけ、それぞれの子Observableを subscribe することです。
first() はシーケンスを早く止めるので、データがキャッシュされている場合に不要な遅いソースの問い合わせはありません。 言い換えれば、メモリから結果が返された場合、ディスクやネットワークにアクセスする必要はありません。 逆に、メモリとディスクがデータを持っていない場合は、新しくネットワークリクエストを行います。
当然、次のステップは、ソースが入ってきたときにそれを保存することです。ネットワーク要求の結果をディスクに保存したり、ディスクへのリクエストをメモリにキャッシュしなければ、何の意味もありません。上記のコードは、常にネットワークリスエストを行うだけです。
私の考えた対策は、それぞれのソースがそれを発行するときにデータを保存/キャッシュすることです。
Observable<Data> networkWithSave = network.doOnNext(data -> {
saveToDisk(data);
cacheInMemory(data);
});
Observable<Data> diskWithCache = disk.doOnNext(data -> {
cacheInMemory(data);
});
これで、networkWithSaveとdiskWithCacheを使用した場合、データはロード時に自動的に保存されます。
(この方法のもう1つの利点は、networkWithSave / diskWithCache はどこでも使用できることです。)
このままでは、古いままのデータが常に返されます。新鮮なデータの取得のために、たまにはサーバから取得しなければなりません。
解決策は、first() で。これはフィルタリングも実行できます。価値のないデータを除去するように設定します。
Observable<Data> source = Observable
.concat(memory, diskWithCache, networkWithSave)
.first(data -> data.isUpToDate());
これで、「最新」と見なされる最初のアイテムのみを発行します。したがって、そのデータソースが古い場合は、新しいデータが見つかるまで次のソースに進みます。
first() の代わりに takeFirst() を使うこともできます。
2つの違いは、いずれのソースも有効なデータを発行しない場合、first()は NoSuchElementException をスローするのに対し、takeFirst() は例外なしで完了することです。
どちらを使用するかは、データ不足を明示的に処理する必要があるかどうかによって異なります。