2013年5月31日金曜日

ViewへModelのデータを表示

AngularJS における MVC の役割は以下のようになっています



View
HTMLファイル
Modelのデータをどのように表示するかを設定する
タグに ng-controller で Controller を設定する

Controller
JavaScript の関数オブジェクト
View から ng-controller で指定される
指定されたタグ以下だけから参照できるスコープを作成する
$scope を使ったデータ(モデル)の定義とその他のビジネスコードを書く

Model
Controller の中で定義される $scope の要素として定義されるデータ
View の {{}} や ng-repeat などを使って画面に表示される

View と共に Controller も階層化されることと、Controller の中で Model が定義されるのがミソっぽいです

ngController - AngularJS


View に Controller を設定して、Controller 内で定義される Model を画面に表示するサンプルです。
HTML に View、 JavaScript に Controller と Model が定義されています。
小さなコードですが基本的な3要素が入っています。

2013年5月30日木曜日

ng-appディレクティブとAngular式

AngularJS を使うときには通常 <html> 要素に ng-app ディレクティブを追加する。
ng-app ディレクティブを見つけたら、そこから下の要素内にある {{}} で囲まれた式を実行する。
AngularJS の内部では ng-app などのディレクティブは ngApp のようにキャメルケースで扱われる。
API Reference でもディレクティブはすべてキャメルケースで表記されている。

ngApp - AngularJS
http://docs.angularjs.org/api/ng.directive:ngApp


{{}} の中身は JavaScript ではなく Angular 用の式になる。

  • 変数の中身を表示したり、簡単な計算ができる
  • if や for などの制御はできない。
  • 変数が未定義でも undefined が表示されたりしない
  • フィルタを使って日付やお金など様々なフォーマットで出力できる
などの特徴がある

Expressions - AngularJS
http://docs.angularjs.org/guide/expression


フィルタについていくつか試してみたのがこちらです。
フィルタは自作することも可能なようです。

2013年5月29日水曜日

AngularJSを導入する方法

公式サイトを開いて Download をクリックします
http://angularjs.org

CDN の URL をコピーして HTML へ貼り付けます。
もちろんソースコードをダウンロードして参照してもOKです。
<!DOCTYPE html>
<html ng-app>
    <head>
        <meta charset="utf-8">
        <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.min.js"></script>
    </head>
    <body>
        {{'Hello' + ' world !'}}
    </body>
</html>

この HTML ファイルをブラウザで開いてみて Hello world ! と表示されれば問題ありません。
{{'Hello' + ' world !'}} がそのまま出力された場合はスクリプトが読みこめていません。
jQuery や underscore.js など他のライブラリに依存していないのがポイントですね。

2013年5月28日火曜日

JavaScriptでMVC

現在、JavaScript で Nintendo 3DS 向けのブラウザゲームの開発ツールを作っています。3DS向けの脱出ゲームが簡単に作れるようになる予定です。



jQuery を使ってイベントをバインドしながらゴリゴリコードを書いているのですが、どうしてもぐちゃぐちゃになってしまいます。イベントのバインド、スタイルの変更、データの変更などが同じ場所に書かれているためです。

JavaScript でも MVC モデルのようにうまいこと整理して書けないかと調べてみたら、JavaScript にも MVC のフレームワークがあることがわかりました。

JavaScript MVCフレームワークはすでに十種類以上、その比較や最新情報などのまとめ - Publickey
http://www.publickey1.jp/blog/12/javascript_mvc.html


中でも気になったのは Backbone.js と AngularJS です。
どちらも MIT ライセンスで自由に使うことができます。

Backbone.js
http://backbonejs.org

AngularJS
http://angularjs.org


プログラミング学習サイトのドットインストールでどちらもチュートリアル動画がありました。

Backbone.js 入門 - ドットインストール
http://dotinstall.com/lessons/basic_backbonejs

AngularJS 入門 - ドットインストール
http://dotinstall.com/lessons/basic_angularjs


まだどちらも触っていないのですが、ドキュメントや動画を見た感じで何となく印象を書いておきます。

Backbone.js は Model, View, Controller といったクラスを提供してくれて、それらを継承して使うことでコードが整理できるようです。Model に変化があった場合に View へ自動的に知らせるようなイベント(listenTo()) なども準備されており、他の MVC フレームワークと似ている感じです。
ただし、 Controller が予想とは少し違いました。マウスイベントを Controller が受け取ると思いきや、View が受け取って Model へ処理を依頼するらしい。Controller は URL のフラグメントに対応する役割を持っているそうです。これによって Ajax アプリケーションでも戻るボタンが使えるとか。
Controller はほとんど使わず、 View と Model が Event を使ってやり取りを行う模様。View を画面に反映させるときは jQuery を使っていつもどおり要素をいじるっぽい。

Backbone.jsを利用したクライアントサイドMVCの導入についてそそろそろ書いておくか - Tous Les Jours 攻防記
http://d.hatena.ne.jp/kazuk_i/20110407/1302130947


一方、AngularJS は HTMLファイル = View という印象です。HTML の要素の属性として ng-xxxx 設定し、そこでデータがどのように表示されるかを記述します。書き方は Go 言語の template パッケージにそっくりです。
また、HTMLの要素に対して Controller を対応付けることができ、要素で発生したイベントが Controller へ投げられるようです。
Model はどうなっているのかというと、Controller の中にデータを書くっぽい?まだよくわかっていないのですが、Controller と Model が合わさってるような感じなのかな?
Controller 同士は、対応付けられた HTML の要素に合わせて階層構造を持ち、親のデータを取得してこれるようです。できるだけ上の方の要素にデータを集めておいて、下の方の要素からそれぞれいじる感じにすればいいんだろうか・・・?


HTML ファイルをそのまま View として扱えるところが面白かったので、まずは AngularJS を中心に勉強してみようと思います。

2013年5月27日月曜日

Mac の画面を更に暗くする

部屋が暗い時は iMac の画面の輝度を最低まで下げてもまだ眩しいことがあります。
最低よりも暗くできないかと調べてみたところ、できるソフトウェアがありました。

SHADES - Charcoal Design
http://www.charcoaldesign.co.uk/shades

上のURLからパッケージを落としてインストールします。
画面にスライダーが追加され、輝度が調整できるようになります。
最低にすると画面が真っ暗になるくらいまで落とせます。



設定項目には Shades が追加されます。


設定画面の iMac タブを開きます。



Silider control: を None に設定すると画面上からスライダーが消えます。
Menu control を Brightness Icon にするとメニューバーのアイコンで輝度を調節できるようになります。


2013年5月26日日曜日

Inkscape でローディングアニメーションを作る

enchant.js で使うためにローディングアニメーションを作成したので
作業手順を紹介します。

まず、50x50px の正方形を作ります。
フィルは何でもOKです。ストロークは無しです。
四角形の座標は切りの良い数字にしておきます。


円ツールで適当な大きさの円を描きます。
フィルは白、ボーダー無しです。

control + D で円をコピーします。
そのまま control + ドラッグ でコピーした円を下へ移動させます。

ドラッグして2つの円を選択します。

選択状態の円をクリックして回転できるようにします。


control + D で2つの円をコピーします。
そのまま control + ドラッグで2つの円を回転させます。

同じようにして円形に円を並べます。

円を1つクリックして選択状態にします。
shift + control + Fフィル/ストロークパネルを出します。
アルファ値を下げて透明にしましょう。


同様にしてグラデーションになるように、その他の円の透明度も設定します。

8個の円を選択して control + G でグループ化します。
後ろの正方形は含まないでください。

円のグループの中心とを正方形の中心を合わせます。
shift を押しながら円のグループと正方形をクリックして両方とも選択状態にします。

shift + control + A を押して整列と配置パネルを出します。
「中心を水平軸に合わせる」
「中心を垂直軸に合わせる」
それぞれ1回ずつクリックして中央に合わせます。

スプライト用に1コマずつコピーしていきます。
正方形と円を両方とも選択した状態で contol + D で複製します。
その状態で、画面上にあるX座標を 50 増やします。
同じ画像が右に 50px ずらせました。

複製した方の円のグループを選択します。
control を押したままグループを1コマ分、回転させます。

これを繰り返して1周分(8コマ)のアニメーションを作成します。

背景の正方形をすべて選択して、shift + control + F でパネルを出します。
アルファ値を 0 にして透明化します。

透明化した正方形も含めて、作成した画像をすべて選択します。
(今回は白い円なので背景と被って見えませんが選択出来ます)


その状態で、shift + control + E でビットマップにエクスポートのダイアログを出します。
ビットマップのサイズが 400x50 になっていることを確認します。(50px x 8コマ = 400px)
xxx.png と名前をつけて、エクスポートボタンで書き出します。

指定したファイルにスプライトが書きだされます。
これでローディングのスプライトが完成です。
あとは必要に応じて JavaScript や CSS でアニメーションさせましょう。


2013年5月25日土曜日

BacklogとGitHubの連携

GitHubのリポジトリにコミットしたら、Backlogにコメントを自動的に残す方法です。
どうやらGitHubからのホックでは日本語に対応していないらしく、
コミットログに日本語が含まれているとBacklogにコメントが残りませんでした。

まず、GitHubのリポジトリページを開きます。右上の Setting をクリックします。




Service Hooks の中から Backlog を開きます。
Api Url には https://(スペース名).backlog.jp/XML-RPC を、
User Id と Password にはそれぞれログイン時に使用しているものを入力します。
最後に Active にチェックを入れればOKです。



設定したリポジトリに対して以下のようにタスク番号を含めたコミットをします。
#close や #fix などでタスクを完了したり処理済みにしたりもできます。
コミットログで課題を参照 - backlog
http://www.backlog.jp/help/usersguide/git/userguide1400.html



するとBacklog上の指定したタスクにコメントが残ります。



先述した通り、ログに日本語が含まれるとコメントが残せないようです。
日本語でもコメントを残すためには自分でサービスを作るしかなさそうです。

2013年5月24日金曜日

enchant.js の Label を中央表示

Label の文字列を中央配置するのに少し引っかかったのでメモ。

こちらの情報で解決しました
enchant.js でテキストラベルを中央に表示する - くろの雑記帳
http://kurochan-note.hatenablog.jp/entry/2013/01/28/000734

Label の _boundWidth からラベルの横幅を取得できるようです。


var button = new Group();

var background = new Sprite();
background.image = game.assets['/mucha/button.png'];
background.width = background.image.width;
background.height = background.image.height;
button.addChild(background);
   
var label = new Label();
label.text = config.button;
label.color = 'white';
label.font = '30px sans-serif';
label.x = (background.width - label._boundWidth) / 2;
label.y = (background.height - 30) / 2;
button.addChild(label);
   
button.width = background.width;
button.height = background.height;
button.x = (messageWindow.width - button.width) / 2;
button.y = 350;
button.addEventListener('touchstart', function() {
 game.currentScene.removeChild(messageWindow);
 config.callback.call(game);
});
messageWindow.addChild(button);

2013年5月23日木曜日

1秒ごとにマウスカーソルが元の場所に戻る現象

トラックパッドでカーソルを動かしたつもりが、
1秒ごとに画面の右上にマウスカーソルがジャンプしてしまう現象に遭遇しました。
マウスカーソルを動かそうにも、1秒経つと右上のある座標へ戻ってしまうので作業になりません。

トラックパッドの電池を入れ直したり、設定を見なおしたりするが変わらず。
ネットで調べても同じような情報がありません。
故障・・・?

原因を探ろうとBlue tooth の設定パネルを開き、
トラックパッドをクリックしようとすると、
マウスカーソルがワープして別の所をクリックしてしまいました。
しかも、そこが Blue tooth を切るチェックボックス。

見事に切断されるワイヤレスキーボードとワイヤレストラックパッド。
まさかのインタフェース全滅。完全にただの箱です。

しばらくあたふたする。
とりあえずUSBのマウスをつないで Blue tooth のチェックボックスを ON にしないと・・・。
しかし部屋にUSBのマウスが見つかりません。
そうだ、USBのペンタブが挿しっぱなしだったはず。
ペンタブへ視線をやると。



































おまえだああああああああああ





・・・ということで、ペンが微妙にタブレットの上に置きっぱなしになっていました。
タブレットの右端と、ペンが反応してカーソルが右上に固定されていたようです。
この状態でトラックパッドを操作すると、動いたマウスポインタが1秒毎にペンの座標へ更新されてしまうんですね。
壊れていなくて一安心。徹夜明けの朝の出来事でした。

2013年5月22日水曜日

enchant.js で viewport タグが上書きされる

viewport で width=320 と設定しても、
コンテンツが 320px で表示されずにはまりました。

コンソールで確認したところ、
width=320 と設定した viewport が width=640 と書き換えられていました。

調べてみたところ enchant.js をロードした時に、
端末に合わせて viewport の値を変更するようです。
<!-- viewport が上書きされるパターン -->
<meta name="viewport" content="width=320, initial-scale=1.0, user-scalable=no">
<script src="enchant.min.js"></script>

viewport の指定を enchant.js の読み込み後に指定することで回避出来ます。
<!-- 改めて viewport を設定するパターン -->
<script src="enchant.min.js"></script>
<meta name="viewport" content="width=320, initial-scale=1.0, user-scalable=no">

2013年5月21日火曜日

enchant-stage の z-index をマイナスにするとタッチイベントが発生しない

タッチイベントが取得できずにはまっていました。

この状態だとタッチイベントが取得出来ません。
enterframe などその他のイベントは取得できています。
<div id="enchant-stage" style="z-index: -1"></div>

z-index を指定しないか、正の数を指定すればタッチイベントが
取得できるようになりました。
<div id="enchant-stage"></div>


<div id="enchant-stage"> によってゲームが全画面になることを防ぎ、
さらに、外部の <form> で作成したフォームを enchant-stage の上へ
表示しようとしていました。
enchant-stage を <form> の後ろに回すため、
z-index に -1 をセットしたところ、タッチイベントが動かなくなりました。

enchant-stage とその他の要素の前後関係を設定したい場合は、
負の数を使わず正の数のみで行えば問題ありません。

2013年5月20日月曜日

GAE for PHP

Google App Engine で公式に PHP が使えるようになったようです。

Google App Engine for PHP
https://gaeforphp.appspot.com

API を見に行った時に PHP のドキュメントが追加されておや?と思ったのですが、
16日に発表されていたようですね。

ローカルの開発が基本ですが、申請が通ればサーバ上へのアップロードもできるようです。
とりあえず申請してみつつ、ローカル開発を始めてみたいと思います。

2013年5月19日日曜日

okasize を公開


Android 端末の画面サイズと解像度を入力すると、
Size Group (small / normal / large / xlarge) と
Density Group (ldpi / mdpi / hdpi / xhdpi / xxhdpi) の
どれに属するのかを調べることができる Web アプリです。

こちらで使えます
http://okanoworld.appspot.com/okasize


GitHub でソースコードを公開しています。
MIT ライセンスなのでご自由にお使いください。


計算方法

ユーザからの入力は以下の3つです

  • 画面サイズ inch
  • 解像度 widthPx heightPx

この3つから dpi を計算します。
1 インチあたり、何個のドットが入っているかを調べます。
対角線上のドット数をピタゴラスの定理で求めて、対角線の長さ inch で割ります。
dpi を計算出来れば Density Group の判定ができます。
var dpi = Math.sqrt(widthPx * widthPx + heightPx * heightPx) / inch;

 次に px を dp に変換します。
Size Group を判定するために使う単位は dp です。
px が実際の端末の画面サイズによって相対的に大きさが変わるのに対して、
dp はどんな端末でも物理的に同じ大きさで表示されることが保証されます。
dp については過去の記事を参照してください。
var widthDp = widthPx / (dpi / 160);
var heightDp = heightPx / (dpi / 160);

あとは dpi と dp によってグループ分けをするだけです。
グループわけに使う閾値はいかにまとめられています。

Supporting Multiple Screens - Android Developers
http://developer.android.com/guide/practices/screens_support.html

var density = getDensityCode(dpi);
var size = getSizeCode(widthDp, heightDp);

...

var getDensityCode = function(dpi) {
 var result;
 if(dpi < 120) {
  result = 'ldpi';
 } else if(dpi < 160) {
  result = 'mdpi';
 } else if(dpi < 240) {
  result = 'hdpi';
 } else if(dpi < 320) {
  result = 'xhdpi';
 } else if(dpi < 480) {
  result = 'xxhdpi';
 } else {
  result = 'not matched';
 }
 
 return result;
};

...

var getSizeCode = function(width, height) {
 // 横長にする
 if(width < height) {
  var buf = width;
  width = height;
  height = buf;
 }
 
 var result;
 if(width > 960 && height > 720) {
  result = 'xlarge';
 } else if(width > 640 && height > 480) {
  result = 'large';
 } else if(width > 470 && height > 320) {
  result = 'normal';
 } else if(width > 426 && height > 320) {
  result = 'small';
 } else {
  result = 'not matched';
 }
 
 return result;
};

2013年5月18日土曜日

Android の API Level の取得

android.os.Build パッケージを使って取得出来ます。
// API バージョンの出力
Log.d("debug", Integer.toString(Build.VERSION.SDK_INT));


2013年5月17日金曜日

マニフェストファイルでのバージョン指定

Android アプリのマニフェストファイルで動作条件となるバージョンを指定出来ます。

AndroidManifest.xml の <susesl-sdk> 要素の属性として記述します。
    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />


アプリが使用している API Level に合わせて設定します。

minSdkVersion にはアプリが動作するために最低限必要な API Level の数値をセットします。
この数値よりも低い API Level の端末では、アプリがインストール出来ませんと表示されます。

targetSdkVersion には実機で動作確認した確実に動く API Level をセットします。
この数値よりも高い API Level の端末でも、
新しいバージョンのインタフェースが使われず、
指定したバージョンのインタフェースが使われます。
新しいバージョンを使うことによって、予想していない動作や表示がなされることを防ぎます。

もう1つ maxSdkVersion という値も設定できるようです。
こちらは現在非推奨となっているため設定はしません。

詳しい解説はこちら
<uses-sdk> - Android Developer
http://developer.android.com/guide/topics/manifest/uses-sdk-element.html

2013年5月16日木曜日

Android 画面サイズのシェア

以前にも紹介しましたが、
Android のバージョンに関するシェアは公式サイトで確認できます。
今回は画面サイズのシェアについて見てみましょう。

Dashboards - Android Developer
http://developer.android.com/about/dashboards/index.html#Screens






画面の大きさで一番多いのが Normal でほぼ 80% です。
一方、dpi はだいぶ散らばっています。

hdpi - 38.5%
xhdpi - 25.9%
mdpi - 23.4%
ldpi - 10.4%
tvdpi - 1.0%
xxhdpi - 0.8%

だそうです。
mdpi, hdpi, xhdpi の 3 つへ対応したいところですね。

2013年5月15日水曜日

異なる大きさの画面への対応

Android では特定の画面サイズや解像度に対して専用のリソースを準備出来ます。
アプリ実行時に、端末の画面に合わせて適切なリソースがロードされます。


画像

解像度ごとに画像を変えることができます。

res/drawable-ldpi
res/drawable-mdpi
res/drawable-hdpi
res/drawable-xhdpi
res/drawable-xxhdpi

というディレクトリを作成して中にそれぞれ同じ名前の画像ファイルをいれておきます。
すると、実行時の端末の密度に合わせて最適な画像が選ばれます。

ディレクトリに入れる画像ファイルの大きさですが、
基準となる mdpi の画像が 100x100px の場合、

ldpi = 75x75px
hdpi = 150x150px
xhdpi = 200x200px
xxhdpi = 300x300px

という大きさの画像をそれぞれ準備しておくと、
画面上に表示された時、物理的に同じ大きさで画像を表示することができます。


レイアウト

インタフェースも画面ごとに変えることができます。
通常は画面の大きさにフィットするように自動で画面が拡大縮小されるので、
必要な場合にのみ設定することになると思います。

デフォルトでは res/layout フォルダしか無いですが、
新しく以下のフォルダを作って xml ファイルを配置することで
専用レイアウトが適用されます。

layout-small/
layout-large/
layout-xlarge/


画面の向き

画面の向き (portrate / landscape) によって読み込むレイアウトを変えることもできます。
デフォルトでは縦向きのデザインですが、
フォルダ名に -land や -port を付けることで縦横専用のレイアウトになります。

layout-port/
layout-land/
layout-large-port/
layout-large-land/

...


詳しい解説はこちらを参照
Providing Resources - Android Developers

2013年5月14日火曜日

dp とは何か

Android でレイアウトのサイズを決めるときに dp という単位が使われます。

Supporting Multiple Screens - Android Developers
http://developer.android.com/guide/practices/screens_support.html#overview

これは mm や cm と同じように画面上の物理的な長さを表す単位です。
大きさや解像度が異なる画面上でも物理的に同じ大きさのパーツを作りたいときに使います。

考え方

まず 1 インチの画面を考えます。(サイズが 1 インチ)
1 インチあたり 160 個のピクセルがあります。(密度が 160 dpi)
この時の 1 個のピクセルの物理的な長さを 1 dp と呼びます。


どんな大きさ、解像度の画面でも 1cm は 1cm です。
それと同じで、1dp はどんな画面でも 1dp になります。

2013年5月13日月曜日

Android の画面サイズ

Android 端末には様々な大きさや解像度があります。
それらを分類するグループが定義されているので見てみましょう。

画面の大きさによる分類

大きさは small, normal, large, xlarge の4つのグループにわかれます。

960dp x 720dp 以上 = xlarge
640dp x 480dp 以上 = large
470dp x 320dp 以上 = normal
426dp x 320dp 以上 = small

dp は mm などのように、物理的な長さを表す単位です。
詳しくは後日触れます。

ピクセルの密度による分類

1 インチあたりのピクセル数 (dpi) によって 4 つのグループにわかれます。

120dpi 以下 = ldpi
160dpi 以下 = mdpi
240dpi 以下 = hdpi
320dpi 以下 = xhdpi


これらのグループそれぞれに専用のレイアウトを作成することができます。
画面サイズについての詳しい解説はこちら

Supporting Multiple Screens - Android Developers
http://developer.android.com/guide/practices/screens_support.html

2013年5月12日日曜日

ムチャブリBacklog を公開

PC・スマートフォン対応のWebアプリ「ムチャブリBacklog」を公開しました。

公式ページ:http://yokano.github.io/mucha/
アプリURL:http://okanoworld.appspot.com/mucha

勇者となって王様からBacklogのタスクをムチャぶりしてもらえるアプリです。
行く末に迷った時などにご使用ください。
アプリはMITライセンスのためソースコードや画像はご自由にお使いください。
詳しくは上記の公式ページをごらんください。







2013年5月11日土曜日

Android アプリを多言語に対応する

Android アプリでは文字列をソースコードとは別に管理します。

/res/values/strings.xml に文字列が定義されています。
<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">MultiLang</string>
    <string name="action_settings">Settings</string>
    <string name="hello_world">Hello world!</string>

</resources>

まずデフォルトの文字列を日本語に変更します
<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">多言語対応</string>
    <string name="action_settings">設定</string>
    <string name="hello_world">こんには世界!</string>

</resources>

日本語になった

画面左上の新規作成ボタンを押してフォルダ新規作成します。

フォルダの新規作成


/res/values-en/ フォルダを作成します

values-en を作成する


多言語対応で作成するディレクトリ名は values-◯◯ です。
◯◯には言語コードが入ります。
中国語なら values-zh、韓国語なら values-ko という感じ。
今回は英語に対応させるため values-en を作成します。

/values/strings.xml を /values-en/ へコピーします。



/values-en/strings.xml の文字列を英語に変えます。
<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">Multi Languages</string>
    <string name="action_settings">Settings</string>
    <string name="hello_world">Hello world!</string>

</resources>

実行する Android の設定を英語に変更します。
Android 4.0 なら 設定 -> 言語と文字入力 で変更できます。

設定で言語を英語に変える

アプリを実行してみるとインタフェースの文字列が
英語に変わっていることが確認できました。
設定で日本語に戻すと、インタフェースが日本語になります。

インタフェースが英語になった

ちなみに最初から作成されている /res/values/strings.xml
はデフォルトの言語ファイルになります。
中国語や韓国語など、準備していない言語が選ばれている場合は、
このデフォルトの言語ファイルが使われます。


多言語対応についてはこちらに解説があります
Supporting Different Languages - Android Developers
http://developer.android.com/training/basics/supporting-devices/languages.html

Localization - Android Developers
http://developer.android.com/guide/topics/resources/localization.html

2013年5月10日金曜日

Android のバージョンや解像度のシェアを調べる

マルチデバイス対応において、
Android のバージョンや解像度のシェアがどうなっているのかは重要ですね。

Android Developers の公式サイトで、
GooglePlay へアクセスした端末から割り出されるシェアが公開されています。

Dashboards - Android Developers
http://developer.android.com/about/dashboards/index.html



Android のバージョン、解像度、OpenGL のバージョンが公開されています。

4月23日の時点では、4月2日までの集計データが載っています。
このページは定期的に更新されるようです。
Android のシェアについては、ここが一番信用できそうですね。

2013年5月9日木曜日

データ保存のタイミングは onPause() ? onStop() ?


Android Developer の Training を読んでいたところ、
onPause() ではストレージにデータを保存せずに、
onStop() で保存するべきだと書いてありました。
onPause() では画面上に別のアクティビティが表示されるため、
時間がかかるストレージへのアクセスは控えるべきだそうです。


Pause Your Activity - Android Developer
http://developer.android.com/training/basics/activity-lifecycle/pausing.html#Pause
Generally, you should not use onPause() to store user changes (such as personal information entered into a form) to permanent storage. The only time you should persist user changes to permanent storage within onPause() is when you're certain users expect the changes to be auto-saved (such as when drafting an email). However, you should avoid performing CPU-intensive work during onPause(), such as writing to a database, because it can slow the visible transition to the next activity (you should instead perform heavy-load shutdown operations during onStop()).


一方、API Guides の Activity を読んでみると、
今度は onPause() の中でデータをストレージへ保存するように書かれています。
onPause() を実行した後は、いつアプリが強制終了するかわからないので、
onPause() の中で保存すべきとのこと。
どっちで保存すればいいんだろう・・・。

Managing the Activity Lifecycle - Android Developer
http://developer.android.com/guide/components/activities.html#Lifecycle
Because onPause() is the first of the three, once the activity is created,onPause() is the last method that's guaranteed to be called before the process can be killed—if the system must recover memory in an emergency, then onStop() andonDestroy() might not be called. Therefore, you should use onPause() to write crucial persistent data (such as user edits) to storage.



更に、Reference の Activity を読んでみると何となくわかりました。
上の API Guides のページでは onPause() の Killable after ? が Yes となっているのですが、Reference のページでは Pre - HONEYCOMB と書いてあります。
API Guides の Activity Lifecycle の表が古い状態のままなんだと思います。

Reference のページによると、HONEYCOMB(Android 3.0) 以降では、
onStop() が終了するまでは強制終了されないことが保証されているようです。
しかし HONEYCOMB より古いバージョンでは、onStop() が終了する前に、
強制終了されてしまう可能性があるとのことです。


Activity class - Android Developer
http://developer.android.com/reference/android/app/Activity.html
Be aware that these semantics will change slightly between applications targeting platforms starting with HONEYCOMB vs. those targeting prior platforms. Starting with Honeycomb, an application is not in the killable state until its onStop() has returned. This impacts whenonSaveInstanceState(Bundle) may be called (it may be safely called after onPause()and allows and application to safely wait until onStop() to save persistent state.

データを保存する最適なタイミングは、バージョンによって変わるようですね。
Android 3.0 より前なら onPause() で、 Android 3.0 以降なら onStop() が推奨です。
動作が遅くなるけれど両方で動く onPause() が安全だと思います。
それにしても 3.0 って微妙なラインですね。2.3系以降なら onStop() で確定なんですが・・・。

2013年5月8日水曜日

Activityの状態遷移

Activity の状態遷移についてまとめ

公式のリファレンスに状態遷移の図が乗っているのでそちらも参照
Managing Lifecycle - Android Developers
http://developer.android.com/guide/components/activities.html#Lifecycle


Activity の状態遷移


onCreate()

ユーザがアプリのアイコンをタッチすると呼び出される。
Activity の layout をセットする
インスタンス変数の初期化をする
Activity のライフサイクルにおいて1度しか実行されないメソッド
このメソッド内で finish() を実行すると、
途中のメソッドを飛ばして onDastroy() を呼び出すことができる。

Created 状態

onCreate() が終了したらこの状態になる
この状態になったらすぐさま onStart() を実行する

onStart()

onCreate() で設定した layout が画面に自動的に描画される。
Stopped 状態から復帰してきた場合は、
引数の Bandle オブジェクトに中断データ(フォームへの入力やスクロール位置など)が渡される。
必要に応じて復元することができる。

Started 状態

onStart() が終了するとこの状態になる。
すぐさま onResume() が呼び出される。

onResume()

Started から遷移してきた場合は特に何もしなくて良い。
Paused から復帰したきた場合には、停止した処理の再開をする。

Resumed 状態

最前面で実行され、ユーザのインタラクションに対応できる。
ダイアログを表示したり、別のアプリを呼びだそうとすると onPause() が実行される。

onPause()

別のアクティビティへ遷移したり、アプリから離れようとした時に呼ばれる。
以下のことをやる。

  • アニメーションなどの CPU を消費する処理を停止する
  • メールの下書きなど消えたら困るデータを保存する
  • ポーズ中に使わないリソースを開放する(カメラやGPS機能へのアクセスなど)


Paused 状態

ダイアログが上に表示されるなど、部分的に見えてはいるんだけど操作はできない状態。
再開するときには onResume() が呼ばれる。
再開時には onPause() で止めた処理を再開すること。
Activity オブジェクトはメモリ上に残り続けて、再開時にそのまま利用できる。
画面が完全に隠れて表示する必要もなくなったら onStop() を実行する。
HoneyComb より古いバージョンではシステムから強制終了がかかる可能性がある。
(これについては明日、詳しく書きます)

onStop()

別のアプリへの遷移するときや、別のアクティビティへ遷移する時に呼ばれる。
再開時に使いたいデータは Bundle オブジェクトとして保存しておく。

Stopped 状態

システムから強制終了がかかる可能性がある。


2013年5月7日火曜日

最初に起動する Activity の指定

Android でアプリを起動したときに最初に起動する Activity は AndroidManifest.xml で指定します。

アプリのアイコンをタッチすると <intent-filter> タグで actionMAIN
 categoryLAUNCHER が指定されている Activity の onCreate() が呼び出されます。
<activity> タグの name 属性にパッケージ名も含めた Activity のクラス名を書けば OK です。

<activity android:name="com.example.hoge.MainActivity" android:label="@string/app_name">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

詳しくはこちら
Starting on Activity - Android Developers
http://developer.android.com/training/basics/activity-lifecycle/starting.html#launching-activity

2013年5月6日月曜日

Intent とは

Intent とは Activity 間の通信や、アプリ間での通信を行う機能のこと。
別の画面を表示したり、他のアプリを呼び出したりするときに使う。
イベントやメッセージのようなもの。

全体的な説明はこちら
Intent and Intent Filter - Android Developers
http://developer.android.com/guide/components/intents-filters.html


Intent を作るときには Intent クラスをインスタンス化して使う。
Intent class - Android Developers
http://developer.android.com/reference/android/content/Intent.html


別のアクティビティを起動するときはこんな感じ。
Intent intent = new Intent(this, DisplayMessageActivity.class);
startActivity(intent);
第一引数が Context 、第二引数が送り先のクラスです。
他にも色々とコンストラクタがあるので必要に応じて使い分けることになります。

Intent には HTTP の GET や POST のようにデータをくっつけることができます。
他のページを初期化するときや、特定のアクションを実行したいときなどに使えそうです。
また、今回のように相手を直接指定するのではなく、
条件に合う相手を探して送る機能もあるそうです。
それらについてはまた別の記事で触れます。

Intent についてはこちらがわかりやすいです。
intent - Androidのド肝
http://blog.haw.co.jp/android/?p=54

2013年5月5日日曜日

Activity とは

Activity とはアプリを構成する画面1枚を指す言葉です。
画面を作るときには Activity クラスのサブクラスを作って
onCreate() や onPause() を実装するとのこと。
Android システムが自動的に状態遷移を行なってくれて、
その都度 onCreate() などのメソッドが呼ばれます。
Activity クラスは android.app パッケージで定義されています。

Activity - Android Developers

Activity class - Android Developers


Activity についてはこちらがわかりやすいです。

Activity とは何か? - @IT
http://www.atmarkit.co.jp/fsmart/articles/android02/android02_1.html



別の Activity が呼び出されると前の Activity をスタックに保存しておいてくれたり、
マニフェストファイルで最初に起動する Activity を指定できたりするなど
色々あるようなので、別の記事でそれぞれ触れていこうと思います。

2013年5月4日土曜日

Android アプリ:イベントのバインドとキャッチ

Android でイベントを処理する方法です。

ADT で Blank Activity を選ぶと Hello world! と表示されるアプリが作られます。
Hello world! をタッチしたら Hello Android world! に変えましょう。

イベントについてはこちらに解説があります
Android Developer - Input Events
http://developer.android.com/guide/topics/ui/ui-events.html

手順
  1. 文字を大きくする
  2. TextView に id をつける
  3. id を使って TextView を取得する
  4. OnClickListener を実装する
  5. OnClickListener を View へセットする
  6. onClick() 内で文字列を切り替える
  7. 動作確認

文字を大きくする


デフォルトのレイアウトはこんな感じ
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/hello_world" />

</RelativeLayout>


このままではテキストが小さいので大きくします。
    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
       android:textSize="30pt"
        android:text="@string/hello_world" />

タップできるくらいの大きさにする

テキストの指定についてはこちら
Android Developers - R.attr : textSize http://developer.android.com/reference/android/R.attr.html#textSize

TextView に id をつける


Java から TextView を取得するために xml で id を設定します。
これで R.id.hello_world でこの TextView を参照できるようになります。
    <TextView
        android:id="@+id/helloworld"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textSize="30pt"
        android:text="@string/hello_world" />



Java のソースを開きます。
package com.example.eventlistener;

import android.os.Bundle;
import android.app.Activity;
import android.view.Menu;

public class MainActivity extends Activity {

 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
 }

 @Override
 public boolean onCreateOptionsMenu(Menu menu) {
  // Inflate the menu; this adds items to the action bar if it is present.
  getMenuInflater().inflate(R.menu.main, menu);
  return true;
 }

}

id を使って TextView を取得する


TextView を保存する変数を作るために android.widget.TextView をインポートします。
import android.widget.TextView;

Activity に onStart() メソッドを追加して TextView を取得します。
public class MainActivity extends Activity {
 ...
 protected void onStart() {
  super.onStart();
  TextView textView = (TextView)findViewById(R.id.helloworld);
 }
 ...
}

OnClickListener を実装する


Click イベントをキャプチャするために、android.view パッケージで提供されている OnClickListener インタフェースを使います。

Android Developers - View.OnClickListener
http://developer.android.com/reference/android/view/View.OnClickListener.html

OnClickListener インタフェースは onClick() メソッドを宣言していて、クリックされた時に呼び出されます。

まず、OnClickListener インタフェースをインポートします。
import android.view.View.OnClickListener;

OnClickListener インタフェースを MainActivity クラスへ実装します。
public class MainActivity extends Activity implements OnClickListener {
 ...
}

インタフェースのメソッドを実装します。
public class MainActivity extends Activity implements OnClickListener {
 ...
 public void onClick(View v) { 
 }
}

OnClickListener を View へセットする


次に、TextView がクリックされた時に、このメソッドが呼ばれるようにしましょう。
View の setOnClickListener() メソッドを使います。

Android Developers - setOnClickListener
http://developer.android.com/reference/android/view/View.html#setOnClickListener(android.view.View.OnClickListener)

先ほど取得した TextView にリスナを追加します。
 protected void onStart() {
  super.onStart();
  TextView textView = (TextView)findViewById(R.id.helloworld);
  textView.setOnClickListener(this);
 }

引数には OnClickListener インタフェースを実装した(onClick()メソッドを持っている)クラスを渡します。
今回は MainActivity 自身にもたせているので、 this で MainActivity 自身を渡しています。
これで TextView がタップされた時に MainActivity の onClick() メソッドが呼ばれることになりました。

onClick() 内で文字列を切り替える


最後に onClick() メソッド内で TextView のテキストを変えます。
まず、変更する文字列を定義しておきます。
/res/values/strings.xml へ文字列 hello_android_world を追加します。
ファイルを保存すると、自動的に R.java へ参照が追加されます。
<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">EventListener</string>
    <string name="action_settings">Settings</string>
    <string name="hello_world">Hello world!</string>
    <string name="hello_android_world">Hello Android world!</string>

</resources>

では、文字列を変えましょう。
onClick() メソッドの引数としてクリックされた View が渡されます。
これを TextView へキャストして、setText() メソッドで参照する文字列を変えます。
 public void onClick(View v) {
  ((TextView)v).setText(R.string.hello_android_world);
 }

動作確認


Android 端末で実行します。
テキストをタップすると文字列が変わることが確認できます。

タップしたら文字列が変わりました