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

2014年3月18日火曜日

9PatchはBackGround要素だけ適応される。

書きたいことはたくさんあるのですが。また見つけたAndroidのバグとか(いい再現方法が見つからず報告できてません)。

9PatchはBackGround要素だけに適応されます。
ImageViewのsrc要素には適応されません。 ご注意を。

そして9patchの作成はこれを使うとよい。
android-sdk\tools\draw9patch.bat

2014年1月11日土曜日

Android のRadioGroupは子要素のみだけGroupになる。

すごいつまづきました。
そして、不便だと思いました。

解決法などは
こちらのブログを参考してください。

AndroidのRadioGroupを改造し、子孫要素を全部グループ化できるようにした http://blog.maripo.org/2011/09/android-deep-radio-group/

2013年11月6日水曜日

[Android]Calendarクラスのバグ?

注)比較的難易度高めの記事です。
Android APIのバグの可能性もあるので、もしそうでしたら、報告する場所教えてください><
(何か賞金とかもらえるなら折半で!)

Calendar使う場合、こういうことをする時があります。

DAY_OF_WEEK  
はcalendar オブジェクトが何曜日かというのを指定します。

WEEK_OF_YEAR
は calendar オブジェクトが一年の何週目(最大52週)というのを指定します。

この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

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を設定しないといけないみたいだし。

(自分が知ったかぎりもの)
各対応するもの表にしました。

(軽い動作確認は行いましたが、コードの正確性は保証いたしませんのでご注意ください。)


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のコンストラクタにはありません。


なので配列の要素を全部渡すときは これがエレガントな方法です。


(2013/11/30 追加  yozaさんthx)




今回主にJavaに関してのことでしたが Androidアプリでも同様です
(そもそもきっかけはこちら)

ListViewの表示でよく使う ArrayAdapterで なぜかremove()をするとなぜか失敗していたので調べた結果たどり着いたのが

ArrayAdapterのコンストラクタのこの部分。
Arrays.asList()が使われてます。


つまりこれで作成されたArrayAdapterの内部で使われるリストは不変になってしまいます。

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> {
public static void method() {
}
@Override
protected Void doInBackground(Void... params) {
return null;
}
}
上のクラスの staticメソッドに別スレッドでアクセスすると
 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 が発生してアプリが落ちてしまいます。


ちょっと原因をさぐってみました。

公開されてるAndroidのソースコード(今回は4.0.4)のAsyncTaskをみて


607行目
private static class InternalHandler extends Handler {
・・・
}
さらに

190行目
 private static final InternalHandler sHandler = new InternalHandler();
が怪しいと判断 (判断するまでに至った理由は省略)

ちなみに static フィールドはClassがロードされた時に実行される (参考:static イニシャライザ)

ここでさきほどのExtendsAsyncTaskを以下のように変更
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スレッド
で行いましょう。

(というまとめでいいのかわかりませんが?)

私の設計が悪いのでは・・ということは、言ってはいけません