書きたいことはたくさんあるのですが。また見つけたAndroidのバグとか(いい再現方法が見つからず報告できてません)。
9PatchはBackGround要素だけに適応されます。
ImageViewのsrc要素には適応されません。
ご注意を。
そして9patchの作成はこれを使うとよい。
android-sdk\tools\draw9patch.bat
2014年3月18日火曜日
2014年1月11日土曜日
Android のRadioGroupは子要素のみだけGroupになる。
すごいつまづきました。
そして、不便だと思いました。
解決法などは
こちらのブログを参考してください。
AndroidのRadioGroupを改造し、子孫要素を全部グループ化できるようにした http://blog.maripo.org/2011/09/android-deep-radio-group/
そして、不便だと思いました。
解決法などは
こちらのブログを参考してください。
AndroidのRadioGroupを改造し、子孫要素を全部グループ化できるようにした http://blog.maripo.org/2011/09/android-deep-radio-group/
2013年11月6日水曜日
[Android]Calendarクラスのバグ?
注)比較的難易度高めの記事です。
Android APIのバグの可能性もあるので、もしそうでしたら、報告する場所教えてください><
(何か賞金とかもらえるなら折半で!)
Calendar使う場合、こういうことをする時があります。
DAY_OF_WEEK
Android APIのバグの可能性もあるので、もしそうでしたら、報告する場所教えてください><
(何か賞金とかもらえるなら折半で!)
Calendar使う場合、こういうことをする時があります。
DAY_OF_WEEK
はcalendar オブジェクトが何曜日かというのを指定します。
WEEK_OF_YEAR
WEEK_OF_YEAR
は calendar オブジェクトが一年の何週目(最大52週)というのを指定します。
この2つで、特定の日付を解決します。
(本当は YEAR (年)も設定する必要はありそうですが、なぜかAndroidでは必須ではない。)
一旦 オブジェクトが日曜日 というのを設定します。
さらにcalendar オブジェクトが一年の30週目というのを設定します。
つまり 2013年7月21日というのを設定しています。
なので、ここでは30が出力されます。
しかし、
と書いたら、なぜかWEEK_OF_YEARが反映されずに、
この2つで、特定の日付を解決します。
(本当は YEAR (年)も設定する必要はありそうですが、なぜかAndroidでは必須ではない。)
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
calendar.set(Calendar.WEEK_OF_YEAR, 30);
Log.d("tag", calendar.get(Calendar.WEEK_OF_YEAR) + "");
一旦 オブジェクトが日曜日 というのを設定します。
さらにcalendar オブジェクトが一年の30週目というのを設定します。
つまり 2013年7月21日というのを設定しています。
なので、ここでは30が出力されます。
しかし、
Calendar calendar = Calendar.getInstance();
calendar.set(Calendar.WEEK_OF_YEAR, 30);
calendar.set(Calendar.DAY_OF_WEEK, Calendar.SUNDAY);
Log.d("tag", calendar.get(Calendar.WEEK_OF_YEAR) + "");
と書いたら、なぜかWEEK_OF_YEARが反映されずに、
今週(2013年11月6日現在なら45)
が出力されてしまいます。
時間があったら、この問題を追ってみたいと思います。
ちなみに通常の Java(Java 7)ではこの問題は発生しないっぽいです。
参考:
Java API
http://docs.oracle.com/javase/jp/1.5.0/api/java/util/Calendar.html
Android API
http://developer.android.com/reference/java/util/Calendar.html
が出力されてしまいます。
時間があったら、この問題を追ってみたいと思います。
ちなみに通常の Java(Java 7)ではこの問題は発生しないっぽいです。
参考:
Java API
http://docs.oracle.com/javase/jp/1.5.0/api/java/util/Calendar.html
Android API
http://developer.android.com/reference/java/util/Calendar.html
2013年7月26日金曜日
[Android]ActionBarSherlockからSupport Library v18 のActionBarへの移行
先日、新しいNexus7とともにAndroid 4.3 が発表されましたが、新しいOSとともに発表されるのが、Android SDKのバージョンアップ!
個人的にはこっちのほうが楽しみだったりします。
さて、今回 Android SDK付属の Android Support Libraryがv18 になり
なんと(やっと?)Action Bar UI に対応しました。
http://developer.android.com/tools/support-library/index.html
設定方法はこちらの「Adding libraries with resources」をどうぞ
http://developer.android.com/tools/support-library/setup.html
さて、わたしは今まで ActionBarSherlock というありがたいライブラリを使っておりましたが、
http://actionbarsherlock.com/
公式で対応したということで移行処理をしてみました。
単純なものは、移行は簡単なのですが、もうちょっとGoogleさんには少し頑張ってもらいたかったところ。
相変わらず onCreate時にsetThemeを設定しないといけないみたいだし。
(自分が知ったかぎりもの)
各対応するもの表にしました。
(軽い動作確認は行いましたが、コードの正確性は保証いたしませんのでご注意ください。)
個人的にはこっちのほうが楽しみだったりします。
さて、今回 Android SDK付属の Android Support Libraryがv18 になり
なんと(やっと?)Action Bar UI に対応しました。
http://developer.android.com/tools/support-library/index.html
設定方法はこちらの「Adding libraries with resources」をどうぞ
http://developer.android.com/tools/support-library/setup.html
さて、わたしは今まで ActionBarSherlock というありがたいライブラリを使っておりましたが、
http://actionbarsherlock.com/
公式で対応したということで移行処理をしてみました。
単純なものは、移行は簡単なのですが、もうちょっとGoogleさんには少し頑張ってもらいたかったところ。
相変わらず onCreate時にsetThemeを設定しないといけないみたいだし。
(自分が知ったかぎりもの)
各対応するもの表にしました。
(軽い動作確認は行いましたが、コードの正確性は保証いたしませんのでご注意ください。)
2013年2月9日土曜日
[Java][Android]Arrays.asListについて
Javaには
Arrays.asList()という配列をリストに変換するメソッドがあります。
仕様上の問題で、配列ではなくリストで渡さないといけないというのが
たまーにあるので重要という程でもないですが、知っていると便利なメソッドです。
たまーにあるので重要という程でもないですが、知っていると便利なメソッドです。
こういうコードを書いてみました。
これを実行すると、asList.remove(0)で例外が発生します。
実は、Arrays.asList()で取得したリストは不変(addもremoveもできない)という仕様があります。
(ドキュメントにもちゃんと書いてあります)
(ドキュメントにもちゃんと書いてあります)
たまに忘れます...
ではこのArrays.asList()で取得したリストとは何なのでしょうか。
少し調査してみました。(Java6を対象にしています)
Eclipse でasListの部分をクリックして 宣言を開く (F3) をしてみます。
ArraysクラスのasList の宣言が見れます。
そうするとあれ??
ArrayListに引数のものを入れて返してるだけじゃないですか。
つまりasList()で取得したものはArrayListということになり、可変(addもremove)も出来るはず。
しかしここに落とし穴があり。
さらにこのArrayListのところで F3を押して ArrayListの宣言を見てみます。
(一部分のみ)
気づきにくいですが、これは Arraysクラスの中の内部クラスとして宣言されているものなのです。
我々がよく使うArrayListとは別物なのです。
ちなみにadd メソッドは ここでは宣言されてなくて extends のAbstractListを辿って
add(E element)を辿り
add(int index, E element)
の宣言部分
を見るとこのようになっております。
中身が例外だけ・・・・。(゚д゚)!
とりあえずこの仕組みによって例外が投げられているのですね。
ちなみに、通常のArrayListを調べると 同じくextends AbstractList されていますが、
きちんとオーバーライドでaddの中身が実装されています。
ちなみに
Arraysの中のArrayList(T[] array)という宣言は 通常のArrayListのコンストラクタにはありません。
今回主にJavaに関してのことでしたが Androidアプリでも同様です
(そもそもきっかけはこちら)
ListViewの表示でよく使う ArrayAdapterで なぜかremove()をするとなぜか失敗していたので調べた結果たどり着いたのが
ArrayAdapterのコンストラクタのこの部分。
Arrays.asList()が使われてます。
つまりこれで作成されたArrayAdapterの内部で使われるリストは不変になってしまいます。
JavaDocの説明に これで渡すと不変であると書いてないじゃないですか。。。orz
JavaDocの説明に これで渡すと不変であると書いてないじゃないですか。。。orz
(テストしてなかったこちらも悪いですけど)
まとめ
Arrays.asList で取得したリストは不変です。
宣言の中身を見ると、同名のArrayListが使われてます。(ややこしい)
不変の理由は、addやremoveの中身が無い実装のAbstractListのため
AndroidのArrayAdapterのコンストラクタで配列を渡すと不変リストになってしまうので注意です。重要
2012年10月31日水曜日
Nexus 7でのAppWidgetのサイズ
Nexus 7
(Resolution 800*1025,DPI 195dpi*201dpi ( tv dpi ) )
でのAppWidgetを設置する時、
xmlで記述する
<appwidget-provider>の属性 minWidthやminHeightで設定するDPIとその設置後のセルの大きさが以下のガイドラインに書かれてるものは違ったのでメモします。
App Widget Design Guidelines
Determining a size for your widget
結果だけ書くと、上記のページの表の表記に従うと
Portrait (縦長使用時)
n Columns = 100*n- 120 dp(minWidth )
n Rows = 70*n- 30 dp(minHeight ) 表のまま
Landscape(横長使用時)
n Columns = 70*n- 30 dp (minWidth ) 表のまま
n Rows = 87.9*n- 104 dp(minHeight )
という謎な感じになってました。
dpi とAppWidgetの関係について理解しきれてないところがあるかも知れませんが、
とりあえずメモ代わりに。
また、いろいろと面倒になりそうですね。。
2012年7月26日木曜日
AsyncTaskを継承してるクラスでのstaticメソッド呼び出しの罠
(API レベル4以上で再現する現象・・のはず)
staticメソッドを持った AsyncTaskを継承したクラス(ExtendsAsyncTask)を作成。
public class ExtendsAsyncTask extends AsyncTask<Void, Void, Void> {上のクラスの staticメソッドに別スレッドでアクセスすると
public static void method() {
}
@Override
protected Void doInBackground(Void... params) {
return null;
}
}
public class TestActivity extends Activity{
@Override
protected void onCreate(Bundle arg0) {
super.onCreate(arg0);
Runnable r = new Runnable() { @Override
public void run() {
ExtendsAsyncTask.method();
}
};
new Thread(r).start();
}
}
なんと
ExtendsAsyncTask.method(); の呼び出しで
java.lang.ExceptionInInitializerError が発生してアプリが落ちてしまいます。
java.lang.ExceptionInInitializerError が発生してアプリが落ちてしまいます。
ちょっと原因をさぐってみました。
公開されてるAndroidのソースコード(今回は4.0.4)のAsyncTaskをみて
607行目
private static class InternalHandler extends Handler {
・・・
}
さらに
190行目
private static final InternalHandler sHandler = new InternalHandler();
が怪しいと判断 (判断するまでに至った理由は省略)
ちなみに static フィールドはClassがロードされた時に実行される (参考:static イニシャライザ)
public class ExtendsAsyncTask {
public static void method() {
}
private static InternalHandler handler = new InternalHandler();これでもおなじく
public static class InternalHandler extends Handler {
@Override
public void handleMessage(Message msg) {
}
}
}
java.lang.ExceptionInInitializerError が発生しました。
さらにコンパクトに下記の様にしても同様です。
public class ExtendsAsyncTask {
public static void method() {
}
private static Handler handler = new Handler();
}
つまりHandler 周りが怪しい?
( Handler さんには昔、かなりお世話になっておりました。。)
そして次にActivity自体を以下のようにしてみます。
public class TestActivity extends Activity
{
@Override
protected void onCreate(Bundle arg0) {
super.onCreate(arg0);
Runnable r = new Runnable() {
@Override
public void run() {
new Handler();
}
};
new Thread(r).start();
}
}
java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
という例外が発生します。
ほほう。。
ちょっとググったところ、以下のページがとても参考になったので掲載しておきます。
つまり内部動作を理解すると
各スレッドで Looper.prepare() を呼び出す前にnew Hander()を呼び出すな ということです。
(この記事の発展にもあるように UIスレッド場合は、フレームワーク側が呼び出している)
つまり
public class TestActivity extends Activity
{
@Override
protected void onCreate(Bundle arg0) {
super.onCreate(arg0);
Runnable r = new Runnable() {
@Override
public void run() {
Looper.prepare();
new Handler();
}
};
new Thread(r).start();
}
}
こうすると落ちなくなります。
つまり、
public class TestActivity extends Activity
{
@Override
protected void onCreate(Bundle arg0) {
super.onCreate(arg0);
Runnable r = new Runnable() {
@Override
public void run() {
Looper.prepare();
ExtendsAsyncTask.method();
}
};
new Thread(r).start();
}
}
元のコードはこうしても落ちなくなります。
そして、注目したいのは
public class TestActivity extends Activity
{
@Override
protected void onCreate(Bundle arg0) {
super.onCreate(arg0);
new ExtendsAsyncTask();
Runnable r = new Runnable() {
@Override
public void run() {
ExtendsAsyncTask.method();
}
};
new Thread(r).start();
}
}
というように UIスレッド上でExtendsAsyncTaskのインスタンスを生成すると、
アプリが落ちることはありません。
アプリが落ちることはありません。
これらが(Looper.prepare()をされたあとの)UIスレッド上で実行されるためです。
private static final InternalHandler sHandler = new InternalHandler();
private static class InternalHandler extends Handler {
・・・
}
筆者の場合
ExtendsAsyncTask.method();を呼び出す前に
ほとんどUIスレッド上でnew ExtendsAsyncTask();
でインスタンスを生成していたのですが、
ある処理の時、ExtendsAsyncTaskのインスタンスを一度も生成せずに
(ExtendsAsyncTaskをクラスをロードせずに)
直接 ExtendsAsyncTask.method();を別スレッドで実行していたことが判明し、
問題が発覚し、原因を追求しました。
他の状態に依存しない public static メソッドは
どこで定義しても大丈夫だろうという思い込みがあったのは
確かです。
どこで定義しても大丈夫だろうという思い込みがあったのは
確かです。
まぁAndroidのバグではないと思いますが、つまづきやすい仕様というか
なんというかという感じですが。
何かの参考になっていただければ幸いです。
まとめ
AsyncTaskを継承してるクラスのpublic staticメソッド呼び出しはUIスレッド
で行いましょう。
(というまとめでいいのかわかりませんが?)
登録:
コメント (Atom)