ラベル Android の投稿を表示しています。 すべての投稿を表示
ラベル Android の投稿を表示しています。 すべての投稿を表示

2013/06/22

カスタム属性作成時の注意点

先日、自分のプロジェクトにdeclare-styleableを追加したらビルドが出来なくなったのでメモ的な。

環境:
IntelliJ 12.1.4、Android Studio 0.1.6
SDK 22.0.1、Build-tools 17

結論:
idリソースと重複する名前のdeclare-styleable > attr > enum (flag)を定義することは出来ない

具体的には、以下のように定義したidと同じ名前を持つenum、flagが定義できない。レイアウトXML等で『android:id="@+id/sample"』と設定している分には問題無いのだけれど。。。

↓コンパイルエラー

↓OK

2013/06/01

レイアウトxmlにViewの追加情報を仕込む

レイアウトxmlからViewを取得する時に、その取得対象が固定的な内容だったらFragmentに固定で書いても良いけれど、パースするxmlがコロコロ変わる場合はどのViewにどの情報を表示して良いか分からないよね!

→ xmlに仕込みを入れておけばいいじゃない!!(楽観視)


サンプル:TextViewに曜日情報を仕込んで、Activityから取得する。


こんなカスタム属性を用意しておけば、ViewのIDと日付を同時に取れます。


レイアウトxmlにこんな感じでカスタム属性を仕込みます。3行目は自分のアプリ名。namespaceのnxは「noxi」の略なので自分に合ったものに変えることをお勧めします。


android.view.LayoutInfleter$Factoryを実装したクラスを作ります。これを実装することで、xmlパースの処理をフックすることが出来ます。


LayoutInflater#fromでLayoutInflaterを取得し、setFactoryで今回作成したクラスをセットします。ちなみにLayoutInflater$Factory2とかあるらしいけど、違いは親のViewGroupが引数に入るかどうかとAPI11なこと。

2012/02/28

SparseArrayメモ

ADT17が間もなくリリースされるそうですが、Lint先生にパフォーマンスに関する項目が追加になるそう。
Floatでjava.lang.Mathの各メソッド使うのは無駄だからandroid.util.FloatMath使えとか、Map<Integer, E>は無駄だからSparseArray使えとか。

私自身FloatMathは知っていたけれどSparseArrayはListViewのマルチチョイスモードで選択位置の取得の返り値がSparseBooleanArrayってことくらいしか知らなかったので、SparseArrayについてのメモ。
注)大分適当です


Q. SparseArrayって何?
A. キーがintでListっぽくもMapっぽくも使える何か。

Q. どう使うの?
A. Map<Integer, E>をそのままSparseArrayに書き換えればおk。

Q. キー一覧や値一覧ってどうやって取得するの?
A. forループやwhileで回して頑張れ。


値がBooleanやIntegerの場合にはSparseBooleanArrayやSparseIntegerArrayが実装されているのでそっちを使おう。
あんまりJavaの内部のことを知らないのでintとIntegerがどれくらい違うのかが分からないのだけれど、Androidで利用する分にはパフォーマンスが上がるのでしょう。


SparseArrayは内部で
private int[] mKeys;
private Object[] mValues;
private int mSize;
を管理していて、SparseArray#putで中身を突っ込むとキーと値がそれぞれに格納される。Parcelに突っ込むときはParcel#writeSparseArrayってメソッドがあるのでそれを使うか、sizeとkey、valueをループ回して突っ込もう(Parcel#writeSpaseArrayの中身はループ回してるだけなので)。逆もしかり。


###
SparseArrayは日本語に訳すと疎な配列。それぞれの値に関連性が薄いんでしょう。

2011/12/17

他パッケージ(APK)のclassファイルを読み込む

ちょっと興味があって調べてみた。


結論としては
  • 他のパッケージのクラスファイルは読み込める
  • セキュリティー的に問題あるんじゃね?

某ブログには
  • SharedUserIdを共有して
  • 共有Contextを作成すればできる
なんて書いてあるけどこれは嘘。以下、その方法

まずAndroidの標準的なリソース共有方法であるContextの共有から調べてみた。 これでClassを作成しようとすると怒られます。
。。。ん?
この部分が怪しい。
と言うわけでdalvik.system.PathClassLoaderをちょっと見てみると、 mDexとかmZipとか、何となくAPKパッケージを探していそう。コンストラクタを見てみると ビンゴですね。「:」で第一引数を区切ってそこからdexファイルを取得しようとしています。
PathClassLoaderを生成するときの第一引数はクラス名ではなくAPKファイル名を指定しなければいけないようです。


つまりこういうこと

実際にやってみて驚いたのが、これを実行するのにSharedUserIdが同一である必要は無いし、電子署名が一致してる必要も無いこと。これで既存アプリの中身に直接アクセス出来ちゃいます。
試してはいませんが、リソースにもこれで直接アクセス出来てしまうのかもしれませんね。

ちなみにAndroid4.0でこのPathClassLoaderの継承元がjava.lang.ClassLoaderからdalvik.system.BaseDexClassLoaderに変わっているため、同じ方法でアクセス出来ないかもしれません。要注意。これから調べる。
どうやらAndroid4.0でもいけるっぽい? ソースコードぱっと見アウトに思えたけど、API14エミュで動いた。

最後に、例に挙げているjp.co.noxi.weathernow.Commonは実際のアプリには存在しないクラスです。

2011/09/25

Windowsでメーカー製USBドライバーを利用せずにADBで接続する

Windowsで利用していると実機を認識させるのにUSBドライバーを毎回インストールするのは面倒臭いです。
実際はメーカーのUSBドライバーを利用せずとも、Android SDKで入手できるGoogle製のドライバーを数行書き換えるだけで利用できるらしいです。


...android-sdk\extras\google\usb_driver
に「android_winusb.inf」というファイルがありますが、これに2行ほど加えるだけ。


まずは端末のハードウェアIDを確認します。
認識させたい端末を接続するとデバイスマネージャー上で不明なデバイスとして登録されているはずです。プロパティー>詳細>ハードウェアIDを確認すると

こんな文字列が得られます。

今回必要なのは
USB\VID_04DD&PID_939A&REV_0100&MI_01
この部分です。


上に記したandroid_winusb.infを開くと こんな文字列が見られるかと思います。,
ここに こんな感じで2行書き加えればOKです。
ちなみにこれは64ビット版Windowsの場合ですので、32ビット版を利用中の場合は[Google.NTx86]下に書き加え。。。た方がいいかもしれません?(未検証)


これを書き加えたらデバイスマネージャーから手動で上記フォルダーを指定してドライバーのインストールをすれば終了です。

2011/02/21

ContentProviderを利用した画像の出力について

前回の記事で、「ImageView#setImageURI」に直接イメージファイルを設定することが出来ないと分かりました。じゃあ、どうすればいいのか。

・Raw Bitmap Data(?)を出力できる何か

を介せばいいので、それが何かを探しました。結論として、タイトルにあるとおり、ContentProviderを利用することで無事出力できました。


ではではその方法を丸々どどんんと紹介。
ちなみに、基本的なContentProviderの利用方法を紹介する気はありません(というか私が知りません)。ここでは外部に画像を出力する方法のみを紹介します。

Manifest.xmlの一部

以下ではnameを「Provider」、autoritiesを「jp.co.noxi.weathernow.contents」にします。
autoritiesはこのProviderにアクセスするためのものです。

で、Provider本体は

以上です。
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException
をオーバーライトすれば画像を出力できました。
今回は画像出力だけが目的なので他のメソッドは何もいじりません。


あとは

上で設定したAuthoritiesはcontent://のあとに続く文字になります。


ここまでたどり着くのに今日の午後全て潰した...疲れた。

ImageView#setImageUriについて

WeatherNowのホームウィジェットで、次に実装する機能をテストしていたらどうやらIntentの転送量オーバーで表示が更新されない。うーむ...

RemoteViewsで使えるImageViewメソッド?は
・setImageViewResource (アプリのリソースファイルを表示)
・setImageViewBitmap (Bitmapを表示、これで転送量オーバーに)
・setImageViewUri (Uriから表示)


SDカード内の画像ファイルを表示させたいので、残りのsetImageViewUriを試してみた。で、ここで問題が。
試したコード:


結果:
Uri failed on bad bitmap uri: file:///sdcard/weathernow/plugin/image/test/icon_100s
と怒られました。でも何が原因なのか、全く分からない。

2時間近く悩んだ挙句、「分からないならAndroidのソースコードを見ればいいじゃない!」という結論に

ということで、ImageView#setImageURIから見てみましょう。

なにやらresolveUri()が呼ばれている。じゃあresolveUri()の中身はというと、

ImageView#resolveUri

今回はFileを読み込みたいので、ContentResolver.SCHEME_FILEの部分

Drawable#createFromStreamが呼ばれ、更にContentResolver#openInputStreamが呼ばれているらしい

ではまずCotentResolver#openInputStreamは

UriがFileの場合、new FileInputStream(uri.getPath())が呼ばれていただけでした。

じゃあDrawable#createFromStreamというと

createFromResourceStreamが呼ばれている。見てやろうじゃないか。

Drawable#createFromResourceStream



で、更にBitmapFactory#decodeResourceStreamを見てみる。


BitmapFactory#decodeStream


...ん?w
The input stream that holds the raw data to be decoded into a bitmap.


つまりあれか。ここまで見て、BitmapのRawデータを渡さないとだめっぽいと理解。(英語の解釈を間違えているだけかもしれないけど)。


結論:
ImageView#setImageURIやRemoteViews#setImageViewUriで普通にファイルを参照することは出来ない。

まして(名前からして出来そうな) 
ウェブ上のイメージファイルなんてもってのほか 
である。


PS.
凄い誤解があるかもしれません。
間違いがあればぜひこちらまで。
次回に続く。