2010年12月17日金曜日

Android開発における端末別の画面表示対応

androidの開発で苦労するのが端末別の対応です。
現在のアプリの対応端末の基本はXperia、Desire、Galaxyでしょう。
しかし、これにIS03が加わると大変です。

なぜなら、Xperia、Desire、Galaxyの画面SkinはWVGAなのですが、IS03はHVGAなのです。
IS03はHVGAなので、現状の主力端末の表示方法とは相容れない「ガラパゴススマフォ」なのです。

個人アプリならScrollView、RelativerLayout、dpi、spの組み合わせで、画面layoutを無視してなんとでも対応できます。
しかし、仕事となるとスクロールを使えない場合があります。ScrollViewが使えず、画面レイアウトを重視されるともう大変です。個人的にはIS03は無視でいい。と思うのですが、日本の仕事場はそこまで割り切った切捨てができない場合が多いので、にっちもさっちもいかなくなる。そして、一画面にデータを収めるのに四苦八苦しないといけないわけです。

これはandroid端末の最大の欠点です。
将来、androidがiphoneに負けるとしたらこれが理由になるでしょう。
つまり、「バラバラな端末仕様のせいで、良質のアプリが全ての端末に提供できない」ということです。
 海外では切捨てをあまり気にしなさそうなので、androidは間違いなく一番手で普及するでしょうが、日本で切捨ては無理でしょう。
というわけで、とりあえずの私が緊急に行った対応方法をメモに残しときます。

今回のケースはxperiaの解像度に合わせて作成した画面WVGA854(480 x 854)を他の主力端末に合わせるケースです。
WVGA800でも表示は特に問題はなかったのですが、ついでに対応しました。

xperia以外の対応端末は

WVGA800
(480 x 800)の
Desire(HTC)
Galaxy S



HVGAの
(640 x 960)
HVGA
IS03
です。


私の場合、layoutフォルダに画面レイアウトxmlをひとまとめにしていたので、これを分割しました。
resの配下に「layout-854x480「「layout-800x480」フォルダを作成します。

つまりは、
res - layout

から

res - layout-854x480
- layout-800x480
- layout

といったフォルダ構成に変更します。

フォルダ構成変更後、既存のlayoutフォルダの中身を

layout-854x480,layout-800x480
に格納します。

これでxperiaのレイアウトは
layout-854x480フォルダ内のxmlが適用されます。
Desire(HTC)とGalaxy Sのレイアウトは
layout-800x480フォルダ内のxmlが適用されます。

そして、IS03はlayoutフォルダ内のxmlが適用されます。
あとは、それぞれの端末に合わせた調整をすればOKです。


参考
http://developer.android.com/guide/practices/screens_support.html

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

2010年12月14日火曜日

androidでWEB接続 その1

最近は、androidを使ったWEB周りのコーディングを行っていました。
WEB周りは今後も色々とコーディングする機会が多そうなので、詳細なメモを残しときます。


・例1
WebViewクラスを利用して、yahooやgoogleなどのサイトに接続する


layoutのxmlにWebViewタグを記述する

<WebView
android:id="@+id/webview"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />

activityクラスで呼び出す

private final static String YAHOO_URL = "http://www.yahoo.co.jp/";
private WebView webview;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.test);

this.webview = (WebView) findViewById(R.id.webview);
this.webview.loadUrl(YAHOO_URL);
}


manifest.xmlにインターネット接続の許可を記述

<uses-permission android:name="android.permission.INTERNET" />

あとはapkファイルを作成して、アプリを立ち上げればyahooに繋がります。
…とはいえ、このまま使うことはあまりないでしょう。
「構築したサイトにBasic認証で接続」とかが一般的でしょう。
というわけで、WebViewを利用して、Basic認証を行ってみます。

・例2
WebViewクラスを利用して、Basic認証で接続する

Basic認証を行う場合は、activityクラスを以下のように変更します。

private final static String TEST_URL = "http://www.test.com/";

public static final String USERNAME = "hoge";

public static final String PASSWORD = "hogehoge";

public static final String HOST = "www.test.com";

public static final String REALM = "Access Directory";


private WebView webview;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.main);

this.webview = (WebView) findViewById(R.id.webview);

this.webview.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);

this.webview.getSettings().setJavaScriptEnabled(true);
WebViewDatabase.getInstance(this).clearHttpAuthUsernamePassword();
this.webview.setHttpAuthUsernamePassword(HOST, REALM, USERNAME, PASSWORD);
this.webview.setWebViewClient(new WebViewClient(){

@Override
public void onReceivedHttpAuthRequest (WebView view,
HttpAuthHandler handler, String host, String realm){
String[] up = view.getHttpAuthUsernamePassword(host, realm);
if( up != null && up.length == 2 ) {
handler.proceed(up[0], up[1]);
} else{
Log.d("LOG_TAG","Could not find user/pass for domain :"+
host+" with realm = "+realm);
}
}
});
this.webview.loadUrl(TEST_URL);

}


TEST_URLをhttp://username:password@www.test.com/
と変更しても接続できないので注意してください。

又、Realmまできっちりと設定してください。でないと、動作しません。
あとは、HOSTとURLの指定を間違えないようにしてください。

これでapkファイルを作成して、アプリを立ち上げればbasic認証が行われ、TEST_URLに繋がります。
ただ、basic認証は接続に結構時間がかかるので、プログレスバーを利用したほうがいいでしょう。

なので、
WebViewクラスを利用して、Basic認証で接続
接続開始時にプログレスバーを表示
接続終了時にプログレスバーを非表示にして、toastメッセージを出力

とします。
以下がそのコードです

private final static String TEST_URL = "http://www.test.com/";

public static final String USERNAME = "hoge";

public static final String PASSWORD = "hogehoge";

public static final String HOST = "www.test.com";

public static final String REALM = "Access Directory";

private ProgressDialog mProgressDialog;

private WebView webview;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.main);

this.webview = (WebView) findViewById(R.id.webview);

this.webview.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);

this.webview.getSettings().setJavaScriptEnabled(true);
WebViewDatabase.getInstance(this).clearHttpAuthUsernamePassword();
this.webview.setHttpAuthUsernamePassword(HOST, REALM, USERNAME, PASSWORD);
this.webview.setWebViewClient(new WebViewClient(){

@Override
public void onReceivedHttpAuthRequest (WebView view,
HttpAuthHandler handler, String host, String realm){
String[] up = view.getHttpAuthUsernamePassword(host, realm);
if( up != null && up.length == 2 ) {
handler.proceed(up[0], up[1]);
} else{
Log.d("LOG_TAG","Could not find user/pass for domain :"+
host+" with realm = "+realm);
}
}


@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
//ダイアログを作成して表示
mProgressDialog = new ProgressDialog(view.getContext());
mProgressDialog.setTitle("ネットワーク接続");
mProgressDialog.setMessage("接続中です");
mProgressDialog.show();
}

@Override
public void onPageFinished(WebView wv, String url){

if (mProgressDialog != null && mProgressDialog.isShowing()) {
mProgressDialog.dismiss();
mProgressDialog = null;
Toast.makeText(wv.getContext(), "ネットワーク接続に成功しました", Toast.LENGTH_SHORT).show();
}
}
});
this.webview.loadUrl(TEST_URL);

}


onPageStartedがネットワーク接続開始時に呼び出され、onPageFinishedが接続終了時に呼ばれます。

最後にクッキーも扱えるように処理を追加します。

private final static String TEST_URL = "http://www.test.com/";

public static final String USERNAME = "hoge";

public static final String PASSWORD = "hogehoge";

public static final String HOST = "www.test.com";

public static final String REALM = "Access Directory";

private ProgressDialog mProgressDialog;

private WebView webview;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.main);

this.webview = (WebView) findViewById(R.id.webview);

this.webview.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);

this.webview.getSettings().setJavaScriptEnabled(true);
WebViewDatabase.getInstance(this).clearHttpAuthUsernamePassword();
this.webview.setHttpAuthUsernamePassword(HOST, REALM, USERNAME, PASSWORD);
this.webview.setWebViewClient(new WebViewClient(){

String loginCookie = "";
@Override
public void onLoadResource(WebView wv,
String url){
CookieManager cMgr = CookieManager.getInstance();
loginCookie = cMgr.getCookie(url);
}

@Override
public void onReceivedHttpAuthRequest (WebView view,
HttpAuthHandler handler, String host, String realm){
String[] up = view.getHttpAuthUsernamePassword(host, realm);
if( up != null && up.length == 2 ) {
handler.proceed(up[0], up[1]);
} else{
Log.d("LOG_TAG","Could not find user/pass for domain :"+
host+" with realm = "+realm);
}
}


@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
//ダイアログを作成して表示
mProgressDialog = new ProgressDialog(view.getContext());
mProgressDialog.setTitle("ネットワーク接続");
mProgressDialog.setMessage("接続中です");
mProgressDialog.show();
}

@Override
public void onPageFinished(WebView wv, String url){

CookieManager cMgr = CookieManager.getInstance();
cMgr.setCookie(url, loginCookie);

if (mProgressDialog.isShowing()) {
mProgressDialog.dismiss();
mProgressDialog = null;
Toast.makeText(wv.getContext(), "ネットワーク接続に成功しました", Toast.LENGTH_SHORT).show();
}
}
});
this.webview.loadUrl(TEST_URL);

}

以上です。
次はURLConnectionクラスを使ったネットワークのつなぎ方を記述する予定です。

それでわ。


参考サイト
http://developer.android.com/reference/android/webkit/WebView.html#setHttpAuthUsernamePassword%28java.lang.String,%20java.lang.String,%20java.lang.String,%20java.lang.String%29

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

2010年12月10日金曜日

androidのsqliteを日本語で使う

androidのsqliteの日本語処理ではまりました。
はまったのは以下のケース

・sqliteのsqlファイルを用意。sqlファイルの文字エンコーディングはUTF-8
・テーブルのtext型に文字列を格納。改行文字を\nとして格納
・android側でDBからデータを取得。文字をTextViewに設定すると\nがそのままviewに出力されていまう。
・\nを置換する。しかし、\nが置換されない。

というケースで半日はまった。
これでもjavaプログラマーなのかと自己嫌悪。

原因
・置換改行文字をUTF-8に変換していなかった。

最初は

String hoge = getDB();
hoge.setText(hoge.replaceAll("\\\\n", "\n"));

とやっていた。

だが、これはNG。すっかり忘れていたが、javaの文字列内部コードはISO-8859-1なのである。androidとて例外ではない。
脳がフレームワーク脳になっている。

ここは、パターンマッチに使う改行文字をUTF-8のコードに変換してやる必要がある。
以下、解決方法

byte[] bytes = "\\\\n".getBytes("ISO-8859-1");
String new_line = new String(bytes, "UTF-8");

これでUTF-8の改行パターンマッチが取得できる。
あとは普通にreplaceAllを使う

hoge.setText(hoge.replaceAll(new_line, "\n"));

これで思い通りの結果が出力される。


ps
スマートフォンアプリの開発では英語力があったほうが良い。
これはiphoneもandroidでも共通だ。
ドキュメントや講義のyoutubeが英語が中心だからだ。
仕方なしに空き時間には英語の勉強もちょこちょこやっているのだが、英語ができるようになればなるほど日本語が好きになるのが不思議だ。
英語が世界共通語だから英語メインになっていくのは仕方ないが、英語に触れれば触れるほど、
日本人ということを強く意識するようになるは皮肉なものである。

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加

androidのlogcatで日本語を使う

世阿弥も愛した素敵な日本語。しかし、androidは日本語をあまり愛していないようだ。なので、ときどき文字コードで困ったことが起こる。
以下、解決方法をメモ。

Logで日本語を出力

eclipseでlogcatを見ると、日本語が文字化けする。なんという非国民。愛国者になるには、コマンドプロンプトを利用する

windowsXPの場合の手順

・コマンドプロンプトを立ち上げる

・タイトルバーを右クリック

・プロパティ

・フォントタブを選択肢、MSゴシックにする

・UTF-8に変更するため、プロンプトに以下のコマンドを打ち込む
chcp 65001

・logを出力(サンプルはDebugレベル)
adb logcat -d

で日本語でlogが出力されるようになります。

この記事がお役にたちましたらシェアをお願いします

このエントリーをはてなブックマークに追加
Related Posts Plugin for WordPress, Blogger...