Android開発ログ

タグ: Android

元情報は公式サイトから。

http://developer.android.com/reference/android/os/SystemClock.html


Androidでは3種類の時間が利用できる。
特徴を箇条書きする。



1.Systrem.currentTimeMillis()
・"wall"時間(日付情報も含む)である。http://en.wikipedia.org/wiki/Wall-clock_time
・俗に言うUNIX時間(エポック時間、epoch)を表す。つまり、1970年1月1日午前0時0分0秒からの経過秒数の数値を示す。
・ミリ秒(milliseconds)で表現される。
・ユーザやネットワークから取得した時間を設定することができるので、予期せず未来や過去の時間を示すこともある
・この時間は現実世界の時間が重要な時のみに使われるべきである。たとえばカレンダー、アラームなど。インターバル(間隔)や経過時間を計算する際は別の時刻を使うべきである。
・これを使うなら、"ACTION_TIME_TICK", "ACTION_TIME_CHANGED", "ACTION_TIMEZONE_CHANGED" といったインテントからのブロードキャストをキャッチして、時間が変わったことを検知して対応することをお勧めする。



2.uptimeMillis()
・システムが起動してからの時間を示す。
・ミリ秒(milliseconds)で表される。
・システムがディープスリープに入るとこの時間カウントも停止するので注意。(ここでいうディープスリープとは、CPUがオフになり、ディスプレイが暗くなり、デバイスが外部入力待ちの状態)
・CPU周波数スケーリング(clock scaling)、アイドル状態、その他節電の仕組みには影響されない。
・Thread.sleep()、Object.wait()、System.nanoTime()のような間隔やタイミングを扱うメソッドの基本時間として使われる。
・モノトニック(Monotonic)である。つまり単調増加が保証され、時間が巻き戻ったり調整されない時間数値である。
・デバイスがスリープしたりしない時の間隔やタイミングを計りたいときに適した時間である。



3.elapsedRealtime(), elapsedRealtimeNanos()
・システムが起動してからの時間を表す。
・"uptimeMillis()"との違いは、ディープスリープしている間の時間も計測する点にある。
・"uptimeMillis()"と同様、モノトニックな時間である。
・CPUが省電力状態でもカウントし続けるため、様々な目的の時間計測に有効である。



その他注釈:
・Thread.sleep(millis)やObject.wait(millis)はuptimeMillis()を使用しているため、デバイスがスリープに入るとスリープが解除されるまで通知が延期される。これらの同期機能は、Thread.interrupt()を使うことで中断することができるが、その際はInterruptedExceptionをハンドルする必要がある。
・SystemClock.sleep(millis)はThread.sleep(millis)とよく似たメソッドだが、SystemClock.sleep()はInterruptedException(割り込み例外)を無視する点が異なる。そのため、Thread.interrupt()を使わず、SystemClock.sleep()を使用すると、スレッドの割り込み状態を保持しておくことができる。
・Handlerクラスは内部的にuptimeMillis()を使用している。Handlerクラスは絶対時間あるいは相対時間で同期のためのコールバックをスケジューリング(予約)することができ、GUI処理でよく使われるイベントループに使われる。
・AlarmManagerは、ディープスリープ状態やアプリが起動していない状態でもイベントのトリガとして使用することができる。RTC:currentTimeMillis()やELAPSED_REALTIME:elapsedRealtime()、インテントのブロードキャストが起こった際にイベントが発生する。



Android Open Source Projectからソースを拾ってきて、OSをビルドしてました。
すると
In file included from system/core/gpttool/gpttool.c:24:
/usr/include/zlib.h:34: fatal error: zconf.h: そのようなファイルやディレクトリはありません

こんなエラーが発生。
対策は、不足する諸々を入れてやること。こうしてやればよい
 $ sudo ln -s /usr/include/x86_64-linux-gnu/zconf.h  /usr/include
 $ sudo apt-get install xorg-dev


Android Open Source Projectからソースを拾ってきて、OSをビルドしてました。
すると
g++: g++: selected multilib '32' not installed
selected multilib '32' not installed
g++: selected multilib '32' not installed

こんなエラーが発生。


このサイトが参考になります。
要約すると、次のライブラリを入れとけだそうです。
なお、現状のAndroidではgcc4.4を使用しろとのことでした。
なので4.4とあえて古いのを入れてます。

 g++-4.4-multilib
なんでインストール
 $ sudo apt-get install g++-4.4-multilib
余談ですが、update-alternativesコマンドを使うとコマンドのバージョン管理で幸せに暮らせます。


Android Open Source Projectからソースを拾ってきて、OSをビルドしてました。
すると
dalvik/vm/native/dalvik_system_Zygote.cpp: In function ‘int setrlimitsFromArray(ArrayObject*)’:
dalvik/vm/native/dalvik_system_Zygote.cpp:193: error: aggregate ‘rlimit rlim’ has incomplete type and cannot be defined
dalvik/vm/native/dalvik_system_Zygote.cpp:216: error: ‘setrlimit’ was not declared in this scope
make: *** [out/host/linux-x86/obj/SHARED_LIBRARIES/libdvm_intermediates/native/dalvik_system_Zygote.o] エラー 1
make: *** 未完了のジョブを待っています....

こんなエラーが発生。

このサイトが参考になります。
要約すると、
 dalvik/vm/native/dalvik_system_Zygote.cpp
のインクルードに
 #include <sys/resource.h>
を追加せよ
だそうです。

ちょっとした事情で、assetsに保存したDBファイルを初期データとして使いたいということがありましたが、Android上でどうファイルコピーするのが速いんだろうということで、ネット上の記事を参考に実際にプログラム走らせて調べてみました。
ここで測ったのはAndroid端末内部ストレージ間でのファイルコピー処理です。
結論だけちょろっと言っておくと、1バイトずつコピーとかアホなことさえしなきゃ問題ないというところです。
ソースコードは最後に。




まぁ基本AndroidアプリはJavaだよねということで、Javaでのファイルコピーの速度に関して調べた記事(File Copy in Java – Benchmark)を参考にしました。
10種類の方法で軽いファイル(5KB)や重いファイル(50MB)に対するコピー完了までの速度を計測したもので、ソースもDL可能です。


まぁAndroidでも同様だろうけども、念のため調べるかということで試してみました。
環境は次のもの。
 ・実機:Panasonic P-02E(Android4.1.2)
 ・バッファサイズ:4096Byte
 ・コピー元:apkのassetsファイルに保存したファイル
 ・コピー先:アプリのデータ領域
 ・コピーファイル:テキストファイル(5MB)


上記のリンクでは10種類の方法で試していましたが、ここでは5種類の方法で試します。
  Copy1.1ByteずつFileInputStreamでコピー
  Copy2.1ByteずつBufferedInputStreamでコピー
  Copy3.Bufferを使ってFileInputStreamでコピー
  Copy4.Bufferを使ってBufferedInputStreamでコピー
  Copy5.NIOFileChannelを使ったコピー


で、結果が次になります。
  Copy1:319.656 sec
  Copy2:7.317 sec
  Copy3:0.250 sec
  Copy4:0.142 sec
  Copy5:0.386 sec

バッファサイズに関しては、4096Byteから大きくしたり小さくしたり変えてみましたが、大して変化なし。
そのため、ほどほどの4096の結果のみ記載してます。






1バイトずつコピーする方法は遅く、実用には耐えられないレベルでした。まぁしょうがないですよね。
また、コピー時間に関してはFileInputStreamの方が遅い傾向にありましたが、ほぼ大差ありません。

あと、冒頭のリンクでも述べられていたのですが、NIOでコピーするのが速いのはある程度ファイルサイズがある時ということで、これはAndroid上でも一緒でした。
冒頭のサイトを読んだ時も思いましたが、意外とFileINputStreamやBufferedInputStreamよりも遅い。
上記サイトの結果を踏まえると、50MBとかの大きいファイルサイズのデータをコピーしたいときは、NIOでコピーしてあげた方がおそらく良いと思います。

今回はassetsからファイルをコピーするという前提があるため、1ファイル当たりのサイズ最大値は5MBです。
とういことで、今回調べたかった環境で一番早くコピーするには
  ・Copy4.Bufferを使ってBufferedInputStreamでコピー
しとけば良いということでした。
あとは、JNIでコピーしたらどうなるのかなーとかも思っていますが、まだ行ってはいません。
いつか気が向いたらやります。


プログラムや記事に何か間違いがあればコメント頂けると幸いです。

続きを読む

このページのトップヘ