2013年6月28日金曜日

Android搭載端末の調査に便利なサイト まとめ

Androidアプリの作成では様々な端末への対応を考慮しなければなりません。
現在どのような端末が出てるのか、調査に便利なサイトをまとめてみました。

まずはこちら、Google公式?のAndroid Device Galleryです。
かなりの数の端末が登録されていて国やキャリア、OS等の条件で検索できます。かなりの数なのでGoogle Playストアで承認されている端末が全部あるのかなと思いましたが、そこまでではないようです。
端末ごとにCPU・Camera・Display・OS Version・Storage and Memory・Battery・Connectivity等のかなり詳しい情報も見ることが出来ます。
Android Device Gallery
http://www.android.com/devices/

次はこちらWikipediaのAndroid端末一覧ページです。
2009年のHT-03Aから始まって、発売日順にメーカー・形状・OSバージョン・キャリア等を一覧で見ることが出来ます。
Android端末一覧
http://ja.wikipedia.org/wiki/Android%E7%AB%AF%E6%9C%AB%E4%B8%80%E8%A6%A7

次はスマートフォンデータベースです。
スマートフォン231機種のスペックをキャリア・メーカー・OSバージョン・性能・機能等の条件を指定して一覧で見ることが出来ます。
スマートフォンデータベース
http://smartphone.ultra-zone.net/

次は国内主要キャリアの端末を一覧でまとめているDevelopers AppKitBoxのサイトです。
キャリアごとにメーカー・OSバージョン・解像度・CPU等を一覧で見ることが出来ます。
Developers AppKitBox
Docomo
http://appkitbox.com/knowledge/android/2012/11/12/docomo-smartphone
AU
http://appkitbox.com/knowledge/android/2012/11/12/au-smartphone
Softbank
http://appkitbox.com/knowledge/android/2012/11/12/sb-smartphone
その他
http://appkitbox.com/knowledge/android/2012/11/12/other-smartphone

最後は主に画面のサイズ、解像度等を一覧で見ることが出来るSCREEN SIZ.ESというサイトです。
こちらの特徴として、独自の方法で計算された指標ではありますがpopularityとういう項目で端末の人気度を見ることが出来ます。
SCREEN SIZ.ES
http://screensiz.es/

以上参考までに。

2013年6月26日水曜日

間取りー図が5万ダウンロードを達成しましたー

このたび間取りー図が5万ダウンロードを達成しましたー。
これもひとえにダウンロードしていただいたユーザーの皆様のおかげです。
公開開始が2012年11月6日でしたので、約7か月半での達成となりました。


この間10回程のバージョンアップを行いました。ユーザーからの不具合報告や要望はありがたい限りです。
国別でみると日本が66.84%、アメリカ7.4%、他25.76%と意外に海外の方も利用して頂いているようです。Feet単位に対応してほしいなどの要望もあったのでVersion 1.2.0で対応したりもしました。

今後も機能追加や改善に励みたいと思いますので、よろしくお願いいたします。

2013年6月25日火曜日

dimen.xmlからのdip指定によるgetDimensionの落とし穴

使い方を間違っているだけなのに落とし穴と書いてると怒られそうですが、昨日修正を公開した間取りー図での不具合は、リソースのdimen.xmlでdip単位で書いてある値をSurfaceViewのボタンの大きさ指定に使っているのですが、ここで間違った計算をしているのが原因でした。

最近間取りー図のユーザーレビューで
ボタンが見切れてほとんど使えない
5インチフルHDの画面なんだけど、各種ボタン(+-や反転等の)の大きさが極端に合ってない
という報告が上がってきていて、ボタンはdipの値から計算してサイズ設定しているからそんなはずはないんだけどなぁと思いながら、対象の実機で確認してみると本来は


こうなるべきところが
と報告と同じくえらいでかいサイズになってしまっていました。
原因を探ってみたところ、どうやらxxhdpi(超高解像度)の端末で、このような現象になっている模様。
リソースでの指定は
  <dimen name="button_width">48dp</dimen>

こんな感じ、この値をプログラムでは
int bw = (int)(context.getResources().getDimension(R.dimen.button_width) * context.getResources().getDisplayMetrics().density + 0.5f);

このように値を取得・計算して、最終的にピクセル単位にしてボタンを描画していました。
要はこの計算が間違っていたのですが、どうやらgetDimensionはanyDensityがtrueの場合DisplayMetricsで単位変換されるということのようです。

つまり私はgetDimensionですでに単位変換されている値を、更に単位変換してしまっているので、xxhdpiの場合getDimensionでもとの3倍、それをさらに3倍しているということでした。
あまりこのような使い方をしてる人はいないかもしれませんが、お気を付けて…

参考:【教えてください】TextView等のテキストサイズについて
参考:Converting dp units to pixel units

2013年6月24日月曜日

"間取りー図"のバージョンアップを公開しました。

"間取りー図"、"間取りー図 Pro"のバージョン 1.2.2を公開しました。
修正点は一部の端末(Xperia Z、Garaxy S4等)において図形操作ボタンが大きすぎて、画面に表示しきれない問題を修正しました。
対象の方々にご迷惑をおかけしましたこと、この場を借りてお詫び申し上げます。

2013年6月21日金曜日

自作ライブラリ-SurfaceViewで画像の数字を表示

Androidアプリ・ゲームを作るときに、スコアやパラメータなど数字を表示したい場合が結構あります。
こんなときCanvas#drawText()で済めばいいんですが、見た目にこだわりたいときは画像を使う他ありません。 
やることは数字の画像を0から9まで用意して各桁の数字に合わせて位置を決めて描画するというだけですが、何回もでてくるので汎用的なクラスにしてしまったほうがいいかなということで作ってみました。 
まず0から9までの画像を用意。


表示用のクラスはこんな感じ

public class CvsNumber {
    public Rect res;
    public Bitmap[] images = null;
    public int number = 0;
    public int digit = 3;
    public boolean zerofill = false;
    public int top;
    public int left;
    public int width;
    public int height;
    public Paint paint = new Paint();
    private Rect src;

    public CvsNumber(int id, Context context, int[] resources) {
        images = new Bitmap[10];
        //0から9の画像をセット
        for (int i = 0; i < 10; i++) {
            images[i] = BitmapFactory.decodeResource(context.getResources(), resources[i]);
        }
        //1つ目の画像の大きさを取っておく
        src = new Rect(0, 0, images[0].getWidth(), images[0].getHeight());
    }

    public void draw(Canvas canvas) {
        int r = left + width; //描画範囲の右端
        int w = width / digit; //1桁当たりの描画幅
        int h = (w * images[0].getHeight()) / images[0].getWidth(); //1桁当たりの数字の描画高さ
        int t = top + ((height - h) / 2); //描画開始高さ
        int s = number % 10; //1の位の数字
        //1の位を描画
        canvas.drawBitmap(images[s], src, new Rect(r - (w * 1), t, r, t + h), paint);
        //digitで指定した位まで描画
        for (int i = 1; i < digit; i++) {
            if (zerofill || String.valueOf(number).length() > i) {
                s = (number / (int)(Math.pow(10, i))) % 10;
                canvas.drawBitmap(images[s], src, new Rect(r - (w * (i + 1)), t, r - (w * i), t + h), paint);
            }
        }
    }
}

表示結果はこんな感じ。
与えるパラメータは描画位置のtop,left,width,heightとnumber(値),digit(桁数),zerofill(0埋め)です。
 
四角い枠は指定した描画範囲をわかりやすいように表示してます。

一度作っておけば画像を差し替えれば、いろんなパターンで利用できて捗ること間違いなしです。
SurfaceViewに限らず自作Viewでも利用可能ですね。 

2013年6月19日水曜日

Androidアプリでデータをファイルで保存したい

Androidアプリでデータをファイルに保存したいことがあります。
ものによってはデータベースを使う方がいい場合もありますが、単体で出力したい場合に便利なのがシリアライズ。 データを1つのSerializableなクラスインスタンスにまとめておけばObjectOutputStream.writeObjectで簡単にファイルにすることが出来ます。
シリアライズのすごいところはそのクラスのフィールドがSerializableなクラスで構成されている場合には、出力コードを何にも書かなくていいんです。
たとえSerializableではないクラスがあったとしても、そこだけ自分で出力するかSerializableクラスに置き換えるだけでいいんです。

//データクラス
class S implements Serializable {
    private static final long serialVersionUID = 1L;
    public int id;
    public String name;
    public boolean visible;
    public S(int id) {
        this.id = id;
    }
}
//出力
S data = new S(1);
FileOutputStream fos = context.openFileOutput(filepath, Context.MODE_PRIVATE);
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(data);
oos.close();
//読込
FileInputStream fis = new FileInputStream(filepath);
ObjectInputStream ois = new ObjectInputStream(fis);
S data = (S)ois.readObject();
ois.close();
ファイルを読み込むときもObjectInputStream.readObjectで開いてキャストするだけで復元できます。 ただし、シリアライズではこんな落とし穴こんな注意点もありますので、お気をつけて…

2013年6月18日火曜日

SurfaceViewでの画像のタイル描画(繰り返し)

SurfaceViewを扱うとき背景のところを1枚絵で描画しているときはいいですが、小さい画像の繰り返しで済むような場合は、リソースの節約のためにもタイル(繰り返し)描画をしたほうがいいかと思います
ロジック的には下のような感じ、while分の中で描画したい大きさに達するまで位置を変えて繰り返し描くだけです。

//描画領域Rect
Rect r = new Rect(left, top, left + width, top + height);
//画像幅取得
int imgWidth = background.getWidth();
//画像高さ取得
int imgHeight = background.getHeight();
switch (layout) {
case BACK_FIT : //領域全体
    canvas.drawBitmap(background, imgRect, new Rect(r.left, r.top, r.width(), r.height()), paint);
    break;
case BACK_VREPEAT : //縦の繰り返し
    int sh = 0;
    while (sh < height) {
        canvas.drawBitmap(background, imgRect, new Rect(r.left, r.top + sh, r.width(), imgHeight), paint);
        sh += imgHeight; //画像の高さ分足す
    }
    break;
case BACK_HREPEAT : //横の繰り返し
    int sw = 0;
    while (sw < width) {
        canvas.drawBitmap(background, imgRect, new Rect(r.left + sw, r.top, imgWidth, r.height()), paint);
        sw += imgWidth; //画像の幅分足す
    }
    break;
}

最後の描画で描画領域を考慮していないのではみ出すことがありますが、それで困る場合は先日書いたSurfaceViewで描画範囲を限定するを利用するとよいでしょう。

2013年6月17日月曜日

AndroidのSerializableクラスでのtransient指定の落とし穴

Androidのと付けましたがJava全般の話ですね。
先日Serializableなクラスを継承したクラスの落とし穴という話を書きましたが、またしてもSerializeではまってしまいました。
落とし穴というか自分が無知だっただけなんですが、Serializableクラスでフィールドへtransient指定した場合、宣言と同時に値を入れていてもデシリアライズ時には反映されません。
具体的にはこんな感じ

class S implements Serializable {
    public final int x;
    public transient int t = 20;
    public S(int x) {
        this.x = x;
    }
    public String toString() { return "X=" + x + ",T=" + t; }
}

S s = new S(400);
oout.writeObject(s);
Log.v("LOG", (s + ":オブジェクトを書き込みました"));
ObjectInputStream oinp = new ObjectInputStream(finp);
Log.v("LOG", (oinp.readObject() + ":オブジェクトを読み込みました"));

[結果]
06-18 16:26:18.990: V/N(21976): X=400,T=20:オブジェクトを書き込みました
06-18 16:26:18.990: V/N(21976): X=400,T=0:オブジェクトを読み込みました

初期値で与えているt=20が反映されていません。
デシリアライズ時はコンストラクタも通りませんので気を付けましょう。

2013年6月14日金曜日

Factoryがアプリゲットでレビューされていました

全然気づいていなかったんですが、なんとなく検索してみたらFactoryが5月22日にアプリゲット様で今日のおしゲー「ゲームウォッチ風単純ゲーム」という感じでレビューしていただいてました。

  ありがとうございました。

2013年6月13日木曜日

SurfaceViewで描画範囲を限定する

SurfaceViewは描画時の座標指定で画面をはみ出して指定しても、きちんとその指定で描いてくれるので、普段はみ出し部分を気にしたりしないんですが、
今作っている新作アプリで1枚のSurfaceViewを上下に分けて使っているところがあって、いつも通りやってたら上の部分の描画が下の所にはみ出してしまう…
上の画面では等間隔のグリッドを透視投影して描いてる(赤い部分)んですが、下のほうがはみ出してしまっています。
こんなときは描画範囲を限定したい描画のところでCanvas.clipRect(Rect rect)するといいようです。
//限定したい範囲のRect作成
Rect clip = new Rect(0, 0, 640, 320);
canvas.save();
canvas.clipRect(clip);
//描画範囲限定の描画処理

canvas.restore();
ソースはこんな感じ。 
clipRectの指定が限定したくない描画に影響しないように、clipRectする前にcanvas.save()、終わった後にcanvas.restore()するのを忘れないようにしましょう。
結果はこんな感じ。
ちゃんとはみ出し部分が消えています。

2013年6月10日月曜日

AndroidでSerializableなクラスを継承したクラスの落とし穴

なんかよくわからんタイトルになってしまいましたが、Serializableなクラスを継承したクラスはSerializableをimplementsしなくてもSerializeすることができます。

public class S implements Serializable {
  private static final long serialVersionUID = 6105608118246672383L;
}

public class Hoge extends S {
  //serialVersionUIDなし、SをextendsしてるのでSerializeはできる
}

ところがこの継承したクラスはserialVersionUIDがないため、コンパイラが自動生成したserialVersionUIDを与えてしまうのです。
そうなると継承クラスをちょっと変えようものなら、変更前にSerializableしたファイルはserialVersionUIDが違うためInvalidClassExceptionを起こしてしまいます。
そうならないために、serialVersionUIDをきちんとつける習慣をつけましょう。
Serializableは拍子抜けするほど簡単にクラスをファイルに落とすことが出来て大変便利なんですが、適当に使うと大変な目にあいますね。
後々の変更も検討してよく考えて使いましょう。この辺もよく読んでおくといいかも。

Serializationの実装
http://book.geocities.jp/bits_of_java/java/io/serializable/index.html#contents

Java セキュアコーディングスタンダード CERT/Oracle 版 シリアライズ (SER)
https://www.jpcert.or.jp/java-rules/#c13

2013年6月4日火曜日

Factoryがアンドロイダー公認アプリに、そしてデイリーランク2位に!

拙作Factoryがアンドロイダー公認アプリになりました。
 そしてなんと、デイリーランキングで2位に!
 こ、これは本当か!?これで勢いが出たらいいなぁー

2013年6月3日月曜日

間取りー図がSony Selectでレビューされましたー

間取りー図Sony Selectでレビューされましたー


間取りー図は公開したのは半年以上前ですが、同アプリが4月に雑誌掲載して頂いたことといい、ツール系のアプリは息が長いのが特徴ですね。