SmartWatch 3を1ヶ月使ってみて
前月ソニーモバイルコミュニケーションズから発売されたAndroid Wear端末のSmartWatch3を買いました。
SmartWatch 3を買いました - pluea engineering blog
SmartWatch3 SWR50 | ソニーモバイルコミュニケーションズ
だいたい1ヶ月くらい使ってみたので感想を書いていきたいと思います。
スマホで通知を見る回数が減った
Android Wearではスマホに来た通知をリアルタイムに受け取ることができます。
今まではスマホが振動する度に、
- スマホの電源をつける
- ロックを解除
- 通知領域を開いてなんの通知が来たのか確認
- 通知が必要なければ消す or 中身を見る
という流れでした。
Android Wearでは、スマホに通知が来ると時計が震え盤面に通知を知らせてくれます。そしてロックの解除が必要ないので、
- 時計を目の前に持ってくる
- 通知が必要なければ消す or 中身を見る
だけで通知を処理できます。
SmartWatch3の独自機能なのかAndroid Wearの機能なのかわかりませんが、腕を目の前に持ってくる動きをすると自動で盤面の電源が入ります。
なので、盤面が消灯していても盤面をタップすることなく盤面を明るくすることができます。この機能も結構便利です。
また、時計は常に腕につけているので、通知に気が付きやすいのも良い点です。
通知が必要なければスワイプで簡単に消すことが出来ます。もちろんAndroid Wear側で通知を消せば、スマホ側でも消えています。
通知を見る場合はアプリにもよりますが、対応していればAndroid Wear側で見ることができます。例えばGmailはタップすることでメールの中身を見れます。また地味に便利なのが、スマホでは2件以上メールが来ると通知がまとめられてしまって、Gmailアプリを開くしかないのですが、Android Wearではメール1つ1つを見ることができます。
対応していない場合はスワイプして「端末で開く」を選択してスマホ側で見る流れになります。
バッテリーについて
SmartWatch 3はサイズの小ささもあってバッテリー容量がそれほどあるわけではありません。
公式では約2日となっています。
また、連携するスマホ側では、Android Wearの機能をフルで使うためにGPSとBluetoothを常にオンにしています。
1ヶ月使ってみたのですがスマホ・SmartWatch共にバッテリーで困ったことは特にありませんでした。
まずSmart Watch 3ですが、使う時間によるとは思うのですが、帰宅して外したときにバッテリー残量を見てみるとだいたい60~70%くらい残っています。
もしバッテリーが切れたとしても1時間でフル充電できるので、いざという時はモバイルバッテリー等で充電すればそれほど困りません。
ただ、ほぼ毎日充電する手間があるのと、充電の端子が刺しづらいという問題もあります。
次にスマホ側ですが、Bluetoothの新規格であるBluetooth Low Energyが優秀なのかさほどバッテリー消費量は増えませんでした。
体感ですが、10%程度の増加でしょうか。
GPSに関しても常にGPSを使った処理をしているわけではないので、こちらもあまり影響はありませんでした。
ただ、常に位置情報を取得できる状態にあるので、その点は注意しないと余計な位置情報を漏らす可能性があります。
アプリについて
Android Wearに対応しているアプリがどの程度揃っているかによって使い心地が変わってくると思うのですが、 現状では概ね満足しています。
私が特に使っているのは
Wear Mini Launcher - Google Play の Android アプリ
=> Launcherを追加する
Yahoo!乗換案内 無料の時刻表、運行情報、乗り換え検索 - Google Play の Android アプリ
=> 電車の検索
Wear for Swarm - Google Play の Android アプリ
=> Foursquareのチェックイン
Wearable Widgets - Google Play の Android アプリ
です。
特にWear Mini Launcherは便利で、左からスワイプすることでアプリ一覧画面を開くことができるので、アプリへのアクセスが格段によくなります。
そもそもAndroid Wearのアプリ一覧へのアクセスがかなり悪いです。
アプリ一覧にアクセスするには、盤面をタップして一番下までスクロールし、「開始」を押さなければなりません。出てくるアプリ一覧も一行に一つなので非常に見難いです。
Wear Mini Launcherを入れることで、この辺りがかなり改善されました。
Yahoo!乗換案内は、予め経路を登録しておくことで現在時刻の経路をすぐに検索することができます。
急いでいるときなど、スマホを開いてアプリを開いて・・・というよりもかなり早く電車時刻の検索ができます。
最後に
Smart Watch3には概ね満足しています。これからも使い続けていこうと思います。
先週辺りにアップデートがきて、盤面のカスタマイズのAPIが使えるようになったので、ますます対応アプリが増えてくるかと思います。
まだまだAndroid Wearを使ってできることがあると思うので、新しい使い方を模索していこうと思います。
SmartWatch 3を買いました
11/28にソニーからSmartWatch 3が発売されたので早速買ってきました。
SmartWatch3 SWR50 | ソニーモバイルコミュニケーションズ
値段はビックカメラで26870円でした。
予約なしで買えるのかなと少し思いましたが、普通に買えました。 ただ、あまり広告にやる気がなく、ビックカメラではモックしかなかったのでヨドバシで実機を見てから買いました。
外観と付属品
ディスプレイは1.6インチで小さめです。
時計なのでこのくらいのサイズでちょうどいいかと思います。
小さすぎてタッチがしにくいといったことはなかったです。
ディスプレイの裏側です。
こちらに充電を行うmicroUSBポートがあります。
バンドはゴム製になっています。
留め具のところは金属になっていてパチっとはめるだけで簡単に取り外しできるようになっています。
付属品は以下の通りです。
- SMART STYLEキャンペーンの申し込み用コード
- 説明書
- 保証書
- microUSBケーブル(短め)
SMART STYLEキャンペーン
私は店頭で知ったのですが、2014年11月28日(金)10:00 から 2015年1月14日(水)23:59 まで対象のXperiaを持っているとEdy5000円分がもらえるキャンペーンを行っています。
SMART STYLEキャンペーン | Xperia™ Store
Xperia Zシリーズを持っている方であれば、誰でももらえるようなので持っている方は期間内に買うと非常にお得かと思います。
設定
SmartWatch 3を起動するとまず言語設定を聞かれます。
日本語もあるので、日本語にしておきます。
次にAndroid Wearをペアリングする端末にインストールするように表示されます。
Google PlayにAndroid Wearというアプリがあるのでそれをペアリングする端末にインストールして開きます。
あとはアプリの指示に従っていけば設定が完了します。
特に戸惑うことはなくスムーズにペアリングを行うことができました。
Bluetoothや位置情報設定などをオンにしておくと楽かと思います。
チュートリアル
設定が終わるとSmartWatch 3側でチュートリアルが始まります。
正直使い方が全然わからなかったので非常に助かりました。
まず上にスワイプするように表示されます。
スワイプすると設定が完了した旨が表示されます。
もう一度上にスワイプします。
どうやらAndroid Wearではカードという単位で天気や通知などが表示されるようです。
不要なカードは右にスワイプすることで削除できます。
画面を暗くしたいときには手で覆えばいいようです。
MarkdownをPandocとブラウザを使ってPDFに変換する
GithubのREADMEなどで使われるMarkdownの形式で文章を書いたり、メモを取ることが最近多くなってきた。
ただ、Markdownの形式で書いていると、人に渡すときに結構困る。
というのもファイルを渡す人がMarkdownに慣れているとは限らないし、そもそもMarkdownエディタ自体をインストールしていなくてファイルを見られない可能性がある。
そこで今回はMarkdownのファイルをPDFに変換してみた。
変換方法を調べるとMarkdown→Tex→PDFというやり方が多く出てくるが、Texの環境を入れるのがなかなか大変(時間がかかる)ので、ただMarkdownを変換したいだけの今回はパスする(綺麗に変換をしたいならこのやり方の方がよい)。
今回の変換方法としては、MarkdownをHTMLファイルに変換し、それをブラウザで開いてPDFで保存する。
今回はMarkdownをHTMLに変換するツールとしてPandocを使う。
PandocのインストールはMacのhomebrewを使って行った。
参考: Haskell製のMarkdownをHTMLやLaTeXに変換できるPandocのインストールとサンプル - 三等兵
※結構時間がかかるので注意
$ brew install haskell-platform $ cabal update $ cabal install cabal-install // cabalのアップデート $ cabal install pandoc
私はbashを使っているので~/.bash_profileに以下を追加する。
export PATH=$PATH:${HOME}/.cabal/bin
パスが通っているかを確認
$ source ~/.bash_profile // bash_profileを再読み込み $ echo $PATH // パスを確認 $ pandoc -v
現在(2014/11/5)時点でバージョン1.13.1がインストールされた。
$ pandoc -v pandoc 1.13.1 Compiled with texmath 0.8, highlighting-kate 0.5.9. Syntax highlighting is supported for the following languages: abc, actionscript, ada, apache, asn1, asp, awk, bash, bibtex, boo, c, changelog, clojure, cmake, coffee, coldfusion, commonlisp, cpp, cs, css, curry, d, diff, djangotemplate, dot, doxygen, doxygenlua, dtd, eiffel, email, erlang, fasm, fortran, fsharp, gcc, glsl, gnuassembler, go, haskell, haxe, html, ini, isocpp, java, javadoc, javascript, json, jsp, julia, latex, lex, lilypond, literatecurry, literatehaskell, lua, m4, makefile, mandoc, markdown, mathematica, matlab, maxima, mediawiki, metafont, mips, modelines, modula2, modula3, monobasic, nasm, noweb, objectivec, objectivecpp, ocaml, octave, opencl, pascal, perl, php, pike, postscript, prolog, pure, python, r, relaxng, relaxngcompact, rest, rhtml, roff, ruby, rust, scala, scheme, sci, sed, sgml, sql, sqlmysql, sqlpostgresql, tcl, tcsh, texinfo, verilog, vhdl, xml, xorg, xslt, xul, yacc, yaml, zsh Default user data directory: /Users/kyamaguchi/.pandoc Copyright (C) 2006-2014 John MacFarlane Web: http://johnmacfarlane.net/pandoc This is free software; see the source for copying conditions. There is no warranty, not even for merchantability or fitness for a particular purpose.
そしてMarkdownをHTMLファイルに変換する。
$ pandoc -s hoge.md -o hoge.html
最後に変換されたHTMLをブラウザで開いて印刷メニューからPDFで保存する
【iOS, Objective-C】 NSUserDefaultsを使って簡単なデータを保存する
iOSではデータを保存する方法が何種類かある。
・ファイル
・データベース(SQLite)
・Core Data
・NSUserDefaults
その中で一番簡単にデータを保存できるのがNSUserDefaultsである。
NSUserDefaultsではキーと値のセットで値が保存できる。
そのため、複雑な構造のデータの保存にはあまり向いていないが、オプションやフラグの値の保存程度ならば簡単に実装できる。
[[NSUserDefaults standardUserDefaults]setBool:YES forKey:@"key"]; Bool value = [[NSUserDefaults standardUserDefaults]boolForKey:@"key"] // YES
setBoolではBoolの値が保存できるが、それ以外の値用のメソッドも用意されている。
メソッド名 | 保存できる値 |
---|---|
setObject | id |
setInteger | NSInteger |
setURL | NSURL |
setFloat | float |
setDouble | double |
setBool | Bool |
例えばスイッチが1つあってそのオン/オフの状態を保存する場合、以下のようになる。
#import "ViewController.h" @interface ViewController () @property (weak, nonatomic) IBOutlet UISwitch *switch; @property (weak, nonatomic) NSString *switchKey; @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; _switchKey = @"switchKey"; _switch.on = NO; // 保存した値を読み込み if ([[NSUserDefaults standardUserDefaults]boolForKey:_switchKey]) { _switch.on = YES; } // スイッチの状態が変わったときに呼ばれる先を指定 [_switch addTarget:self action:@selector(switchDidChange) forControlEvents:UIControlEventValueChanged]; } - (void)switchDidChange { // スイッチの状態が変わったら現在のスイッチの状態をNSUserDefaultsに保存 if (_switch.on == YES) { [[NSUserDefaults standardUserDefaults]setBool:YES forKey:_switchKey]; }else { [[NSUserDefaults standardUserDefaults]setBool:NO forKey:_switchKey]; } }
実際にスイッチを切り替えてからアプリを開き直すと、スイッチの状態が保存されていることが確認できる。
【Android】HanlderとMessageを使ってマルチスレッドの処理結果を受け取る
Androidアプリ内で重たい処理を行う場合、処理をメインスレッドで行うと処理が終わるまで画面が止まってしまう。
そのため、スレッドを分けて処理を行わせる。
その際に、処理結果を別スレッドから受け取るときの一つの方法としてHandlerとMessageを使う方法がある。
Handler handler = new Handler() { @override public void handleMessage(Message msg) { switch(msg.what) { case 1: // msg.objはObject型なのでキャストする必要がある Log.d("Handler", (String)msg.obj); break; default : break; } } } class TaskTread extends Thread { private Handler handler; public TaskThread(Handler handler) { this.handler = handler; } @override public void run() { //重たい処理 // ・・・ Message msg = Message.obtain(); // 実際にはマジックナンバーではなく値を決めておく msg.what = 1; // 結果がString型のresultにあると仮定 msg.obj = result; handler.sendMessage(msg); } }
まず、Handlerをメインスレッド内で宣言する。
Handlerはスレッドを超えてMessageクラスのオブジェクトを送受信することができる。
送信のメソッドは変更の必要がないので、受信を行うメソッドであるhandlerMessage(Message msg)のみoverrideする。
Handler handler = new Handler() { @override public void handleMessage(Message msg) { switch(msg.what) { case 1: // msg.objはObject型なのでキャストする必要がある Log.d("Handler", (String)msg.obj); break; default : break; } }
Messageはwhatというintのpublic変数を持っている。
送信の際にこのwhatを設定してあげることで、switch文などで送信先によって処理を分けることができる。
実際に受け取るデータはmsg.objに入っており、キャストしてデータを受け取る。
次に処理を行わせるスレッド(TaskTread)を宣言し、コンストラクタでHandlerを渡しておく。
このHandlerを利用して後にMessageをTaskThreadからメインスレッドに送信する。
class TaskTread extends Thread { private Handler handler; public TaskThread(Handler handler) { this.handler = handler; } @override public void run() { //重たい処理 // ・・・ Message msg = Message.obtain(); // 実際にはマジックナンバーではなく値を決めておく msg.what = 1; // 結果がString型のresultにあると仮定 msg.obj = result; handler.sendMessage(msg); } }
TaskThreadで重たい処理を行わせた後、Messageの設定を行う。
MesageのインスタンスはMessage.obtain()で取得できる。
newでインスタンスを作ることもできるが、obtain()で行うことが推奨されており、効率がよい。
While the constructor of Message is public, the best way to get one of these is to call Message.obtain() or one of the Handler.obtainMessage() methods, which will pull them from a pool of recycled objects.
Message | Android Developers
次にwhatに送信先を識別するintを設定し、objに送信するデータを設定する。
そして最後にsendMessage(msg)でMessageを送信する。
sendMessage()を呼ぶとHabdlerのhanldeMessage()がメインスレッドで呼ばれ、処理結果を受け取ることができる。
【Android】 CSVファイルを読み込んでパースする
Androidで初期データなどCSVファイルを処理したい場合がある。
その時は、CSVファイルをassetsと呼ばれるフォルダに置き、それを読み込んでパースを行う。
assetsフォルダはプロジェクトの一番上に作成する。
assetsフォルダへのアクセスはAssetManagerを通じて行う。
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Map; import java.util.StringTokenizer; import android.content.Context; import android.content.res.AssetManager; public class CSVParser { public static void parse(Context context) { // AssetManagerの呼び出し AssetManager assetManager = context.getResources().getAssets(); try { // CSVファイルの読み込み InputStream is = assetManager.open("data.csv"); InputStreamReader inputStreamReader = new InputStreamReader(is); BufferedReader bufferReader = new BufferedReader(inputStreamReader); String line = ""; while ((line = bufferReader.readLine()) != null) { // 各行が","で区切られていて4つの項目があるとする StringTokenizer st = new StringTokenizer(line, ","); String first = st.nextToken(); String second = st.nextToken(); String third = st.nextToken(); String fourth = st.nextToken(); // 何らかの処理 } bufferReader.close(); } catch (IOException e) { e.printStackTrace(); } } }
【Android】Linuxコマンドの実行
AndroidアプリからLinuxコマンドを実行するにはRuntimeクラスを利用する。
package xxxxxxxxxxxx; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import android.util.Log; public class CommandExecutor { private static boolean isStopProcess = false; public static String execCommand(String command) throws IOException { isStopProcess = false; if (command == null || command.equals("")) { return null; } Runtime runtime = Runtime.getRuntime(); Process process = runtime.exec(command); String result = readInputStream(process.getInputStream()); if (result == null || result.equals("")) { result = readInputStream(process.getErrorStream()); } if (process != null) { process.destroy(); } return result; } private static String readInputStream(InputStream in) throws IOException { InputStreamReader inReader; BufferedReader bufReader = null; StringBuffer output = new StringBuffer(); try { inReader = new InputStreamReader(in); bufReader = new BufferedReader(inReader); String line; while (((line = bufReader.readLine()) != null) && !isStopProcess) { output.append(line + "\n"); Log.d("CommandExe", "output:" + output); } } finally { if (bufReader != null) { bufReader.close(); } } return output.toString(); } public synchronized static void stopProcess() { isStopProcess = true; } }
Runtimeクラスはインスタンスを自由に作ることはできず、getRuntime()というメソッドが用意されている。
getRuntime()で取得したインスタンスに対してexec(String prog)メソッドを実行することでコマンドを実行できる。
返り値としてプロセスが返ってくるので、これを利用して結果を読み込む。
今回は readInputStream(InputStream in)というメソッドを用意して結果を読み込んでいる。
というのもコマンドの実行が成功したときと失敗したときで結果が取得できるInputStreamが異なるためである。
Runtime runtime = Runtime.getRuntime(); Process process = runtime.exec(command); //コマンド実行が成功した場合のInputStream InputStream in = process.getInputStream(); //コマンド実行が失敗した場合のInputStream InputStream errorin = process.getErrorStream();
今回は結果が空だったら失敗とみなして、エラーの結果を取得する。
String result = readInputStream(process.getInputStream()); if (result == null || result.equals("")) { //コマンド実行失敗 result = readInputStream(process.getErrorStream()); }
また、コマンド実行をメインスレッドで行うと結果が返ってくるまで画面が止まってしまうので、マルチスレッドでコマンドを実行することを想定している。
例えばlogcatを実行した場合、プロセスを停止させるまでずっと結果を取得し続けてしまう。
今回はisStopProcessというbooleanのフラグを用意し、この値がtrueになったら停止するようにしている。
isStopProcesはsynchronizedなstopProcess()メソッドを他のスレッドから呼ぶことでtrueになり、プロセスを停止できる。
private static boolean isStopProcess = false; private static String readInputStream(InputStream in) throws IOException { InputStreamReader inReader; BufferedReader bufReader = null; StringBuffer output = new StringBuffer(); try { inReader = new InputStreamReader(in); bufReader = new BufferedReader(inReader); String line; //結果がなくなるかフラグがtrueになったら終了 while (((line = bufReader.readLine()) != null) && !isStopProcess) { output.append(line + "\n"); Log.d("CommandExe", "output:" + output); } } finally { if (bufReader != null) { bufReader.close(); } } return output.toString(); } public synchronized static void stopProcess() { //プロセスを停止するフラグをtrueにする isStopProcess = true; }