マニュアルに目を通さないで、適当なブログを適当にググッて実装すると陥りやすい、「自分で書く必要のないところまで自分で実装して疲れたりバグったり」というケース。経験したものをずらずらと。
- コードはうろ覚え
- 会社のプレゼンの資料で作ったので精査できてない(TODO 後で整理する)
概要
- RosourcesTypes
- Loader
- DataProvider
これらを使って楽をしようという話のケーススタディー的なものです
画像リソースのdpiごとの伸縮
単純に拡大縮小するだけなのに、いろんな解像度分の画像を用意して配置するやつ
Before
猫のアイコン icon_neko.pngを以下のように配置
res/
drawable-mdpi/
icon_neko.png (16x16)
drawable-hdpi/
icon_neko.png (24x24)
drawable-xhdpi/
icon_neko.png (32x32)
drawable-xxhdpi/
icon_neko.png (48x48)
drawable-xxxhdpi/
icon_neko.png (64x64)
ほんとうに必要なのか。
それ、AndroidのPreScaleでやってくれるよ。
After
res/
drawable-xxxhdpi/
icon_neko.png (64x64)
- 一番近いdpiのリソースを自動伸縮して表示してくれる
- pre処理なので更新のたびに毎回伸縮しているわけではないので軽い
注意点
以下の場合は頑張ったほうがいい
- Androidの拡大縮小のアルゴリズムが気に入らない
- 単純な拡大縮小では駄目なケース(例えば, 1pxの線は縮小されても1pxであってほしいとき)
- ドキュメントにこの内容そのものが書いてあったわけではなく、Prescalingの説明と実動作を見た私感にすぎないので程々に疑って下さい(むしろ解像度ごとのリソースを用意することを推奨している)
参考
- Supporting Multiple Screens | Android Developers http://developer.android.com/intl/ja/guide/practices/screens_support.html#DensityConsiderations
画面幅に応じた画面切り替え
- 画面が狭い端末だと表示しきれないので、狭い用のlayoutをプログラムで分岐して表示させるケース
- タブレットでは2ペイン、スマートフォンでは普通のデザインでやりたいケース
Before
public class HogeActivity extentds Activity {
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 画面の横幅が360dp以上かどうかで表示するlayoutを切り替える
DisplayMetrics metrics = getResources().getDisplayMetrics();
if(metrics.widthPixels / metrics.density >= 360) {
setContentView(R.layout.activity_hoge_w360);
}else {
setContentView(R.layout.activity_hoge);
}
}
}
res/
layout/
activity_hoge.xml (デフォルト)
activity_hoge_w360.xml (横360以上用)
それ、AndroidのResourceTypeの指定で出来るよ。
After
public class HogeActivity extentds Activity {
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_hoge);
}
}
res/
layout/
activity_hoge.xml (デフォルトのlayout)
layout-w360dp/
activity_hoge.xml (widthが360dp以上の時に適応してほしいlayout)
- 縦幅横幅うち小さいほうがNdpi以上のとき reources-swNdp なども可能
注意点
- Andorid3.2未満では resource-wNdp の指定が出来ない
- 代わりにresource-lergeなどといった名前ベースの指定を利用するしかない。
参考
- Supporting Multiple Screens | Android Developers http://developer.android.com/intl/ja/guide/practices/screens_support.html
- Providing Resources | Android Developers http://developer.android.com/intl/ja/guide/topics/resources/providing-resources.html
バージョンに応じた処理分岐
- このlayout指定はAPInn以上じゃないと動かないから処理を分岐して頑張ったり、警告を無効化して考えるのを辞めたりするケース
Before
public class HogeActivity extentds Activity {
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// APIレベルが11以上かどうかで処理を分ける
if(Build.VErSION.SDK_INT => 11) {
setContentView(R.layout.activity_hoge_v11);
} else {
setContentView(R.layout.activity_hoge);
}
}
}
res/
layout/
activity_hoge.xml (デフォルト)
activity_hoge_v11.xml (API level 11をサポートしているデバイス用)
それ、AndroidのResourceTypeの指定で出来るよ。
After
public class HogeActivity extentds Activity {
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_hoge);
}
}
res/
layout/
activity_hoge.xml (デフォルト)
layout-v11/
activity_hoge.xml (API level 11をサポートしているデバイス用)
注意点
- Androidのresourceだけでは済まないレベルの分岐は、ソースコードで頑張ってやるしか無い
参考
- Providing Resources | Android Developers http://developer.android.com/intl/ja/guide/topics/resources/providing-resources.html
非同期通信と画面反映
WebAPIから情報を取ってきて画面に設定するだけなのに、
AsyncTaskを定義して、Activityベースのsyncronizedを書いてロックしてなどなど頑張るケース
Before
public class HogeActivity extentds Activity {
// ロック用
private AsyncTask<Void, Void, String> task;
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_hoge);
final TextView text = (TextView) findViewById(R.id.text1);
assignloadtask();
}
// なんかのリスナー
public void onNankaListener() {
assignloadtask();
}
// ロックされてなければロード
private synchronized void assignLoadTask() {
if(task == null) {
task = new AsyncTask<Void, Void, String>() {
@Override
protected String doInBackground(Void... params) {
String result;
// 時間のかかる通信処理
return result;
}
@Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
if(result != null) {
text.setText(result);
}
task = null;
}
};
task.execute();
}
}
}
それ、Loader使えば簡単にかけるよ。
あまり短くなってないけど、ライフサイクル管理とか、再参照の時のキャッシュとか、ロックとかちゃんと書けば書けるらしい!
After
public class HogeActivity extentds Activity implements LoaderCallback<String> {
private static final int LOADER_ID = 0;
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_hoge);
final TextView text = (TextView) findViewById(R.id.text1);
getLoaderManager().initLoader(LOADER_ID, null, this);
}
// なんかのリスナー
public void onNankaListener() {
getloadermanager().restartLoader(LOADER_ID, null, this);
}
@Override
public Loader<String> onCreateLoader(int arg0, Bundle arg1) {
return new AsyncTaskLoader<String>(getActivity()) {
@Override
public String loadInBackground() {
String result = null;;
// 時間のかかる通信処理
return result;
}
};
}
@Override
public void onLoadFinished(Loader<String> arg0, String arg1) {
if(result != null) {
text.setText(result);
}
}
@Override
public void onLoaderReset(Loader<String> arg0) {
}
}
注意点
- Android3.0からなので2対応の場合はサポートライブラリを使いましょう
参考
- Loaders | Android Developers http://developer.android.com/intl/ja/guide/components/loaders.html
データーの更新による他の画面の更新
一覧・詳細パターンで、詳細画面でデータを更新して、一覧画面に戻ってきたら更新内容を反映してなきゃいけないやつ
他のページに解説を譲ります
サンプルを書こうとしたら、思いの外長くなりそうだったので、参考サイトに説明を譲ります。
注意点
- 結構難しい
- 解説ページが少ない(というよりこれを使わないで頑張る記事が多い 気がする)
- 解説ページがSQLITEDBに対するアクセスの例ばかり
- 個人的にRestfulAPIに相性抜群と思っているので、後で書きます!
参考
- ContentProvierとCursorLoaderとFragmentを使ったサンプルを作ってみた - Androidはワンツーパンチ 三歩進んで二歩下がる http://sakura-bird1.hatenablog.com/entry/20121102/1351876650
- Android - ContentProvider - Qiita http://qiita.com/kojionilk/items/9bb1a28d04dc87d301b9
- Android - CursorLoader - Qiita http://qiita.com/kojionilk/items/512334d0dd0a4d4d05d2
- Loaders | Android Developers http://developer.android.com/intl/ja/guide/components/loaders.html
- Content Providers | Android Developers http://developer.android.com/intl/ja/guide/topics/providers/content-providers.html