質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.36%

  • Java

    15108questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

  • Android

    6986questions

    Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。

AndroidウィジェットでListViewのButtonのイベントを取得したい

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 1,639

gorira1321

score 21

前提・実現したいこと

ウィジェットにListViewを配置し、1行毎に名前とボタンを表示するサンプルアプリを作っています。(イメージ参照)
ListViewの表示まで出来たのですが、rowのボタンをタップしてもイベントが取得できません。

イメージのBUTTON1とBUTTON2のタップイベントは取得できました。
SuzukiとSatoの横にあるボタンのイベント取得方法を教えて下さい
(将来的にはSuzukiのボタンをタップしたらSuzukiさんとtextviewを変えたい)
イメージ説明

該当のソースコード

AndroidManifest.xml(抜粋)
  <receiver android:name=".NewAppWidget">
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
                <action android:name="com.android.BUTTON1_CLICKED" />
                <action android:name="com.android.BUTTON2_CLICKED" />
                <action android:name="com.android.BUTTON3_CLICKED" />
            </intent-filter>

            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/new_app_widget_info"/>
        </receiver>

        <service android:name=".SampleWidgetService"
                 android:permission="android.permission.BIND_REMOTEVIEWS">
        </service>

NewAppWidget.class
public class NewAppWidget extends AppWidgetProvider {

    private static final String TAG = "NewAppWidget";

    public static final String btn1Filter = "com.android.BUTTON1_CLICKED";
    public static final String btn2Filter = "com.android.BUTTON2_CLICKED";
    public static final String btn3Filter = "com.android.BUTTON3_CLICKED";

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        super.onUpdate(context, appWidgetManager, appWidgetIds);

        Log.e(TAG, "[onUpdate]");

        for (int appWidgetId : appWidgetIds) {

            Intent remoteViewsFactoryIntent = new Intent(context, SampleWidgetService.class);
            RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.new_app_widget);
            rv.setRemoteAdapter(R.id.listView, remoteViewsFactoryIntent);

            // BUTTON1 このイベントは取得できました
            Intent btn1Intent = new Intent(NewAppWidget.btn1Filter);
            PendingIntent btn1Pending = PendingIntent.getBroadcast(context, 0, btn1Intent, 0);
            rv.setOnClickPendingIntent(R.id.btn1_id, btn1Pending);

            // BTUUON2 このイベントは取得できました
            Intent btn2Intent = new Intent(NewAppWidget.btn2Filter);
            PendingIntent btn2Pending = PendingIntent.getBroadcast(context, 0, btn2Intent, 0);
            rv.setOnClickPendingIntent(R.id.btn2_id, btn2Pending);



            appWidgetManager.updateAppWidget(appWidgetId, rv);
        }
    }

    @Override
    public void onReceive(Context ctx, Intent intent) {
        super.onReceive(ctx, intent);
        Log.e(TAG,"[action]" + intent.getAction());
    }

    @Override
    public void onEnabled(Context context) {
        super.onEnabled(context);
        Log.e(TAG, "[onEnabled]");
    }

    @Override
    public void onDisabled(Context context) {
        super.onDisabled(context);
        Log.e(TAG, "[onDisabled]");
    }
}

Person.class
public class Person {

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    private String name;
}

SampleWidgetService.class
public class SampleWidgetService extends RemoteViewsService {

    private static final String TAG = "SampleViewFactory";

    private List<Person> persons = new ArrayList<Person>();

    @Override
    public RemoteViewsFactory onGetViewFactory(Intent intent) {
        Log.e(TAG,"[onGetViewFactory]");
        return new SampleWidgetFactory();
    }

    private class SampleWidgetFactory implements RemoteViewsFactory {

        public void onCreate() {
            Log.e(TAG, "[onCreate]");

            if (persons.size() == 0) {
                Person p1 = new Person();
                p1.setName("Suzuki");
                persons.add(p1);

                Person p2 = new Person();
                p2.setName("Sato");
                persons.add(p2);
            }
        }

        public void onDataSetChanged() {
            Log.e(TAG, "[onDataSetChanged]");
        }

        public void onDestroy() {
            Log.e(TAG, "[onDestroy]");
        }

        public RemoteViews getViewAt(int position) {
            Log.e(TAG, "[getViewAt]: " + position);

            RemoteViews rv = null;

            Person p = persons.get(position);

            rv = new RemoteViews(getPackageName(), R.layout.listview_row);
            rv.setTextViewText(R.id.nameText, p.getName());

            // LISTBUTTONS
       // R.id.myButtonのイベントを取りたい。setOnClickPendingIntentしてもイベントがとれない
            Intent btn3Intent = new Intent(NewAppWidget.btn3Filter);
            PendingIntent btn3Pending = PendingIntent.getBroadcast(getApplicationContext(), 0, btn3Intent, 0);
            rv.setOnClickPendingIntent(R.id.myButton, btn3Pending);

            return rv;
        }

        public long getItemId(int position) {
            Log.e(TAG, "[getItemId]: " + position);

            return position;
        }

        public int getCount() {
            Log.e(TAG, "[getCount]");

            return persons.size();
        }

        public RemoteViews getLoadingView() {
            Log.e(TAG, "[getLoadingView]");

            return null;
        }

        public int getViewTypeCount() {
            Log.e(TAG, "[getViewTypeCount]");

            return 1;
        }

        public boolean hasStableIds() {
            Log.e(TAG, "[hasStableIds]");

            return true;
        }
    }
}

new_app_widget.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:orientation="vertical"
              android:padding="@dimen/widget_margin">

    <Button android:id="@+id/btn1_id"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="button1" />

    <Button android:id="@+id/btn2_id"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="button2" />

    <ListView
        android:id="@+id/listView"
        android:layout_width="fill_parent"
        android:layout_height="match_parent"/>

</LinearLayout>


listview_row.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
              android:orientation="horizontal"
              android:layout_width="match_parent"
              android:layout_height="match_parent">

    <TextView
        android:id="@+id/nameText"
        android:layout_weight="1"
        android:textSize="24sp"
        android:padding="16dp"
        android:text="名前"
        android:layout_width="0dp"
        android:layout_height="wrap_content"/>

    <Button
        android:id="@+id/myButton"
        android:layout_weight="1"
        android:textSize="24sp"
        android:text="ボタン"
        android:layout_width="0dp"
        android:layout_height="wrap_content"/>

</LinearLayout>

試したこと

以下のページを参考に作成しました

Androidでの簡易なWidget作り方 - Qiita
Y.A.M の 雑記帳: Android AppWidget
AppWidgetのクリックイベントを取得する - Androidプログラマへの道 ~ Moonlight 明日香 ~

補足情報(言語/FW/ツール等のバージョンなど)

AndroidStudio2.1

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

0

ウィジェットでListViewのボタン押下イベントを取得するにはいくつか処理が足りてません。

・NewAppWidgetクラスのonUpdate()にてRemoteViews.setPendingIntentTemplate()を使う
・SampleWidgetServiceクラスのgetViewAt()にてRemoteViews.setOnClickFillInIntent()を使う
・ListView内のボタン判別にはpositionを使う

詳細はAndroid Developerを見ていただければと
https://developer.android.com/reference/android/widget/RemoteViews.html

ソース修正してみました。
変更箇所(抜粋)をのっけておきます。

AndroidManifest.xml ※BUTTON3_CLICKEDの名前を変えただけ

<receiver android:name=".NewAppWidget">
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE"/>
                <action android:name="com.android.BUTTON1_CLICKED" />
                <action android:name="com.android.BUTTON2_CLICKED" />
                <action android:name="com.android.LIST_BUTTON_CLICKED" />
            </intent-filter>

            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/new_app_widget_info"/>
        </receiver>

NewAppWidget.class

public class NewAppWidget extends AppWidgetProvider {

    private static final String TAG = "NewAppWidget";

    public static final String btn1Filter = "com.android.BUTTON1_CLICKED";
    public static final String btn2Filter = "com.android.BUTTON2_CLICKED";
    public static final String listBtnFilter = "com.android.LIST_BUTTON_CLICKED";

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        super.onUpdate(context, appWidgetManager, appWidgetIds);

        Log.e(TAG, "[onUpdate]");

        for (int appWidgetId : appWidgetIds) {

            Intent remoteViewsFactoryIntent = new Intent(context, SampleWidgetService.class);
            RemoteViews rv = new RemoteViews(context.getPackageName(), R.layout.new_app_widget);
            rv.setRemoteAdapter(R.id.listView, remoteViewsFactoryIntent);

            // BUTTON1 このイベントは取得できました
            Intent btn1Intent = new Intent(NewAppWidget.btn1Filter);
            PendingIntent btn1Pending = PendingIntent.getBroadcast(context, 0, btn1Intent, 0);
            rv.setOnClickPendingIntent(R.id.btn1_id, btn1Pending);

            // BTUUON2 このイベントは取得できました
            Intent btn2Intent = new Intent(NewAppWidget.btn2Filter);
            PendingIntent btn2Pending = PendingIntent.getBroadcast(context, 0, btn2Intent, 0);
            rv.setOnClickPendingIntent(R.id.btn2_id, btn2Pending);

            // LIST BUTTON setPendingIntentTemplateを使う
            Intent listBtnIntent = new Intent(NewAppWidget.listBtnFilter);
            PendingIntent template = PendingIntent.getBroadcast(context, 0, listBtnIntent, 0);
            rv.setPendingIntentTemplate(R.id.listView, template);

            appWidgetManager.updateAppWidget(appWidgetId, rv);
        }
    }

    @Override
    public void onReceive(Context ctx, Intent intent) {
        super.onReceive(ctx, intent);
        Log.e(TAG,"[action]" + intent.getAction());

        // 押下したリストの位置を取得し表示
        int pos = intent.getIntExtra("ListPosition", -1);
        Log.e(TAG,"List Click pos"+ pos);
    }

SampleWidgetService.class

public class SampleWidgetService extends RemoteViewsService {

        public RemoteViews getViewAt(int position) {
            Log.e(TAG, "[getViewAt]: " + position);

            RemoteViews rv = null;

            Person p = persons.get(position);

            rv = new RemoteViews(getPackageName(), R.layout.listview_row);
            rv.setTextViewText(R.id.nameText, p.getName());

            // LISTBUTTONS
            // R.id.myButtonのイベントを取りたい。setOnClickPendingIntentしてもイベントがとれない
//            Intent btn3Intent = new Intent(NewAppWidget.btn3Filter);
//            PendingIntent btn3Pending = PendingIntent.getBroadcast(getApplicationContext(), 0, btn3Intent, 0);
//            rv.setOnClickPendingIntent(R.id.myButton, btn3Pending);

            // LISTのボタンイベントを取るにはsetOnClickPendingIntentではなくsetOnClickFillInIntentを使う
            Intent listBtnIntent = new Intent(NewAppWidget.listBtnFilter);
            listBtnIntent.putExtra("ListPosition", position); // リストの押下した位置を持っておく
            rv.setOnClickFillInIntent(R.id.myButton, listBtnIntent);

            return rv;
        }

実行結果

Suzuki ボタンを押下した場合
[action]com.android.LIST_BUTTON_CLICKED
List Click pos0

Sato ボタンを押下した場合
[action]com.android.LIST_BUTTON_CLICKED
List Click pos1

こんな感じでどうでしょうか。
あとはonReceiveでif文なりswitch文でposの値を見て押されたボタンに対応する処理を
行っていけばいいかと

ここを利用するのは初めてなので変なところあったらすいませんっ

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2016/05/24 12:17

    非常にわかりやすく足りない部分を教えていただきありがとうございました!
    おかげさまでListviewのbuttonのイベントを取ることが出来ました。

    キャンセル

同じタグがついた質問を見る

  • Java

    15108questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

  • Android

    6986questions

    Androidは、Google社が開発したスマートフォンやタブレットなど携帯端末向けのプラットフォームです。 カーネル・ミドルウェア・ユーザーインターフェイス・ウェブブラウザ・電話帳などのアプリケーションやソフトウェアをひとつにまとめて構成。 カーネル・ライブラリ・ランタイムはほとんどがC言語/C++、アプリケーションなどはJavaSEのサブセットとAndroid環境で書かれています。