ラベル android の投稿を表示しています。 すべての投稿を表示
ラベル android の投稿を表示しています。 すべての投稿を表示

2016年7月11日月曜日

Android エミュレーターでホストに通信するときのIP

Android エミュレーターでホストマシンのPCに通信するとき、PCのIPは 10.0.2.2

2013年11月14日木曜日

Android Eclipse ADTでビルドできていたプロジェクトが急にコンパイルエラーになった時の対処法

EclipseのADT(Android Development Tools)を使いAndroidアプリ開発していると、今まで問題なかったプロジェクトが急にコンパイルエラーになってしまうことがよくある。

自分のところではEclipseを落としてあげなおしたときに良く発生する。

原因としては自動生成のR.javaがなくなるなどgenフォルダの中身がおかしくなってコンパイルエラーというようである。

そうなってしまうと厄介だが、今のところ以下のいづれかで復旧できるようだ。

  • プロジェクトをクリーンする。
  • プロジェクトを右クリックし、"Android Tools"→"Fix Project Properties"を選択、その後プロジェクトをクリーンする。
  • プロジェクトを一旦削除(ファイルは消さないこと!)。その後再度インポート。

ただ状況によってどれが効くというのが異なるので、いろいろ試してみることになる。

2013年7月8日月曜日

Android 指を近づけただけで応答 FloatingTouch

Galaxy S4のように指を画面に近づけただけで反応するUIをどんなキーワードで調べたらいいかと思っていたが、FloatingTouchというらしい。 しかも、どうも最初に搭載したのはGalaxyではなくSONY XPERIAらしい。全然知りませんでした。

XPERIAの場合APIとしてはView.OnHoverListenerあたりが呼ばれるようです。 HoverはPCではよく使うAPIですがAndroidにもあるので、いつ呼ばれるのだろうと思っていましたがこういう機能向けだったのですね。 Galaxyのほうも同じような仕様なんだろうか…。

うまくつかうとUIの表現方法が広がりそうですが実機が無いので試せないのが残念。 今後搭載端末が増えてきて標準的に使えるようになるのを期待したいです。

それにしてもコマーシャルを見ているとGalaxy特有の機能に見えてしまう。 SONYももっと宣伝すればいいのに… キラーアプリを作れなかったのか?

2013年7月5日金曜日

Android Nexus7にADB接続しようとしてはまる

去年買って使っていたNexus7では特にトラブルなくPCからADB接続できていたのだが、最近買った新しいNexus7を接続しようとしたところではまってしまった。

開発者オプションが無い

設定画面にUSBデバッグを有効化するための開発者オプションが見当たらない。 以下の記事によると隠しコマンドになったようである。どうしてこうなった…

ADBが認識しない

USBデバッグを有効にできたので早速つないでみるとNexus側では "USBデバッグが接続されました" と出るのだが、PC側のADBが "waiting for device" のまま…。 以下記事によると接続の種別を変更する必要があるとのこと。これは分からないわ。

これら方々の記事のおかげで助かった。 Android SDKもバージョンが変わるとわけのわからないトラブルが起きるが、Nexusも同じとは困ったものである。

関連記事

2013年6月20日木曜日

Android カスタムViewの作成

AndroidでカスタムViewを作成するには、ViewまたはViewGroupを継承して作成する。 Java AWTでたとえると(今は分かる人が少ないかも)View=ComponentとViewGroup=Containerの関係に相当すると考えればいいと思う。

複数の子ViewをもつようなカスタムViewの場合、典型的な作り方のパターンとしてはViewGroupを継承してカスタムクラスを作り、最低限以下のメソッドをオーバーライドする。

onMeasureメソッド
ViewGroupのサイズを決める
onLayoutメソッド
実際に子Viewを配置する

2013年5月21日火曜日

Android Eclipse ADT22へのアップグレードではまる

Android SDKをバージョン22にアップグレードしたら、Eclipse ADT(Android Development Toolkit)も同じく22にアップグレードしろというのでアップデート。すると、いきなり既存プロジェクトのgenフォルダのファイルが自動生成されないようになりR.javaが参照できないという大量のエラーが出るようになった。

非常に困っていたが以下のページに助けられる。

どうやらAndroid SDK Build-toolsというツールが新しくビルドに必要になったようである。

こんなのわかるわけない…
せめて自動でインストールしてほしい。

まるで古いPCのアドベンチャーゲームをやらされているような感覚である。 そして、後日Nexus7でもやられてしまった。

関連記事

2013年5月19日日曜日

Android Viewのカスタム属性の作り方

自作のViewにカスタム属性を定義してレイアウトXMLから設定を変えられるようにする場合は、attr.xmlのdeclare-styleableで定義をする方法についてのメモ。

背景色の属性

背景色関連の属性は以下のように色(color)や画像(drawable)で設定できるようにできるとよい。
<!-- 色(color)でmyBackgroundを指定する -->
<myapp.MyView
  android:id="@+id/myview"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  myapp:myBackground="#ffff0000"
/>

<!-- イメージ(drawable)でmyBackgroundを指定する -->
<myapp.MyView
  android:id="@+id/myview"
  android:layout_width="wrap_content"
  android:layout_height="wrap_content"
  myapp:myBackground="@drawable/bg"
/>

こんなときはまず attr.xmlでは以下のようにreferencecolorの属性として定義する。

<resources>
  <declare-styleable name="MyView">
    <attr name="myBackground" format="reference|color"/>
  </declare-styleable>
</resources>

自作ViewのJava側ではDrawableとして受け取り、背景色を設定したいviewにsetBackgrund()で設定する。 colorもDrawableで受けることができ、背景色として設定できるようだ。 この方法でよいのか公式なドキュメントを確認できていないが問題なく動いているようである。

public MyView(Context context, AttributeSet attrs) {
  super(context, attrs);

  Drawable myBackground = a.getDrawable(R.styleable.MyView_myBackground);
  if (myBackground != null) {
    myView.setBackgroundDrawable(myBackground);
  }
}
ちなみに、AttributeSet.getColor()で受けると以下のようなエラーが出る。 背景色を設定できるようにする場合は特に理由がなければDrawableで受けるようにしておいたほうが無難だろう。

Caused by: android.view.InflateException: Binary XML file line #35: Error inflating class myapp.MyView
    at android.view.LayoutInflater.createView(LayoutInflater.java:613)
    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:687)
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:746)
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:749)
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:749)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:489)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:396)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:352)
    at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:270)
    at android.app.Activity.setContentView(Activity.java:1881)
    at myapp.MyActivity.onCreate(MyActivity.java:58)
    at android.app.Activity.performCreate(Activity.java:5104)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2144)
    ... 11 more
Caused by: java.lang.reflect.InvocationTargetException
    at java.lang.reflect.Constructor.constructNative(Native Method)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:417)
    at android.view.LayoutInflater.createView(LayoutInflater.java:587)
    ... 24 more
Caused by: android.content.res.Resources$NotFoundException: File res/drawable-hdpi/bg.png from drawable
resource ID #0x7f020011: .xml extension required
    at android.content.res.Resources.loadColorStateList(Resources.java:2094)
    at android.content.res.TypedArray.getColor(TypedArray.java:319)
    at myapp.SampleQueryView.(SampleQueryView.java:54)
    ... 27 more

2013年5月16日木曜日

Android Twitter4JでOAuth認証する

Twitter4JでOAuth認証するための方法を調査した時のメモ。

Callback URLを使わずお手軽にすませる方法を使った。 この場合はTwitterログインの後にPIN番号が画面に表示されるので、それを手で入力して認証を完了する。 大まかな手順は次のようである。

  1. TwitterにRequestTokenトークン要求
  2. Twitterから認証のためのログインページURLが返されるのでブラウザで表示
  3. ユーザーがログインしてアプリを許可するとTwitterがPIN番号を発行
  4. TwitterにPINを渡してAccessトークン取得

今回紹介するコードはAndroidアプリつぶマップで使用しているので、 どのように動くか興味ある方はインストールしてもらえるとよいかと思う。

「つぶマップ」ダウンロードサイトへ

Twitter4Jラッパークラス

RequestTokenトークン要求とAccessトークン取得の際、素のままのTwitter4J APIを呼び出してもよいが、 それぞれの処理間での値の保持のためラップしたクラスを作成し呼び出すようにした。
public class TwitterTest {

  private static final String CONSUMER_KEY = "アプリに発行されたConsumer Key";
  private static final String CONSUMER_SECRET = "アプリに発行されたConsumer Secret";
  
  private Twitter twitter;
  private RequestToken requestToken;
  
  public String requestToken() {
    // インスタンスの初期化
    twitter = TwitterFactory.getSingleton();

    // Twitterに登録したアプリのConsumer key と Consumer secretを設定
    twitter.setOAuthConsumer(CONSUMER_KEY, CONSUMER_SECRET);

    // RequestTokenトークン要求
    // 認証ページのURLを返すのでWebViewで表示しユーザーにログインしてもらう
    requestToken = twitter.getOAuthRequestToken();
    return requestToken.getAuthorizationURL();
  }
  
  // Accessトークン取得。引数にWebで表示されたPINを入れる。
  // 認証済みのTwitterインスタンスを返す
  public Twitter getAccessToken(String pin) throws TwitterException {
    if (requestToken == null) return false;
    
    // RequestTokenとPINよりAccessトークン取得
    AccessToken _accessToken = twitter.getOAuthAccessToken(requestToken, pin);
    return twitter;
  }
}

アプリ側

アプリ側ではラッパークラスを使い次のようにコードを書く。

まず、TwitterにRequestTokenトークン要求する。ラッパークラスのrequestToken()メソッドを呼び出す。

TwitterTest t = new TwitterTest();
String url = t.requestToken();

メソッド呼び出しの結果、認証のためのTwitterへのログインページURLが返されるのでこのURLをWebViewに表示する。 以下のような画面が開く。同じ画面の上部にはPIN番号を入力するためのEditTextを配置した。

ログインページでユーザーがログインしてアプリを許可するとTwitterがPIN番号を発行する。 画面表示されたPIN番号をユーザーに入力してもらう。

入力されたPINを引数にラッパークラスのgetAccessToken()メソッドを呼び出すことで認証が完了する。

String pin = "ユーザー入力のPIN番号";
Twitter twitter = t.getAccessToken(pin);

メソッドの返り値である認証済みTwitterインスタンスを使ってツイート取得や検索ができる。 以下は検索の例である。

Query q = new Query();
q.setQuery("キーワード");
QueryResult qr = twitter.search(q);

皆さんもぜひ試してみてください。

2013年4月3日水曜日

Android ParcelでString[]を読んだり書いたり

AndroidのJavaオブジェクトのシリアライズ機構ParcleにStringの配列を読み書きする方法。

メソッド名の対応からしてwriteStringArray()で書いたものをreadStringArray()で読み込むのだろうと思っていたが読むほうはcreateStringArray()になるようである。 以下のような感じになるらしい。

public class MyObj implements Parcelable {

  private String[] texts;

  // 読むほう
  public MyObj(Parcel in) {
    texts = in.createStringArray();
  }

  // 書くほう
  @Override
  public void writeToParcel(Parcel out, int flags) {
    out.writeStringArray(texts);
  }

  ...
}

readStringArray()でも読み込めるようだが、書き込んだ長さと同じ配列をあらかじめ準備して引数に指定するらしい。 長さが決まってない配列に使うのは面倒そうだし、nullは扱えなさそうである。 固定長の配列を連続読み込みするような場合には使えそうだが、それ以外はあまり出番が無いのではと思う。

2011年1月18日火曜日

Android アプリからツイートする(非正攻法)

AndroidのアプリからTwitterに投稿するには正攻法としてはTwitter APIを使うのがよいであろう。

しかし、OAuthなどが必要だったり敷居が高く感じる人も多いであろう。

端末にTwitter公式アプリが入っているという前提があるなら、Intentを使うことで投稿準備ができた状態でTwitterアプリを起動し最後に投稿ボタンを押してもらうだけでツイートできるようになる。

Intent intent = new Intent(Intent.ACTION_SEND);
intent.setClassName("com.twitter.android", "com.twitter.android.PostActivity");
intent.setType("text/plain");
intent.putExtra(Intent.EXTRA_TEXT, "Androidから投稿なう"); // 投稿するメッセージ
try {
startActivity(intent);
}
catch(ActivityNotFoundException ex) {
// Twitter公式アプリが無いときのエラー処理
}


ただし公式アプリのクラスを直接呼び出しているので、将来アプリがバージョンアップされた場合には動かなくなる可能性があることに注意。

とりあえず Twitter公式アプリVersion1.0.5で動作を確認した。他のバージョンでの動作報告をコメントしてもらえるとありがたいです。

Android アプリからSMSを送る

Androidのアプリ中からSMSを送るにはIntentを使う。ネットで調べるとそのパラメータの設定についていろいろなやり方があるようだがOSバージョンや搭載しているSMSアプリの種類によって挙動が変わるのかGalaxyTabでうまくいくパターンがなかった。

試行錯誤の結果、以下のような方法で宛先と本文を埋めた状態で標準SMSアプリが起動することがわかった。あとはユーザーに送信ボタンを押してもらえばSMSが発信される。

Uri uri = Uri.parse("smsto://");
Intent intent = new Intent(Intent.ACTION_VIEW, uri);
intent.setType("vnd.android-dir/mms-sms");
intent.putExtra("address", "090xxxxxxxx"); // 電話番号を入れる
intent.putExtra("sms_body", "こんにちは"); // 送信メッセージを入れる
try {
startActivity(intent);
}
catch(ActivityNotFoundException ex) {
// SMSアプリが無いときのエラー処理
}

2011年1月13日木曜日

Android 文字列リソースのエラー

EclipseのAndroid Development Toolkitをアップデートしたときにはまったときのメモ

アップデート前まで正常だったプロジェクトで、strings.xmlがこのようなエラーをはくようになりビルドできなくなってしまった。


W/ResourceType(15164): Bad XML block: header size 276 or total size 18088132 is larger than data size 0
...\res\values\strings.xml:13: error: Multiple substitutions specified in non-positional format; did you mean to add the formatted="false" attribute?
...\res\values\strings.xml:13: error: Unexpected end tag string



プロジェクトが壊れてしまったのかと思いあわてたが、ここの情報によると、書式文字列のチェックが厳しくなったようで、%sなどの置換部分が2個以上ある場合はそれぞれに位置を指定する必要があるらしい。

たとえば、今までこうしていたのは、

<string name="message">製品名=%s %d円です</string>


このように書き換える必要がある。

<string name="message">製品名=%1$s %2$d円です</string>


おまけ

アップデート直後にEclipseを起動すると "sdk platform tools component is missing" というエラーが出るかもしれない。その場合は、メニューから Android SDK and AVD Managerを起動してインストールされているパッケージすべてをUpdate Allしてやると復旧するようです。

2010年12月5日日曜日

Android エミュレータにメディアデータを追加

Androidエミュレーター(Virtual Device)にmp3などの音楽ファイルを転送し標準のメディアプレイヤーで再生できるようにする方法。たまにしかやらない作業なのでいつもやり方を忘れてしまう・・・ここにメモしておこう。ここで使ったホスト機はWindowsです。また、Virtual Deviceには作成したときにSDCARDの容量が適当に割り当てられていることとします。


  1. Virtual Device起動。

  2. コマンドプロンプトから adb shell でシェルに入り mkdir /sdcard/music でフォルダを作成する。

  3. コマンドプロンプトに戻り adb push {mp3ファイル} /sdcard/music を実行して、さっき作ったフォルダにmp3ファイルを転送。({mp3ファイル}のところにはファイル名いれる)

  4. Virtual Deviceのアプリの一覧から "Dev Tools" を実行し "Media Scanner" を実行する









"Media Scanner" を実行すると上記のような画面になり、標準のメディアプレイヤーで追加したファイルを認識できるようになる。

2010年11月18日木曜日

java.util.Dateとandroid.text.format.Time どちらを使うべきか?

Androidにはjava.util.Dateやjava.util.Calendarに似たクラスandroid.text.format.Timeがあり、日付データを扱うときどちらを使うべきか迷うところであるが、ドキュメントによるとjava.util.Calendarより高速な代替品と書いてあるので、文字列にして表示したり日付計算する場合は後者を使うのがよさそうに思える。

http://developer.android.com/reference/android/text/format/Time.html

まだドキュメントを読んだ限りなので、ちょっと実際に使って試してみることにしよう。

2010-12-20 追記
android.text.format.TimeはSerializableでないことが判明。つまりIntentに入れてActivity間で受け渡すデータとしては使えないので注意が必要です。

Timeをサブクラス化してSerializableをimplementsしたものを作ればいいのかもしれないが、将来的にTimeのインスタンス変数にSerializableでないものが入ってくるとアウトなので今回は利用を見送る。

2010年9月9日木曜日

Android nativeコードでファイル書き込み

AndroidでJNIを使ってnativeコードからファイルを読み書きする方法を調べた。ファイルは /data/data/{pkgname} 以下のフォルダに読み書きすることができるらしい。読み書きはLinuxでのファイルIOと同じ関数open/read/write/closeが使える。

Javaからnativeの関数に byte[]配列を渡してそれをファイルに書き込む関数を作ってみた。以下のJavaソースをjavahで変換して対応するヘッダファイルを作成。

FileManager.java

package test.filetest;
public class FileManager {
public native int write(byte[] data);
static { System.loadLibrary("filetest"); }
}


test_filetest_FileManager.h

#include <jni.h>

#ifndef _Included_test_filetest_FileManager
#define _Included_test_filetest_FileManager
#ifdef __cplusplus
extern "C" {
#endif

JNIEXPORT jint JNICALL Java_test_filetest_FileManager_write
(JNIEnv *, jobject, jbyteArray);

#ifdef __cplusplus
}
#endif
#endif


Java_test_filetest_FileManager_write関数の実装は以下のようにしてみた。エラーから抜けるのにgotoを多用しているので人により好き嫌いあるかもしれないが、NDKだとtry-catchが使えないようなのでこの方法が楽といえば楽。

test_filetest_FileManager.cpp

#include "test_filetest_FileManager.h"
#include <string.h>
#include <fcntl.h>
#include <android/log.h>

#define _DBGPRINTF(...) __android_log_print(3, "filetest", __VA_ARGS__)

JNIEXPORT jint JNICALL Java_test_filetest_FileManager_write
(JNIEnv* env, jobject caller, jbyteArray jBin)
{
jbyte* bin = NULL;
int binSize;
int err = 0;
int s;

_DBGPRINTF("Java_test_filetest_FileManager_write");

// ファイルを /data/data/{pkgname} 以下のフォルダに読み書きする
// ここでは hello.dat を書き込み用にオープン(O_WRONLY)。無ければ作成(O_CREAT)
// ファイルのmodeを 0666 に設定
int fd = open("/data/data/test.filetest/hello.dat",
O_WRONLY|O_CREAT,
S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
_DBGPRINTF("fd=%d\n", fd);
if (fd < 0) {
_DBGPRINTF("Error: open");
err = -1;
goto error_exit0;
}

// 渡されたJava byte配列を C byte 配列に変換
bin = env->GetByteArrayElements(jBin, NULL);
if (bin == NULL) {
_DBGPRINTF("Error: GetByteArrayElements");
err = -1;
goto error_exit1;
}
// 渡されたJava byte配列の長さを取得
binSize = env->GetArrayLength(jBin);
_DBGPRINTF("Write: %d bytes");

// writeで書き込み
s = write(fd, (void*)bin, binSize);
_DBGPRINTF("Write: ret=%d", s);
if (s < 0) {
_DBGPRINTF("Error: write");
err = -1;
}
// C byte配列を使い終わったのでメモリから解放
env->ReleaseByteArrayElements(jBin, bin, 0);

error_exit1:
// ファイルクローズ
close(fd);

error_exit0:
return err;
}


Androidのファイルシステムの中身は adb shell コマンドでシェルに入ることで確認できる。プログラムを実行すると、/data/data/test.filetestフォルダには確かにファイルができていた。

# cd /data/data/test.filetest
cd /data/data/test.filetest
# ls -l
ls -l
-rwxr-xrwT app_28 app_28 256 2010-09-09 13:31 hello.dat
drwxr-xr-x system system 2010-09-09 13:23 lib



その上位のフォルダ一覧を見てみると、フォルダ(パッケージ名)ごとに所有者やパーミションがついているのがわかる。アプリごとに所有者が違うということはAndroidはこの仕組みを使ってアプリごとのアクセス管理をしているのだろうか?

# cd /data/data
cd /data/data
# ls -l
ls -l
drwxr-xr-x app_28 app_28 2010-09-09 13:23 test.filetest
drwxr-xr-x app_24 app_24 2010-07-14 12:15 jp.hews.intent
drwxr-xr-x app_21 app_21 2010-01-27 13:32 com.android.mms
drwxr-xr-x app_5 app_5 2010-01-27 13:32 com.android.camera
drwxr-xr-x app_4 app_4 2010-01-27 13:32 com.android.email
...



2010/9/27追記:
openの際に O_CREAT が指定されている場合にはmode(ファイルパーミション)指定が必要のため追加