Android

Android開発 〜そんなところ自分で作る必要ないよ〜

More than 3 years have passed since last update.

マニュアルに目を通さないで、適当なブログを適当にググッて実装すると陥りやすい、「自分で書く必要のないところまで自分で実装して疲れたりバグったり」というケース。経験したものをずらずらと。


  • コードはうろ覚え

  • 会社のプレゼンの資料で作ったので精査できてない(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の説明と実動作を見た私感にすぎないので程々に疑って下さい(むしろ解像度ごとのリソースを用意することを推奨している)


参考


画面幅に応じた画面切り替え


  • 画面が狭い端末だと表示しきれないので、狭い用のlayoutをプログラムで分岐して表示させるケース

  • タブレットでは2ペイン、スマートフォンでは普通のデザインでやりたいケース


Before


HogeActivity.java

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


HogeActivity.java

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などといった名前ベースの指定を利用するしかない。




参考


バージョンに応じた処理分岐


  • このlayout指定はAPInn以上じゃないと動かないから処理を分岐して頑張ったり、警告を無効化して考えるのを辞めたりするケース


Before


HogeActivity.java

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


HogeActivity.java

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だけでは済まないレベルの分岐は、ソースコードで頑張ってやるしか無い


参考


非同期通信と画面反映

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対応の場合はサポートライブラリを使いましょう


参考


データーの更新による他の画面の更新

一覧・詳細パターンで、詳細画面でデータを更新して、一覧画面に戻ってきたら更新内容を反映してなきゃいけないやつ


他のページに解説を譲ります

サンプルを書こうとしたら、思いの外長くなりそうだったので、参考サイトに説明を譲ります。


注意点


  • 結構難しい

  • 解説ページが少ない(というよりこれを使わないで頑張る記事が多い 気がする)

  • 解説ページがSQLITEDBに対するアクセスの例ばかり


    • 個人的にRestfulAPIに相性抜群と思っているので、後で書きます!




参考