2012/12/30

android.net.Uri と java.net.URI の変換

android.net.Uri と java.net.URI の違い で java.net.URI と android.net.Uri はほぼ同じであると書きましたが、継承関係にあるわけでもなく、変換用の関数が用意されているわけでもありません。

では、これらは変換出来ないのかというと、そうではありません。
もともと文字列で表現されるアドレスのパーサですから(正確にはパーサを内包したコンテナというべきでしょうか?)、文字列にしてしまえば相互に変換することができます。

String path = "http://anonymous@192.168.0.1:8888/main.html?id=00001#fragment";
Uri androidUriA = Uri.parse(path);
URI javaUriA = URI.create(androidUriA.toString());

Log.i(TAG, "A " + javaUriA.toString());

URI javaUriB = URI.create(path);
Uri androidUriB = Uri.parse(javaUriB.toString());

Log.i(TAG, "B " + androidUriB.toString());

android.net.Uri と java.net.URI の違い

Android でネットワーク系の開発をしていると必ず出てくる Uri。
これ、android.net.Uri と java.net.URI と2種類あって混乱する時があります。(java.net.URL ってのもありますが、それはまた別のお話)
で、どう違うのか調べてみたので備忘録として書いておきます。

まず、どちらも URI を表すクラスである点では同じです。
参考

そして、パッケージ名を見れば明らかなのですが、 android.net.Uri は android 用に作成されたクラスなのに対して、 java.net.URI は java で定義されているクラスです。
(import しちゃうと途端に区別がつきにくくなるんですけどね…)

まず、大きな違いとしては、java.net.URI は Serializable なクラスなのに対し、android.net.Uri は Parcelable なクラスであるところと、 android.net.Uri は abstract なクラスであるところが挙げられます。

以下に、それぞれに定義されているメソッドを列挙してみました。
2012/12/29

Emulator を起動しようとしたら X Error of failed request

Android アプリを開発していて、いつものように Emulator を起動しようと思ったら、以下のようなエラーが出てしまいました。
Starting emulator for AVD 'Nexus7'
X Error of failed request: BadRequest (invalid request code or no such operation)
Major opcode of failed request: 139 (ATIFGLEXTENSION)
Minor opcode of failed request: 66()
Serial number of failed request: 13
Current serial number in output stream: 13
ちなみに、環境は以下のような感じ
  • Ubuntu 12.04 LTS
  • グラフィックボード GV-R455D3-512I
  • Android SDK 21
  • Eclipse 4.2 (Juno) SR1
  • ADT 21
で、探してみると以下にヒントがありました。
android - Error on starting emulator for avd after adt 20 install - Stack Overflow

どうも ADT の問題というより、グラフィックボードのドライバの問題の可能性が。
という訳で、ドライバを再インストールしてみました。

参考
穀風: Ubuntu 12.04 LTS に RADEON HD 4550 ドライバを入れたらデュアルディスプレイが出なくなった

すると、問題なく Emulator が起動するようになりました。

2012/12/28

Stunnel4 on Ubuntu が起動しない

Ubuntu 12.04 LTS に stunnel をインストールしてみました。

$ sudo apt-get install stunnel4
$ sudo cp /usr/share/doc/stunnel4/examples/stunnel.conf-sample /etc/stunnel/stunnel.conf

/etc/stunnel/stunnel.conf を適当に編集して、実行。
すると、以下のようなエラーが出てしまいました。

$ sudo /etc/init.d/stunnel4 start
SSL tunnels disabled, see /etc/default/stunnel4

/etc/default/stunnel4 の中を見てみると、以下のような一文が。
# Change to one to enable stunnel automatic startup
ENABLED=0
なるほど。
ENABLED を1にしないといけないということですね。
というわけで、以下のように修正。
# Change to one to enable stunnel automatic startup
ENABLED=1

実行できました。
$ sudo /etc/init.d/stunnel4 start
Starting SSL tunnels: [Started: /etc/stunnel/stunnel.conf] stunnel.


ところで、 /etc/stunnel/README を読んでいたら、以下のように書いてありました。
In order to have the tunnels start up automatically on system boot you must *also* set ENABLED to 1 in /etc/default/stunnel4
最初に読んだのに見落としていた…orz

2012/12/22

ScrollView を使わないで TextView に スクロールバーを表示する

Android の ScrollView、便利なのですが、内容にあわせて高さを変更したい場合などには向いていません。

特に、TextView の最大高を行数で指定したい場合、ScrollView を使用することが出来ません。
まぁ絶対使えないのかと言われると不可能ではないと思いますが、かなり面倒くさいことになると思います。

では、簡単に出来る方法は無いのかというと、View には Scrollbar を表示する機能がデフォルトでついているので、これを利用することが出来ます。
参考:Android TextView with scrollbars and maxHeight - Stack Overflow

まず、生成する TextView を以下のように定義します。
<TextView
    android:id="@+id/text_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:singleLine="false"
    android:maxLines="3"  // ←ポイント
    android:scrollbars="vertical" />

上記のように maxLines を指定しておくと、使用しているフォントサイズにあわせて TextView の高さを自動調整してくれます。

さて、このままでスクロールしてくれれば本当に簡単なのですが、残念ながらそこまで簡単ではありません。
以下のコードを Java 側に記述しておく必要があります。
(大抵の場合は Activity.onCreate に書いておけばよいでしょう。)
TextView textView = (TextView)findViewById(R.id.text_view);
textView.setMovementMethod(ScrollingMovementMethod.getInstance());

これで TextView の中身がスクロールするようになります。

ちなみに、参考にしたサイトには、以下の記述があります。
android:textColor="@android:color/secondary_text_dark_nodisable"
これは、Android 2.3 以前では、TextView をクリックした時に文字色が反転してしまうため、文字色を灰色にすることで、その問題を防ぐという意味があります。
しかし、これを書いてしまうと TextView の文字色が灰色になってしまうので、ベストな方法とは言い難いです。

この問題は、 android.Theme.Dark の場合にのみ起こるようなので、android:Theme.Light 等を Application や Activity の theme として設定すれば回避することが出来ます。
もちろん、全体のテーマから変更されるので、全体的に白を基調としたデザインに変更されてしまいますが、Google としては白基調を推奨しているようなので、なるべくなら白基調でうまく作っていくのが良いでしょう。


注:
今回の方法では指に追従するスクロールになってしまいます。
フリックで自動スクロールするようにするためには、 ScrollingMovementMethod を継承した独自の MovementMethod を作成する必要があります。