2014年9月6日

[android]Nexus7 2012でシステムコードが取れないがわからん

わからんシリーズだ。

うちには、Nexus7 2013(5.0α?)と、Nexus7 2012(4.4.4)がある。
FeliCa Liteをかざして見るのだが、なぜかシステムコードが取れない。
しかも、4.4.4(API 19)の方だけ。
why ?

(Tag)intent.getParcelableExtra(NfcAdapter.EXTRA_TAG)

こんなのでTagを取ってきて、

NfcF nfcf = NfcF.get(tag);

こんな感じでNfcFを取ってくる。
そうすると、中の方で

/** @hide */
public NfcF(Tag tag) throws RemoteException {
    super(tag, TagTechnology.NFC_F);
    Bundle extras = tag.getTechExtras(TagTechnology.NFC_F);
    if (extras != null) {
        mSystemCode = extras.getByteArray(EXTRA_SC);
        mManufacturer = extras.getByteArray(EXTRA_PMM);
    }
}

こんなのが行われて、mSystemCodeにデータが入ってくる。
・・・のだが、そこで0が入った配列が渡されてくるので、システムコードが取って来れないのだ。
ちなみに、IDmもだめだった。
こっちは、0x00じゃなくて、ちょっとゴミっぽい。

不思議なことに、NfcFはそうなんだけど、元になっているTagの方にはIDmもシステムコードも入っていた。
だから、Intentから取ってくればいけるのかもしれん(試してない)。
が、せっかくNfcF#getSystemCode()ってのがあるのに使えないのは、なんか変だ。

うーん、わからん。

2014年9月5日

[android]Android Studioでソース管理しなくてよさそうなものはどれだ?

特に、使い勝手がよいとか悪いとかの感想もなく使っているAndroid Studio。
基準にできるものが何も無いので、便利なのか不便なのかもわからない。
「Ctrl+Alt+Lで全ファイルのimport整理ができるのが便利」とは思うけど、Eclipseのときにできなかったかどうかがわからないので、勝負にならん。。

さて、そういう状況の中で、ソースのビルドエラーが消えたので、とりあえずgitのリポジトリを作って保存しておこうと思った。
Android Studioの設定の中にgithubがあったので、githubだと連携が楽なのかもしれない。
が、ひねくれた私は、Bitbucketを使おうと思った。
いや、Bitbucketを使うのがひねくれているのではなく、連携してそうなgithubを使わない、という私がひねくれているのだ。
プライベートなリポジトリが使えるし、5人までなら無料なのよ。

そういうのはよいとして、Android Studioの場合、どれを管理して、どれを管理から外すべきかわからなかった。
これはよさそうな気はするが・・・これはダメそうな気がするし・・・。
あれこれ考えていたが、飲みながらやっていたので「全部やってしまえ!」でadd/commitしたところ、なんかうまいことなってくれた。
そう、.gitignoreファイルがあったので、それが除けてくれたのだ。

なーんだ。
悩んで損した。

2014年9月3日

[java]自分で60点くらいの例外処理を考えよう (3)

今回で最後。
60点どうのこうのいうよりも、Javaがわかってないし経験も足りないので、がんがん書いていって自分のスタイルをつかんでいくのがよいんじゃないか、という結論になりつつある。
でもね、こういう悩むって過程も必要だと思うのだ。悩まざる者、そこにあるのは死だ!みたいなことを、妖精王(山岸凉子)で言ってたように思うが、そんな感じ。

それに、ときどき立ち止まって振り返らないと。
技術なんてしばしば新しくなるから、自分がその時知っていた最善の技術が、今ではそうでもないこともあろう。
ほら、今見てるチェック例外だって、時代を経るに従って受け止められ方が違ってきてるみたいだし。
そういう変化があるから、技術はいつも新鮮で、そういうのが好きな人達をつかんで離さないのだと思う。

というのもあるが、私が飽きてきた、というのが一番の理由だ。


あっさりと終わらせてしまいたかったのだが、どうしてもわからないところがあった。
これだ。

BasicTagTechnology(Tag tag, int tech) throws RemoteException {
    mTag = tag;
    mSelectedTechnology = tech;
}

Javaって、Operator Overloadはなかったはず。
つまりここで行われるのは、純粋な代入処理。
なぜ、RemoteExceptionのチェック例外が指定されているんだろう?

まず、コンストラクタでも例外は返してよさそうだ。
根拠って言う根拠は見つけてないけど、C++でもコンストラクタで返せるから、くらいか。いや、言語も思想も違うのはわかるんだけど、なんか、イメージとしてね。

BasicTagTechnologyクラスはabstractだから、継承する方もthrowsまで@Overrideしないといけないのかもしれない。
つまり、基底クラスにthrowsがついていなかったら、派生クラスにも付けられない、という考え方だ。
どうだ?

ってよりも、私がちょろっとやったとき(Personal Java)のときは、@Overrideなんてなかったぞ。
まあ、そんなことをいったら、私が入社した頃のコンパイラはCにvoidポインタがなかったけどな。


あ、@Overrideは不安なので確認しておこう。
onCreate()にthrows IOExceptionを追加すると・・・エラーが出た。
エディタ上に出たので、コンパイルエラーなのかどうかがわかってないけど、ダメだと思ってよいのだろう。

つまり、BasicTagTechnologyのコンストラクタでthrowsを付けたのは、「きっと子供たちの誰かがRemoteExceptionを返したくなることがあるはず・・・」という親の想いがあったからだろう。
それをありがたいと思うか迷惑と思うかは人それぞれだろうが、その子供たちもthrowsというくびきを背負うことになるのだな("くびき"って、頸と木で、十字架の意味?)。


で、疲れてきたので、しばらくこうしようと思う。

  • 標準で実行時例外があるものは、知ってる範囲でそれを返すようにしよう。
    それをcatchするのは、引数に責任を持っている人。
    たとえば、A-->B-->Cの順番で呼ぶことになっていて、Aは引数無し、Bが引数付き、Cが引数で例外発生、となったら、Bがcatchする。
    Bが作った引数にAが関与しているなら、Bがcatchして意味を持つExceptionに変換してAに投げる。
  • チェック例外は、継承した人達が使いそうなら、とりあえず付けておく。
    そこまで先がわからないなら、付けない。
    チェック例外を受けた方は、なるべく早めに他の例外なり戻り値なりに変換した方がよい。チェック例外はけっこうどうしようもない例外が多いので、上に行けば行くほど「なんのこと?」になってしまうと思うから。

かなり曖昧なところは残るのだけど、とりあえず文章にすることができたのがよかった。
仕様書はいらん、となることもあるかもしれんが、文章で説明できないことを口頭で説明できるとも思えない。
文章で説明して、足りないところは口頭で説明して、ダメなら会って説明して、その結果をまた文書に反映して、というのを繰り返して、ようやくできあがるものもある。

ネットの時代だ、とかで大規模開発が時代遅れっぽく見られることもあるけど、やはり工数がかかって、人数も多く必要で、という開発は存在するだろう(そういう開発しかやったことがないけど、ネットに出ないだけだと思う)。
工数がかかって人数が少なめでよい場合はいいんだけど、だいたいそういうときは「金に糸目は(あまり)つけないから、ばんばん人使って開発しろー」ってときだと思う。
そうなると、人-人の意識伝達を早くするため、プロジェクトの最初の方で「こうやりましょう、こんな感じでやりましょう」という大きな方向付けがあるだろう。
100人すごい技術者をそろえても、各人が1時間まごまごしたら、100時間無駄になるのだ。その「まごまご」は、各人のせいではなく、管理者の責任になる。
そうなると困るので、まずは100人が直接自分と対応するのではなく、グループを作ってもらい、そのグループ長とだけ接点を持つように考える。そうすると、まごまごの責任は分散できる(ということより、100人の相手はやってられない、という物理的な事情があるのだが)。
そうして、この責任を・・・

はっ、なんか、関係ないことまで書こうとしてる!!
ともかくここで言いたかったのは、例外処理について考えるだけでもこういうごにょごにょした議論を一人ですることになるんだから、お仕事で人に来てもらって作業するときは、そういう議論があることを前もって把握して、準備しておくべきだろう。

私は一人でJavaやっているので、基準作りは自分でやらないといけない。
そして、自分の書いたJavaのコードに、それぞれそれなりの説明を付けられるようになったとき、私も「初級Javaプログラマ」の称号を得ることができるのであろう!

まだ見ぬ、その日まで・・・。

2014年9月2日

[java]自分で60点くらいの例外処理を考えよう (2)

どうエラーを返すか、の前に、もうちょっとチェック例外のことを考えたい。
今作ろうとしているのは、NfcAクラスに対するMifareUltralightクラスのようなもので、そのFeliCa Lite版だ。

  • close
  • connect
  • get
  • getMaxTransceiveLength
  • getTag
  • getTimeout
  • getType
  • isConnected
  • readPages
  • setTimeout
  • transceive
  • writePage

赤文字が、追加されたメソッド。
NfcAにあるgetAtqa()なんかがないのは、NfcAを継承してないから。

TagTechnology > BasicTagTechnology、という継承になってるんだけど、BasicTagTechnologyはpublicがついてないから、私から使うことができない(のよね? 勝手にandroid.nfc.techなんてパッケージ名付けてもだめだと思ってるが)。


私が追加したいのも、こういうやつで、FeliCa Liteのブロックにアクセスする処理だ。
迷っているのは、こういう内部のAPIを使って機能を実現するやつ。
transceive()を使うけど、それはIOExceptionを投げる。
じゃあ、使ったAPIもIOExceptionを投げた方がよいか、隠蔽した方がよいか。

MifareUltralightクラスは、ほぼそのままにしている。
transceive()の返すIOExceptionもあるが、checkConnected()の返すIllegalStateExceptionもそのまま。
実行時例外はスルーして上まで投げて、チェック例外はやった方がよいなら自分でチェックするし、そうじゃないと思ったらthrowsして上に投げる、という判断なのかな。

 

圧倒的に、Javaソースを眺めている経験値が足りないですわ-。
今はAndroidのNFCのソースしか見てないという、視野が非常に狭い状況だから、またどっかで混乱するんだろうな。
まあ、足場がないと混乱もできないから、以前よりはよくなったと前向きに考えよう。

[java]自分で60点くらいの例外処理を考えよう (1)

たぶん、数日考えたくらいでは、Javaの例外を私がどうさばくのかという方針は決まらないだろう。
とはいえ、これに時間をかけているわけにもいかないので、自分の判定で60点くらいの納得ができればよいことにしてしまいたい。

最初の書いておくと、昨日の段階で自作のクラスはたいがいがExceptionを返すように作り替えてしまった。
勢いでやったと思うんだけど、やりすぎなのでまた作り方を変えるつもり。
その作り方を、ここで書きながら考えていこう。


まず、チェックされる例外、と、チェックされない例外、というものがJavaにある。
チェック例外・非チェック例外、検査例外・非検査例外など、呼び名は色々あるようだ。
英語だと、checked exception / unchecked exception、のようだ。

メソッド名の後ろにthrowsをつけ、そこにずらずら例外を書くのが「チェック例外」だと勝手に思っていたのだが、そうではないとのこと。
http://www.ne.jp/asahi/hishidama/home/tech/java/exception.html#h_checked_exception

チェック例外は、RuntimeExceptionを継承していない例外で、メソッド外に投げたいならばthrowsをつけてないとできないとのこと。
「そんな話から書くんか!」と思われるかもしれないが、知らないのだから仕方がない。

ようやく、定義らしきところにたどり着いた。
みんな「使い分け」の方に力が入っていて、そもそも何よ?が出てこなかったのだ。
http://docs.oracle.com/javase/jp/7/api/java/lang/Exception.html
はい、さっき書いたのと同じことが書かれてた。
関連するリンクに、Errorというのがあった。
http://docs.oracle.com/javase/jp/7/api/java/lang/Error.html
ここら辺まで眺めて、ようやくEffective Java 項目58の「checked exception / runtime exception / error」という分類になっているかがわかったというところ。

  • 非チェック例外はRuntimeExceptionを継承したもの。
    そうじゃないものはチェック例外。
    異常だというのがエラー。
  • 非チェック例外=実行時例外=RuntimeExceptionを継承しててthrowsなしでも伝わっていく。
  • チェック例外=throws書いていないと伝わらないので、書かないならtry-catchで解決する。

これでよいのかな?


抽象的なのは疲れるので、今やっているところの話にしたい。

今使っているAPIは、こんな例外を投げてくるようだ。

  • java.io.IOException
  • android.os.RemoteException
  • android.nfc.FormatException

継承図を見ると、どれもRuntimeExceptionが入っていないので、チェック例外ということになる。

例えば、NfcFクラスだと、以下が投げてくる。

  • close()
    呼ぶと、他でブロック状態になっていた要求がIOExceptionを投げられてキャンセルされる。
  • connect()
    既に他でconnectされていたら投げる
  • transceive()
    I/O失敗か、キャンセルされたら投げる

close()はthrows対象になっているのは、close()処理がブロックされているときに他スレッドでclose()されたときに投げるからかな?

上記の例外は、けっこうどうしようもない感じだ。
自分のあずかり知らぬところで処理がキャンセルされたり、transceive()だと・・・何だろう?

 

NfcFクラスでは出てこないけど、その基底になるBasicTagTechnology。
これが、けっこうRemoteExceptionを返している。
NfcFではこれが現れないので、NfcF内で吸収していることになる。

RemoteExceptionは、AndroidのBinder関係の例外基底クラスのようだ(その割りに、継承してる人がほとんどいない)。
でも、これはこれでどうしようもない気配が漂っている。

BasicTagTechnologyなんか見てると、transceive()でRemoteExceptionが発生するとIOExceptionに差し替えているし、close()なんかは発生してもログを出すだけだったりする。
もうどうしようもないから、普通の流れで変なことをせずに終わろうとしている、という感じか。


そんなわけで、まず1つの基準。
RemoteExceptionはどうしようもないから、上に返さないでエラーにしてあげよう。

じゃあIOExceptionはどうするか。
これも、なるべく隠してあげる方がよいような気がしている。
今作ろうとしているのはNfcFっぽいクラスなんだけど、TagTechnologyを継承してthrowsがついているところは、そのままにして、そうじゃないで自分で作ったメソッドなんかは、なるべくエラー値で返してあげようか。

そうなると、どうエラーを返すか、とか、引数エラーはどうするか、とかが出てくる。
今日は力尽きたので、次回にしよう。

2014年9月1日

[java]戻り値がよいか例外がよいか・・・

Cで作っていたライブラリを、Androidで動かそうと移植している。
まあ、NFC関係ですわ。
そうなると、Cでは戻り値でエラーを返していたところが、Androidでは例外で返すようになっているところがある。
そんなときは、例外をcatchしてエラー値に変換していた。

そしてエラーの戻り値としてenumを定義し、catchして変換をするようなことを書き始めて、ふっと思った。
「このまま例外で処理したらいいんじゃないの?」と。

例外を返すようにして、呼び出しの一番上でcatchするようにすると、ソースの見栄えが非常によろしい。

ret = proc1();
if (!ret) {
  return ERR1;
}
ret = proc2();
if (!ret) {
  return ERR2;
}

とか、

ret = proc1();
if (ret) {
  ret = proc2();
}
if (ret) {
  ret = ....

とかが、

try {
  proc1();
  proc2();
  proc3();
  ...
}
catch(xxxException e) {
  xxx;
}
catch(yyyException e) {
  yyy;
}

みたいになって、ロジックとエラー処理を別々に書ける。
まあ、エラーの種類によって動作を変えることもあるだろうけど、見通しはよくなると言うのはわかる。

 

そうなってくると、エラーが起きたときに、戻り値で返すのか例外で返すのか、がだんだんわからなくなってきた。
C++では、例外のコストがけっこう高いのと、組込みのC++は例外が外されてることもあったので、実はそんなに使ったことがない。
Cでは、gotoとラベルを使って、(ソースの見た目上は)似たようなしくみを実現しているのを見かけたことはあるが、私自身は戻り値で知らせる派であった。

ただ、例えば引数がNULLだったり範囲外だったりしたら、お仕事ではチェックしてエラーを返したりするけど、自分でやるときはassert()で落としたりしている。
これがJavaだと、NullPointerExceptionとかIllegalArgumentExceptionがあるので、それを返すだけになっている。
assert()だとNDEBUGで無効になるし、なによりアプリが落ちる以外の選択肢しかないのが厳しい。
「ダメなんだけど、何も死ぬことはない」という状態だ。


この辺については、自分の中で整理をしないといかんですな。

2014年8月31日

[android]Log.d()はそのまま出る仕様なんだ!

いやあ、知らないって事は恐ろしいですな。

AndroidManifest.xmlに、確かdebaggableとかいう設定があったと思う。
だから私は「これをfalseにすれば、デバッグ出力のLog.d()は出力されないんだろう」と何の根拠もなく思い込んでいた。

偶然、「ログをリリース時にオフにする方法」みたいな記事があったので見てみると、全然そんな仕様じゃないことがわかった。
debaggableじゃなくて他の設定だろうと思って調べたけど、どうもそうではない模様。
つまり、Log.d()はそのまま出るんだ!


Javaのところは、ここ。
最後はprintln_native()が呼ばれている。
https://android.googlesource.com/platform/frameworks/base/+/android-4.3_r2.1/core/java/android/util/Log.java

 

Nativeは、これでよいのかな。
https://github.com/android/platform_frameworks_base/blob/master/core/jni/android_util_Log.cpp

__android_log_buf_write()が呼ばれるようだ。
もう、誰にも止められない・・・

JNIなんだな、ログって。
けっこう重たい動きになるんだ。


なんか、一括して、しかもバイナリレベルで呼び出されないくらいのことをしてくれんかと思って探すと、ProGuardで消すというのが一番多かった。

proguard-rules.proに、

-assumenosideeffects class android.util.Log {
    public static int v(...);
    public static int d(...);
    public static int i(...);
    public static int w(...);
    public static int e(...);
    public static int wtf(...);
}

みたいなのを書いて、build.gradleに、

buildTypes {
    release {
        runProguard true
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
    }
}

みたいな変更をして、Signed APKを作るようだ。 

[android]Android Studio初心者 (2)

"@string/foobar"みたいな記述をしている箇所を、自動的に該当する文言で表示してくれる。
便利と言えば便利なのだが、Android勉強中の私からすると「あれ、strings.xmlにまだ入れてなかったっけ」と思って、カーソルを当ててbackspaceで削除し始めてしまうことがしばしば。
慣れるまでは、入力したものをそのまま表示してほしい。

Settingsの、IDE Settingsの、Editor > Code Foldingの中に「Android String References」があるのでチェックを外すとよい。
できれば、動的に変更できるとよいのだが・・・。


昨日、ArrayAdapterのextendsか何かを書いていたときだったと思うけど、表示が「<~>」みたいになってた。
書き間違えたんかねー、とカーソルを当ててbackspaceで削除し始めて、それが省略表記だったことに気付く、ということがしばしば。
今の私は、自動的に省略してくれることのありがたみが、まだわかる段階に来ていないのだよ・・・。

たぶんこれも、上記のCode Foldingのところにあるんじゃなかろうか。
でも、どれかよくわからないので、Importのとこだけチェックして、残りは外してしまった。
いつの日か、このチェックをデフォルトに戻せる日が来ることを信じて・・・。

[android]Android Studio初心者 (1)

プロジェクトを作るとき、こんな画面が出てくる。

image

いつもの感覚で、パッケージ名を入力していたのだが・・・。
そう、画面を見るとわかるように、ここで入力するのは「Company Domain」で、パッケージ名はその下に表示されている。
つまり、順番が逆なのだ。

前使ってるプロジェクトからファイルを持ってきて、初めて気付いた。
ちっ。

javaフォルダで右クリックしてパッケージを作り、そっちにファイル移動する、というやり方をまねした。
http://stackoverflow.com/questions/16804093/android-studio-rename-package


NdefMessageクラスを使おうとしたら、APIのバージョンが14なので使えません、と言われた。
AndroidManifest.xmlを編集すると、それはビルドするときにスクリプトが上書きするので無視されます、と言われた。。
ちっ。

build.gradleというファイルがあるので、それに追加するとよさそうだ。
なお、uses-permissionは直接書き換えるようだ。

2014年8月30日

[android]ListViewに渡したいデータがString[]じゃないときは、ArrayAdapterをextendsする

前回の続き。

しか先生のコメントをいただき、toString()をOverrideするのはJava仕様としてよろしくない、という理解ができた私。
ArrayAdapterをextendsするのがよいとのことなので、やってみよう。


まずどうでもよいことから先に書くと、ListViewのレイアウトをandroid.R.layout.simple_expandable_list_item_1からsimple_list_item_1に変更した。
理由は、expandable、というのが開いたり閉じたりできるタイプだったので、そんな用途もないのでシンプルにしておきたいという理由だけだ。
XMLの中身としてはどっちも同じようなものだったと思う。

ArrayAdapterを拡張する例をネットで調べると、凝ったことをしたい人が多かった。
私のように、単にタイトルの文字列を指定したいだけ、というのがあんまりなさそうだった。
以下は、自分でListView用のXMLを作りたくない人向けになる。

    class MenuAdapter extends ArrayAdapter<ListData> {
        public MenuAdapter(Context context, int resource, ListData[] objects) {
            super(context, resource, objects);
        }
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            TextView view = (TextView)super.getView(position, convertView, parent);
            ListData item = getItem(position);
            if ((view != null) && (item != null)) {
                view.setText(item.title);
            }
            return view;
        }
    }

ListData、というのが、自分で作ったclass。
前回はStringとintだったけど、今回はStringとStringになった。

    class ListData {
        public String title;
        public String actname;
        public ListData(String title, String value) {
            this.title = title;
            this.actname = value;
        }
    }

やってることは・・・単にTextViewにListDataのtitle文字列を設定しているだけだ。
getView()の引数convertViewがTextViewなのは、きっとandroid.R.layout.simple_list_item_1がTextViewを1つしか持っていないからだろう。

最初は、コンストラクタのresourceを保持して、他のArrayAdapterのカスタマイズ記事を見ながらInfraterなどやってたんだけど、うまく行かなかった(今思えば、Infrater後にfindViewByIdでTextViewを探そうとしたところが間違ってたかも)。
convertViewは、非nullなら再描画で使い、nullならInfraterで自作するようだから、じゃあsuperでやってくれるだろう、ということで今の形に落ち着いている。

呼び出し方は前と同じで、こう。

        String[] titles = getResources().getStringArray(R.array.main_list_label);
        String[] actnames = getResources().getStringArray(R.array.main_list_actname);
        ListData[] list_data = new ListData[titles.length];
        for (int i = 0; i < titles.length; i++) {
            list_data[i] = new ListData(titles[i], actnames[i]);
        }
        ListView lv = (ListView) findViewById(R.id.listView);
        MenuAdapter adapter = new MenuAdapter(this, android.R.layout.simple_list_item_1, list_data);
        lv.setAdapter(adapter);

 

私としてはこれでよいと思ってるんだけど、どうかな?