FC2ブログ
HOME   »  Android
Category | Android

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

[Android]Buttonを押さずにonClickイベントを発生させる

Buttonを押さずにonClickイベントを発生させる方法。

Button(View)のsetOnClickListenerメソッドでOnClickListener(インタフェースを実装したクラスのインスタンス)を設定しておくと、Buttonが押された際にOnClickListenerのonClickメソッドが呼び出される。
通常は物理的にButtonを押す(クリックする)ことによりこのonClickメソッドが呼び出されるが、Buttonを押す代わりにButton(View)のperformClickメソッドを実行することでもonClickメソッドを呼び出すことができる。

ViewクラスのソースコードでperformClickメソッドを見ると、
public boolean performClick() {
    sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_CLICKED);

    if (mOnClickListener != null) {
        playSoundEffect(SoundEffectConstants.CLICK);
        mOnClickListener.onClick(this);
        return true;
    }

    return false;
}
となっており、mOnClickListener(setOnClickListenerメソッドで設定したOnClickListener)のonClickメソッドが実行されている。

以下の例で確認してみる。

まず、下記の様なButton 2個とTextView 1個のActivityを準備する。

ClickTest1

Activityの実装は以下の通り。
public class MainActivity extends Activity implements View.OnClickListener {
    private Button button1;
    private Button button2;
    private TextView textView1;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        button1 = (Button) findViewById(R.id.button1);
        button2 = (Button) findViewById(R.id.button2);
        textView1 = (TextView) findViewById(R.id.textView1);
        button1.setOnClickListener(this);
        button2.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        if (v == button1) {
            button2.performClick();
        } else if (v == button2) {
            textView1.setText("Click button2");
        }
    }
}
13行目と14行目で各Button(button1とbutton2)のOnClickListenerとしてMainActivity自らを設定し、18行目からonClickメソッドを実装。
onClickメソッドの中では、button1が押されたらbutton2のperformClickメソッドを実行し、button2が押されたらtextView1に"Click button2"と表示する様にしている。

以上を実行してbutton1を押してみると、

ClickTest2

あたかもbutton2が押されたかの様に動作し、textView1に"Click button2"と表示されている。

このperformClickメソッドは、テスト等で擬似的にButton押下の動作をさせる際に使用できる。


スポンサーサイト

[Android]マルチスレッドでBluetoothAdapterクラスを扱う場合の注意点

BluetoothAdapterクラスのインスタンスは、コンストラクタではなくBluetoothAdapterクラスのgetDefaultAdapterメソッドを使用して取得する。
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
下記では、BluetoothAdapterのインスタンスを問題なく取得でき、Toastによる"Completed"メッセージが表示される。
public class MainActivity extends Activity {
    private BluetoothAdapter bluetoothAdapter;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
        if (bluetoothAdapter != null) {
            Toast.makeText(this, "Completed", Toast.LENGTH_SHORT).show();
        }
    }
}
しかし下記では、getDefaultAdapterメソッド実行時にRuntimeException("Can't create handler inside thread that has not called Looper.prepare()")がスローされてしまう。
public class MainActivity extends Activity {
    private BluetoothAdapter bluetoothAdapter;
    private Handler handler;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        handler = new Handler();
        new Thread() {
            @Override
            public void run() {
                bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
                if (bluetoothAdapter != null) {
                    handler.post(new Runnable() {
                        public void run() {
                            Toast.makeText(MainActivity.this, "Completed", Toast.LENGTH_SHORT).show();
                        }
                    });
                }
            }
        }.start();
    }
}
これは、getDefaultAdapterメソッドあるいはそこから呼ばれる別のメソッドの中でHandlerクラスあるいはそのサブクラスのコンストラクタを実行しているからである。

Handlerクラス及びそのサブクラスはメッセージの投げ先として、コンストラクタの引数あるいは内部処理にてLooperクラスのインスタンスを取得して保持しており、このLooperクラスのインスタンスはスレッドと1対1で関連付けられている(1つのスレッドには1つのLooperクラスのインスタンスのみが存在し得る)。
上記の失敗する場合では、getDefaultAdapterメソッドがメインスレッドとは別のスレッドで実行されており、このスレッドには関連付けられたLooperクラスのインスタンスが存在しない為、結果としてHandlerクラスあるいはそのサブクラスのコンストラクタにてRuntimeExceptionがスローされることになる(メインスレッド(UIスレッド)には裏で自動的にLooperクラスのインスタンスが関連付けられている為、特に意識する必要はないが、自前のスレッドではLooperクラスのprepareメソッドを実行して明示的に関連付ける必要がある)。

マルチスレッドでBluetoothAdapterクラスを扱う場合は注意が必要である。


[Android]BluetoothのSPPで使用するUUID

BluetoothをSPP(Serial Port Profile)で使用する場合、BluetoothDeviceクラスのcreateRfcommSocketToServiceRecordメソッド等の引数として設定するUUIDは、以下の値を使用する必要がある。

00001101-0000-1000-8000-00805F9B34FB

Android SDK付属のサンプルアプリケーション「Bluetooth Chat」では、このUUIDが

FA87C0D0-AFAC-11DE-8A39-0800200C9A66

となっているので注意が必要。

尚、UUIDクラスのfromStringメソッドを使用して文字列からUUIDクラスのインスタンスを取得する場合は、引数の文字列をRFC 4122で規定されている以下のフォーマットで設定する必要がある。

"4バイト(8文字)-2バイト(4文字)-2バイト(4文字)-2バイト(4文字)-6バイト(12文字)"


[Android]WebViewのイベントが発生した時に任意の処理をさせる

WebViewの各イベント(ページ読み込み開始/ページ読み込み完了等)が発生した時に任意の処理をさせたい場合は、WebViewClientクラスを使用する。

まず、WebViewClientクラスを継承したクラスを作成し、任意の処理をさせたいイベントのイベントハンドラメソッドをオーバーライドして、そのメソッドの中で目的の処理を実装する(下記の例はページ読み込み開始時とページ読み込み完了時の処理を実装)。
public class MyWebViewClient extends WebViewClient {
    @Override
    public void onPageStarted(WebView view, String url, Bitmap favicon) {
        あれこれ(ページ読み込み開始時の処理)
    }

    @Override
    public void onPageFinished(WebView view, String url) {
        あれこれ(ページ読み込み完了時の処理)
    }
}
そして、上記のクラスのインスタンスをWebViewクラスのsetWebViewClientメソッドの引数として設定する。
WebView webView = (WebView) findViewById(R.id.webView);
webView.setWebViewClient(new MyWebViewClient());
これで、webViewでのページ読み込み開始時とページ読み込み完了時に、MyWebViewClientクラスで実装した処理をさせることができる。


[Android]Handlerクラスのまとめ

UIの操作を別スレッドから実行する時に使用するHandlerクラスについてのまとめ。

○postメソッド
HandlerクラスのインスタンスはUIスレッドで取得する。
取得した(Handlerクラスの)インスタンスのpostメソッドは別スレッドで実行する。
postメソッド実行により、postメソッドの引数に設定したRunnable(インタフェースを実装した)クラスのrunメソッドがUIスレッドで実行されるので、runメソッドでUI操作コードを実装することにより、別スレッドからのトリガによるUI操作ができる。

○sendEmptyMessageメソッド
Handlerクラスを継承したクラスのインスタンスはUIスレッドで取得する。
取得した(Handlerクラスを継承したクラスの)インスタンスのsendEmptyMessageメソッドは別スレッドで実行する。
sendEmptyMessageメソッド実行により、Handlerクラスを継承したクラスのhandleMessageメソッドがUIスレッドで実行されるので、handleMessageメソッドをオーバーライド(UI操作コードを実装)することにより、別スレッドからのトリガによるUI操作ができる。

○sendMessageメソッド
使い方はsendEmptyMessageメソッドと同じ。
引数としてMessageクラスのインスタンスを渡すことができるので、別スレッドからUIスレッドへ情報を渡すことができる。

○postDelayed/sendEmptyMessageDelayed/sendMessageDelayedメソッド
使い方はそれぞれpost/sendEmptyMessage/sendMessageメソッドと同じ。
第2引数に設定した時間分実行を遅らせることができる。

○postAtTime/sendEmptyMessageAtTime/sendMessageAtTimeメソッド
使い方はそれぞれpost/sendEmptyMessage/sendMessageメソッドと同じ。
第2引数で実行する時間を指定することができる。


[Android]SDカードに書き込む時のパーミッション設定

アプリケーションからSDカードに何らかのデータを書き込める様にする為には、Wi-Fi機能を使用する時と同様に、

android.permission.WRITE_EXTERNAL_STORAGE

というパーミッション設定を以下の様にAndroidManifest.xmlに追加する必要がある(7行目)。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="xxxxxxx"
          android:versionName="1.0.0" android:versionCode="1">
    <uses-sdk android:targetSdkVersion="4" android:minSdkVersion="4"/>

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

    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name="xxxxxxx.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>
    </application>
</manifest>
尚、このパーミッション設定はAndroid 1.6から必要になったらしい。


[Android]SDカードのパスを取得する

アプリケーションからSDカードにデータ等を保存したい時、保存先としてSDカードのパスを知る必要がある。

特定の端末のみを対象とするのであれば、その端末固有のパスを直接指定する方法もあるが、汎用的なアプリケーションとしたい場合は、それでは都合が悪い。

そんな時は、EnvironmentクラスのgetExternalStorageDirectoryメソッドとFileクラスのgetPathメソッドを使用すればよい。

まず、EnvironmentクラスのgetExternalStorageDirectoryメソッドでSDカードについてのFileクラスのインスタンスを取得し、取得したFileクラスのインスタンスからgetPathメソッドによりSDカードのパスを表す文字列を取得する。
File sdCardFile = Environment.getExternalStorageDirectory();
String sdCardPath = sdCardFile.getPath();


[Android]Wi-Fi機能を使用する時のパーミッション設定

Wi-Fi機能を使用する(状態を参照する/設定を変更する)時には、

android.permission.ACCESS_WIFI_STATE(状態参照)
android.permission.CHANGE_WIFI_STATE(設定変更)

の2つのパーミッション設定を以下の様にAndroidManifest.xmlに追加する必要がある(7行目と8行目)。
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="xxxxxxx"
          android:versionName="1.0.0" android:versionCode="1">
    <uses-sdk android:targetSdkVersion="3" android:minSdkVersion="3"/>

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

    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name="xxxxxxx.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>
    </application>
</manifest>


[Android]ProgressDialogのコンストラクタ引数Contextについて

Activityからメソッドを呼ぶ時に渡す引数Contextを指定する方法として、Activity自身を指すthisを指定する方法と、getApplicationContextメソッドで取得したContextを指定する方法の2通りがある(他にもまだあるかも?)。

ProgressDialogのコンストラクタも引数としてContextを渡す必要があるが、この場合getApplicationContextメソッドで取得したContextでは正常に動作しない為、thisを指定する必要がある。


[Android]画面の向きを変えた時にActivityの状態を保持する

画面の向きを変える(縦→横/横→縦)と、通常はActivityが一旦破棄(onDestroy)された後再生成(onCreate)される為、Activityの状態が初期状態に戻ってしまう。

これを防止する為には、AndroidManifest.xml内のactivityタグにandroid:configChanges属性を追加すればよい。
<activity android:name="xxxxxxx.MainActivity"
          android:label="@string/app_name"
          android:configChanges="orientation">
android:configChanges属性でorientationを指定してやると、画面の向きが変わった時の処理はアプリケーション側で引き受ける、と宣言したことになり、勝手?にActivityが更新されてしまうことを防止できる。

(2011-05-30 追記)
画面の向きが変わった際、orientationのイベント以外にkeyboardHiddenのイベントも発生する場合があり、万全を期す為には、以下の様にorientationに加えてkeyboardHiddenも指定した方がよいかも(複数同時に指定する場合は、"|"で区切って併記する)。
<activity android:name="xxxxxxx.MainActivity"
          android:label="@string/app_name"
          android:configChanges="orientation|keyboardHidden">
尚、android:configChanges属性で指定したイベントが発生した時は、Activityが更新される代わりにonConfigurationChangedメソッドが呼ばれる為、このメソッドをオーバーライドすることにより、イベント発生時の処理をアプリケーション側で任意に実装することができる。


プロフィール

まさお

Author:まさお
プログラミングは趣味レベルなので、お手柔らかに。

ブログランキング
ブログランキング参加中。是非クリックお願いします。


にほんブログ村 IT技術ブログ Androidアプリ開発へ

人気ブログランキングへ

ブログランキング



ブログ王

ブログランキング【ブログの惑星】

プログラム人気ブログランキング
最新記事
最新コメント
最新トラックバック
月別アーカイブ
カテゴリ
検索フォーム
RSSリンクの表示
リンク
ブロとも申請フォーム
QRコード
QR
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。