My Photo

« Xperia rayにb-mobile Fair導入 | Main | 配列リテラル »

November 09, 2011

Androidアプリ開発メモ036:AppWidget その3:設定用Activity

AppWidgetについての以前の記事:
Androidアプリ開発メモ034:AppWidget
Androidアプリ開発メモ035:AppWidget その2

設定用Activity

AppWidgetを貼り付けるときに設定画面を出すことが出来る。

  • 設定ファイルのandroid:configure(Androidアプリ開発メモ034参照)に、Activityのパッケージ名を含む完全なクラス名を書く。完全なクラス名で書くのは、このActivityがAppWidgetホストから起動されるからだろうか。
  • AndroidManifest.xmlにactivity要素を追加し、APPWIDGET_CONFIGUREアクションを受け取れるようにintenti-filter要素を追加する。

下記はAndroidManifest.xmlへの追記の例。
<activity android:name=".AppWidgetExampleConfigure">
  <intent-filter>
    <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
  </intent-filter>
</activity>

Activityのコードでは以下の事を行う。
  1. AppWidget IDをIntentから取得する。
  2. AppWidgetを設定する。
  3. AppWidgetManger#updateAppWidgetでAppWidgetを更新する。
  4. setResult()でRESULT_OKをActivityの起動元に返すようにして終了する
リファレンスには、設定用Activityを使う場合はAppWidgetが作成されたときにACTION_APPWIDGET_UPDATEがブロードキャストされない、つまりonUpdate()が呼ばれないとある。よって、上記3にあるようにupdateAppWidget()で画面を更新する。
しかし、AVD上で実行するとAppWidgetのホーム画面に貼り付けるとonUpdate()が呼ばれる。リファレンスの記述とAVDがどちらが正しのかは不明。
以下は設定アクティビティのエディットテキストに入力した文字を表示するAppWidgetの例。
package com.example.appwidgetexample;

import android.app.Activity;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.RemoteViews;

/**
 * AppWidget設定用Activity
 */
public class AppWidgetExampleConfigure extends Activity
	implements View.OnClickListener {
	
	EditText editText1;
	int mAppWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		Log.v("TEST", "AppWidgetExampleConfigure#onCreate()");
		
		// Set the result to CANCELED.  This will cause the widget host to cancel
		// out of the widget placement if they press the back button.
		setResult(RESULT_CANCELED);
		
		setContentView(R.layout.configure);
		
		// AppWidget IDを取得する
		Intent intent = getIntent();
		Bundle extras = intent.getExtras();
		if (extras != null) {
			mAppWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID, AppWidgetManager.INVALID_APPWIDGET_ID);
			if (mAppWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
				// AppWidget IDが不正
				Log.v("TEST", "AppWidgetExampleConfigure#onCreate():mAppWidgetId=" + mAppWidgetId + "(INVALID_APPWIDGET_ID)");
				finish();
			} else {
				Log.v("TEST", "AppWidgetExampleConfigure#onCreate():mAppWidgetId=" + mAppWidgetId);
				setupConfigureViews();
			}
		} else {
			Log.v("TEST", "AppWidgetExampleConfigure#onCreate():no extras");
			finish();
		}
	}

	/**
	 * OKボタン押下時の処理
	 */
	@Override
	public void onClick(View v) {
		Log.v("TEST", "AppWidgetExampleConfigure#onClick():mAppWidgetId=" + mAppWidgetId);
		
		RemoteViews views = new RemoteViews(this.getPackageName(), R.layout.appwidget);
		
		// AppWidgetのボタンの設定
		Intent intent = new Intent(this, com.example.appwidgetexample.AppWidgetExampleConfigure.class);
		intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
		PendingIntent pendingIntent = PendingIntent.getActivity(this, mAppWidgetId, intent, 0);	// 第2引数が大事
		views.setOnClickPendingIntent(R.id.awButton1, pendingIntent);
		
		// エディットテキストのテキストでAppWidgetを更新する
		CharSequence text = editText1.getText();
		views.setTextViewText(R.id.awTextView1, text);
//		views.setCharSequence(R.id.awTextView1, "setTextKeepState", text);	// setXXX()のテスト
//		views.setInt(R.id.editText1, "setTextColor", 0xffff00);	// setXXX()のテスト。これを実行するとAppWidgetは表示されない
		AppWidgetManager awm = AppWidgetManager.getInstance(this);
		awm.updateAppWidget(mAppWidgetId , views);
		
		// RESULT_OKをセットする
		Intent resultValue = new Intent();
		resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, mAppWidgetId);
		setResult(RESULT_OK, resultValue);
		finish();
	}
	
	/**
	 * 設定画面のビューの設定をする
	 */
	private void setupConfigureViews() {
		// TODO プリファレンスかローカルファイルか何かから表示するテキストを取ってきてエディットテキストにセットする
		editText1 = (EditText)findViewById(R.id.editText1);
		
		Button button1 = (Button)findViewById(R.id.button1);
		button1.setOnClickListener(this);
	}
}

onCreate()の始めで結果にRESULT_CANCELEDを設定している部分はApiDemosのExampleAppWidgetConfigure.javaから持ってきたコードで、設定アクティビティが完了する前にバックキーを押されたときにAppWidgetホストにキャンセルされたという通知するためとリファレンスには書かれている。しかし、AVD上ではRESULT_CANCELEDを設定する/しないによってバックキーを押したときの見た目上の動きは変わらない(どちらでもAppWidgetは貼り付けられない)。

onClick()中のAppWidgetManager#getActivity()は、AppWidgetを2個貼り付けた場合に第2、第4引数の組み合わせによって動作が変わってくる。

  • (0,0)の場合、以下の3パターン。
    1. 1個目をAppWidgetを貼り付ける。
    2. 1個目のAppWidgetのボタンで更新をかける。->1個目のAppWidgetが更新される。
    3. 2個目のAppWidgetを貼り付ける。
    4. 2個目のAppWidgetのボタンで更新をかける。->1個目のAppWidgetが更新される。

    1. 1個目をAppWidgetを貼り付ける。
    2. 2個目のAppWidgetを貼り付ける。
    3. 2個目のAppWidgetのボタンで更新をかける。->どちらのAppWigetも更新されない。
    4. 1個目のAppWidgetのボタンで更新をかける。->どちらのAppWigetも更新されない。

    1. 1個目をAppWidgetを貼り付ける。
    2. 2個目のAppWidgetを貼り付ける。
    3. 1個目のAppWidgetのボタンで更新をかける。->どちらのAppWigetも更新されない。
    4. 2個目のAppWidgetのボタンで更新をかける。->どちらのAppWigetも更新されない。
  • (0,PendingIntent.FLAG_CANCEL_CURRENT)の場合、2個目のAppWidgetを貼り付けると1個目のAppWidgetのボタンが反応しなくなる。2個目のAppWidgetのボタンから更新をかけると2個目のAppWidgetが更新される。
  • (0,PendingIntent.FLAG_UPDATE_CURRENT)の場合、どちらの更新ボタンで更新をかけても、2個目のAppWidgetが更新される。
  • (mAppWidgetId,PendingIntent.FLAG_CANCEL_CURRENT),(mAppWidgetId,PendingIntent.FLAG_UPDATE_CURRENT),(mAppWidgetId,0)の組み合わせでは、ボタンを押したAppWidgetが更新された。

前記事にも書いたが、getActivity(),getBroadcast(),getService()の第2引数は使用されている。同じアプリのAppWidgetを複数貼り付ける可能性がある場合は第2引数にAppWidget IDをセットすると良いようだ。参考サイト3を参照。

onClick()の中でコメントアウトしているRemoteviews#setCharSequence()について。

android.widget.RemoteViewsクラス
public void setCharSequence(int viewId, String methodName, CharSequence value)
このsetCharSequence()をはじめRemoteViewsクラスのsetInt()、setDouble()、setBoolean()といったsetXXX()("XXX"は型名)というメソッドは、第1引数viewIdで指定したビューの第2引数methodName指定した名前のメソッドを、第3引数valueを引数として渡して呼び出すメソッドである。
つまり上記の例ではコメントアウトを外せば「TextViewのsetTextKeepState(text)を呼ぶ」ということになる。
ビューのメソッドにはこれらのsetXXX()で呼び出せるものと呼び出せないものがある。
例えば上記のTextView#setTextKeepState()はsetCharSequence()で使えるが、TextView#setText()は使えない。
RemoteViews#setTextViewText()があるので、わざわざTextView#setText()をsetCharSequence()経由で呼び出さなくても用が足りるからではないかと思う。つまり、setXXX()で使えないビューのメソッドは、setXXX()を使わなくても済むようなメソッドがRemoteViewsに用意されているメソッドではないかと推測している。参考サイト4を参照。

参考サイト:
1.f. アプリウィジェット - ソフトウェア技術ドキュメントを勝手に翻訳
2.Y.A.M の 雑記帳: Android AppWidget
3.Y.A.M の 雑記帳: Android AppWidget の PendingIntent で putExtra するときの注意
4.RemotableViewMethod - 横浜デ部

« Xperia rayにb-mobile Fair導入 | Main | 配列リテラル »

Androidアプリ開発」カテゴリの記事

Comments

Post a comment

(Not displayed with comment.)

TrackBack

TrackBack URL for this entry:
http://app.cocolog-nifty.com/t/trackback/26461/53205345

Listed below are links to weblogs that reference Androidアプリ開発メモ036:AppWidget その3:設定用Activity:

« Xperia rayにb-mobile Fair導入 | Main | 配列リテラル »

May 2017
Sun Mon Tue Wed Thu Fri Sat
  1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30 31      
無料ブログはココログ

日本blog村

  • にほんブログ村 IT技術ブログへ
  • にほんブログ村 アニメブログへ
  • にほんブログ村 サッカーブログ アルビレックス新潟へ

好きな音楽家

メモ

XI-Prof