i++

プログラム系のメモ書きなど

Android : Error:Execution failed for task ':app:packageRelease'. > Unable to compute hash of .... build\intermediates\classes-proguard\release\classes.jar

ProGuard を有効にした Signed apk を作成しようとした際に発生しました。

Error:Execution failed for task ':app:packageRelease'.
> Unable to compute hash of (プロジェクトのフォルダ)\app\build\intermediates\classes-proguard\release\classes.jar

compute hash of で示されていたファイルは存在しておらず、どうやら ProGuard で Warning が検出された場合に、このファイルが生成されないために起こるエラーのようです。

なぜかこのエラーが発生した際のログには ProGuard の Warning 表示がなかったのですが、ビルドし直すと大量に Warning はあったので、proguard-rules.pro に -dontwarn 行を加えたところエラーが解消しました。

自分の場合は Kotlin を使用したため Kotlin 関係の Warning が大量に出ていて、以下の行を追加しましたが、使っているライブラリによって必要な -dontwarn は異なり、参考先では java.nio.filecom.google.android.gms に対して -dontwarn を行っていました。

-dontwarn kotlin.dom.*
-dontwarn org.w3c.dom.events.*

ProGuard は毎回鬼門です。。。

参考

Android : java.lang.RuntimeException: Missing type parameter (ProGuard + gson)

原因は gson を使っていた + gson 用の ProGuard の設定をしていなかったことでした。ProGuard によって難読化されたことで serialize / deserialize 対象のタイプ、クラスが正しく参照できなくなってしまい例外を引き起こしていたようです。

参考先の proguard.cfg の内容を proguard-rules.pro にコピーして、Application classes の部分を自分のアプリで serialize / deserialize しているオブジェクトに書き換えることで、解決しました。

参考

Android : android.view.InflateException: Binary XML file line: Error inflating class android.support.design.widget.NavigationView

今回の NavigationView については自分の場合は ProGaurd が原因で、以下の行を proguard-rules.pro に書き加えることで、実行時に表題の InflateException が発生することはなくなりました。

-keep class android.support.v7.widget.LinearLayoutManager { *; }

Issue Tracker によると support library 23.0.1 では発生せず、23.1.0 で発生しているようなので、いずれ修正される案件だとは思われますが、しばらくはこのワークアラウンドが必要そうです。

※ InflateException には他にも原因が考えられるため、原因が ProGuard とは限りません。

参考

Android : Overflow メニューにアイコンを表示する

Overflow メニューに入れられたメニュー項目はそのままではアイコンが表示されませんが、以下の方法でアイコン表示を行うことができました。

f:id:tkyjhr:20151107113525p:plain:w360

コードで実現するバージョン

  • 利点
    • 標準的なメニューの見た目、挙動を保てる
  • 欠点
    • Reflection を使用しているので将来的にも動き続けるかは保障できないと思われる

具体的な方法はこちら
Reflection を使って、メニュー作成時に Menu.setOptionalIconsVisible を呼び出しています。

回答では onMenuOpened() を使っていますが、Fragment のメニューで実現する場合は onCreateOptionsMenu に同じコードを入れて実現できました(featureId のチェックは省略)。コメントには onPrepareOptionsMenu を使っている方がいましたが、onCreateOptionsMenu で一度呼ぶだけで良さそうです。

また、proguard を使う(gradle で minifyEnabled true を指定)と、クラス名及びメンバー名が難読化されてそのままの設定では動かなくなってしまうので、プロジェクト中の proguard-rules.pro に以下の行を追加する必要があります。

-keep class android.support.v7.internal.view.menu.MenuBuilder { void setOptionalIconsVisible(boolean); }

メニュー xml のみで実現するバージョン

  • 利点
    • 簡単にできる
  • 欠点
    • Overflow アイコンを自分で用意する必要がある(標準で使われる Drawable はアプリからは参照できない模様)
    • どのメニュー項目が Overflow メニューに配置されるかを決めておく必要がある(動的に変更できない)

具体的な方法はこちら
Overflow のアイコンと見せかけたメニューを置いて、そのメニューをクリックするとアイコンのあるサブメニューが開くという仕様です。上に挙げた欠点を許容できるのであれば、こちらが安牌のように思います(私はアイコンを設定する必要性がある点が扱いにくく感じたので、コードで行う方法を採用しましたが…)。

参考

Android : Can't bind to local 8600 for debugger 確立された接続がホスト コンピューターのソウトウェアによって中止されました

AndroidStudio でアプリを実機デバッグしようとした際に遭遇しました。

デバイスを抜き差しするだけでは直らず、

  1. デバイスの USBケーブルを抜く
  2. AndroidStudio を終了する
    • Waiting for process detach ダイアログが終わらなかったので強制終了
  3. AndroidStudio を起動する
  4. デバイスを USBケーブルで繋ぐ
  5. デバッグ実行開始

で再びデバッグができるようになりました。
確認できていないので不明ですが、もしかしたら AndroidStudio の再起動だけで良かったのかもしれません。

Kotlin : ビット演算メモ

&| という記号ではなく andor を使います。

また、|=&= といった複合代入演算子形式の記載方法はありません。

Java/C系言語での書き方 Kotlin での書き方
x &= y x = (x and y)
x |= y x = (x or y)
x ^= y x = (x xor y)
~x x.inv()

※ and や or も x.and(y) のように呼び出すことが可能です。

参考

Android : SwipeRefreshLayout の更新中 Indicator を起動時に表示する

onCreateView で直接 SwipeRefreshLayout.setRefreshing(true) をしても表示されないので、post を使って少し遅らせてから refreshing が true になるようにします。

SwipeRefreshLayout の onMeasure が呼ばれて、サイズが確定してから refreshing を true にしないと上手く表示されためだそうです。

mSwipeRefreshLayout.post(new Runnable() {
    @Override
    public void run() {
        mSwipeRefreshLayout.setRefreshing(true);
    }
});

参考