2019/06/24

io.grpc.ManagedChannelProvider$ProviderNotFoundException が発生した時の対処方法

[Google Photos API](https://developers.google.com/photos/) の Java クライアントライブラリを使おうとしたところ、以下のようなエラーが出てしまいました。

```
io.grpc.ManagedChannelProvider$ProviderNotFoundException: No functional channel service provider found. Try adding a dependency on the grpc-okhttp, grpc-netty, or grpc-netty-shaded artifact
```

> Try adding a dependency on the grpc-okhttp, grpc-netty, or grpc-netty-shaded artifact

とのことなので `ManagedChannelProvider` の実装が必要なことはわかりました。
が、「どうやって指定するのよ…」と悩むこと小一時間。

2018/02/20

信頼できない ZIP ファイルは ZipInputStream で開いてはいけない

@Java 1.8.0

`ZipInputStream` から取得した `ZipEntry` の `getSize()` は `-1` になることがあります。

```java
`highlight: 6;
    private void read(InputStream is) throws IOException {
        ZipInputStream zis = new ZipInputStream(is);
        ZipEntry entry;
        while ((entry = zis.getNextEntry()) != null) {
            // getSize() が -1 になることがある
            Log.d(TAG, entry.getName() + "'s size is " + entry.getSize());
        }
    }
```

2016/08/04

最新版の update-java-alternatives は javac を更新してくれない

2018/2/12 追記
java-common 0.59 で対応されたようです。
ただし、java-common 0.59 の適用は Ubuntu 17.10 からです。ご注意を。
@[Ubuntu](http://www.ubuntu.com/) 16.04 LTS

先日、[update-java-alternatives に Oracle java も追加する](https://kokufu.blogspot.jp/2016/07/update-java-alternatives-oracle-java.html) という投稿をしたのですが、
使っていると想定した動作をしていないことがわかりました。

2016/07/31

update-java-alternatives に Oracle java も追加する

@[Ubuntu](http://www.ubuntu.com/) 16.04 LTS

2016/8/4 追記
最新の update-java-alternatives は javac 等を更新してくれないバグがあります。 一時的なものだと思われますが、ご注意ください。

[穀風: 最新版の update-java-alternatives は javac を更新してくれない](https://kokufu.blogspot.jp/2016/08/update-java-alternatives-javac.html)
`update-java-alternatives` には `--install` のようなコマンドがないため、簡単に対象を追加することは出来ません一般的にはパッケージから入れた時に自動的に追加される。 ただ、その中身は単なる `update-alternatives`-java- がついていない のラッパースクリプトなので、動作を理解すれば、任意の JDK (JRE) を手動で登録して、切り替えられるようにすることが可能です。 今回は [Oracle](http://www.oracle.com/technetwork/java/javase/downloads/index.html) から jdk-8u101 をダウンロードして追加してみました。
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/07/28

Android JUnit で Parameterized test case

@Android 2.3.3 (API 10) 以降

先日、
JUnit3 で Parameterized test case (1)
JUnit3 で Parameterized test case (2)
というエントリを書きましたが、本当は、Android JUnit で Parameterized test をしたかったのです。
Native Java Project なら、おとなしく JUnit4 を使っておけば良いわけですから。

というわけで、早速 JUnit3 で Parameterized test case (2) で作成したコードを Android JUnit に移植してみました。

今回のプロジェクトは以下にアップしてあります。ご自由にお使いください。
AndroidJUnit3Experiment.zip
2012/07/27

JUnit3 で Parameterized test case (2)

昨日、JUnit3 で Parameterized test case (1) というエントリを書いたのですが、その後いろいろいじっていると、ちょっと不満が出てきたので改造してみました。

本日のコードも以下にアップしてありますので、ご自由にお使いください。
JUnit3Experiment_02.zip

昨日の問題点

一番の不満は、テストを走らせるときに、AllTests.java を選択してから走らせなければならないということ。
「全部走らせる」 = 「プロジェクトを選択して Run」 が Eclipse っぽいような気がします。

JUnit3 で Parameterized test case (1)

JUnit4 には Parameters アノテーションがあって、同じテストをパラメータを変えて実行することができます。
しかし、JUnit3 にはそのような機能がないため、本来はパラメータ毎にテストメソッドを記述しなければなりません。
なんてイマイチな仕様なんだ…

しかし、よく考えてみると、 TestSuite を利用すれば、JUnit4 と同じように Parameterized test が出来ることに気づきました。
以下、やってみた結果です。

今回、作成したプロジェクトは以下においてあります。
ご自由にお使いください。
JUnit3Experiment_01.zip

2012/7/28 追記
ちょっとだけ不満が残ったので、改造してみました。
穀風: JUnit3 で Parameterized test case (2)
2012/02/17

setOnClickListener の実装方法

Android プログラムを書いていると、イベントリスナを実装することは日常茶飯事ですが、「インターフェースを実装した実体であれば何でもよい」という緩い制約のため、いろいろな書き方があります。

普段何気なく使い分けているのですが、どのように使い分けているのか自分の整理も含めて書いてみることにしました。
とりあえず、思いついた4つを書いておきますが、この辺の分け方は恣意的です


  1. 既存のクラスにインターフェースを実装する
    public class MyView extends View
            implements android.view.View.OnClickListener {
        // 他のコンストラクタは省略
        public MyView(Context context) {
            super(context);
    
            setOnClickListener(this);
        }
    
        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
        }
    }

    このように、自分自身にインターフェースを実装して、onXXXListener に this を与えてやる方法です。
    この方法、よく見かけるのですが、私は多用しないようにしています。
    例えば、以下のように Activity に実装した場合のことを考えます。

    public class MyActivity extends Activity implements OnClickListener {
        /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
    
            View titleView = findViewById(R.id.title);
            titleView.setOnClickListener(this);
        }
    
        @Override
        public void onClick(View v) {
            // TODO Auto-generated method stub
        }
    }

    この場合、Viewの数が増えてきた場合に対応できませんし、それを置いておいたとしても、「titleView をクリックしたら、Activity の onClick が呼ばれる」という状況は分かりにくいこと極まりません。
    私は、「名は体を表す」ように実装してあげるように心がけるべきだと思います。

  2. 匿名クラスを使う 1
    public class MyActivity extends Activity {
        /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
    
            View titleView = findViewById(R.id.title);
            titleView.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    // TODO Auto-generated method stub
                }
            });
        }
    }

    この方法もよく見かけますし、私もよく使います。
    慣れるまではちょっと見にくいかもしれませんが、慣れてしまえば、簡単な処理なら内容をすぐ確認できるため便利です。
    ただ、複雑な処理を書く場合は見にくくなったりする難点があります。
    また、クリックされた時の処理が状態によって変わったりする場合、setOnClickListener を呼ぶたびにインスタンスが生成されるため、多少パフォーマンス的に難ありだと思われます。

  3. 匿名クラスを使う 2
    public class MyActivity extends Activity {
        /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
    
            View titleView = findViewById(R.id.title);
            titleView.setOnClickListener(showAlertDialog);
        }
    
        private final OnClickListener showAlertDialog = new OnClickListener() {
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                
            }
        };
    }

    「匿名クラスを使う 1」の問題を回避するために私が時々使う方法です。
    メンバ変数に OnClickListener への参照を持たせておくわけです。
    クリックしたときの処理が複雑で長くなる場合や、別々のボタンに同じ処理を持たせたい場合に便利です。
    ただし、メンバ変数を持たせると、いろいろなボタンで使いまわせなくなるので要注意です。
    この記述、あまり見かけないのは、そういう意味でJavaの思想からずれているからかもしれません
    (まー、1番目の方法「既存のクラスにインターフェースを実装する」でも、複数のボタンに対して使いまわすと、同じ問題が起こりますけどね…)
    2012/2/22 追記 「あまり見かけない」というのは勘違いでした。Android のソースコードの中でも結構使っていますね。

    この方法で一番のメリットは、インスタンスの生成が1度きり。というところです。
    Android のようなリソースが限られた環境の場合は、意味がある場合もあります。しかし、メリットとデメリットをよく理解した上で使用しないと痛い目にあうかも…。

    また、この方法、クラスは匿名なのですが、メンバ変数に名前が必要で、その命名が難しいことが難点です。
    私は、setOnClickListener 近辺を読んでいるときに処理の流れがわかるよう、showAlertDialog のように、動作を表す変数名にするようにしているのですが、この方法だと Listener であることが分かりにくくなってしまいます。
    だけど、showAlertDialogListener では意味が変わってしまいます。
    本来なら、 onClickListenerForShowAlertDialog とでも付けるのが良いのでしょうが、「長い割にわかりにくいかなー」と思い採用していません。

  4. リスナクラスを定義する
    public class MyActivity extends Activity {
        /** Called when the activity is first created. */
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
    
            View titleView = findViewById(R.id.title);
            titleView.setOnClickListener(new ShowAlertDialog());
        }
    
        private class ShowAlertDialog implements OnClickListener {
            @Override
            public void onClick(View v) {
                // TODO Auto-generated method stub
                
            }
        };
    }

    ある意味、一番王道です。
    OnClickListener の実装をきちんと定義してあげるわけですね。
    この問題も、3番同様、名前の付け方が難しいという問題を持っています。

    上記では private なインナークラスとして実装していますが、インナークラスとして実装出来るような場合は、3番の方が使い易いでしょう。(インスタンスの生成タイミングを制御したい場合などは別ですが)
    この方法は様々なクラスで同じイベントリスナを使いたいというような場合に使えます。(そういうケースはあまり多くないと思いますが…)


これらの方法、Activity と View のようにライフサイクルを共にしている場合は問題ありませんが、センサー等にリスナを登録する場合、Activity が見えなくなっても、センサからの参照は生きているということに気を付けてください。
放っておくとOutOfMemoryで落ちてしまいます。
その辺についてはまた別の機会に書こうと思います。
2012/01/16

Google APIs の Javadoc が表示されなくなった

2012/01/19 追記
ごめんなさい。以下に書いてある方法は使えませんでした
この方法を実行した後に実機で動作させようとすると、以下のようなエラーが発生してしまいます。
java.lang.IllegalAccessError: Class ref in pre-verified class resolved to unexpected implementation
動確しないで、不確かな情報を載せてしまい申し訳ありません。
言い訳なんですが、ちょうど動作が不安定になるような大きな変更を入れてる最中にJavadocが表示されなくなった事に気づき、結構書き換えてる時だからJavadocが無いと余計不便で調べてみたのです。
で、変更してみたけど、もともとうまく動かないプロジェクトでやってたから動確せず。で別件に手をとられ放置…という流れでした。
そういうのブログに書くなよって話ですよね。いや、お恥ずかしい…




Google APIs [Android 4.0.3] を使うと、Javadoc (インテリセンスっぽいやつ)が表示されず、
Note: This element has no attached source and the Javadoc could not be found in the attached Javadoc.

というようなエラーが表示されてしまいます。

おかしいと思って、ライブラリを右クリック → プロパティ
2011/08/31

Android SDK を再インストールしたら Javadoc が表示されなくなった

2012/01/17 追記
別件で同じ問題が起こり、下記の付け焼刃的な解決方法ではうまく行かなくなったので、もう少しましな方法を見つけました。
Google APIs の Javadoc が表示されなくなった



諸事情で Android SDK を再インストールしました。(installer_r12-windows.exe)

そうしたら、インテリセンスライクなやつがうまく動かなくなって、
Note: This element has no attached source and the Javadoc could not be found in the attached Javadoc.
っていうエラーが…

で、よくよく見てみると、SDKのインストールディレクトリが

C:\Program Files\Android\android-sdk

になっている。