具有配置活动的多个小部件

时间:2015-01-20 15:48:40

标签: android android-widget

问题:App小部件在添加时启动一些配置屏幕,然后在按下时,实现一些操作,同样基于配置屏幕上的信息输入。并允许窗口小部件的多个实例,每个实例都有自己的配置。 我在实现许多示例时遇到的错误:

  1. 单击小部件将始终将我带到配置活动
  2. 单击小部件将更新所有小部件
  3. 点击什么都不做
  4. 在Eclipse上添加另一个小部件/重新启动/重新启动项目之前,添加小部件不会更新小部件信息

1 个答案:

答案 0 :(得分:1)

我是这样做的。如果您正在复制示例 - 请记住更改包名称的所有实例(Eclipse将帮助您)。

可能有更简单/更好的方法来做到这一点,但我的工作和所有的信息。我把所有悲惨的评论都遗留在代码中,因为让这个工作变得很麻烦...据我所知 - 留下任何东西只会杀死我上面问题中列出的一个功能。 干杯, 尼尔

首先 - 清单:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ntasher.afcon"
 android:versionCode="1"
android:versionName="1.0" >

<uses-sdk
    android:minSdkVersion="19"
    android:targetSdkVersion="19" />

<application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme" >
    <activity
        android:name="com.ntasher.afcon.SettingsPage"
        android:label="@string/app_name"
        android:theme="@android:style/Theme.Dialog"
        android:configChanges="keyboardHidden|orientation">
        <intent-filter>
            <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
        </intent-filter>
    </activity>

    <!-- Broadcast Receiver that will process AppWidget Updates -->
    <receiver
        android:icon="@drawable/ic_launcher"
        android:name="com.ntasher.afcon.MyAppWidgetProvider"
        android:label="@string/app_name" >
        <intent-filter>
            <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
        </intent-filter>

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

</manifest>

现在 - 布局 - activity_main.xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="20dp"
tools:context=".MainActivity">



<TextView
    android:id="@+id/id_tv"
    android:paddingBottom="20dp"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_centerHorizontal="true"
    android:textStyle="bold"
    android:textSize="18dp"
    android:text="@string/hello_world" />

<EditText
    android:id="@+id/editText1"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_below="@+id/id_tv"
    android:ems="10" >

    <requestFocus />
</EditText>

<Button
    android:id="@+id/button1"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_below="@+id/editText1"
        android:textStyle="bold"
    android:text="Save" />

</RelativeLayout>

和widget_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/widget_root"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:background="@drawable/ic_launcher"
android:baselineAligned="false"
android:orientation="vertical" >

<TextView
    android:id="@+id/textView1"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="Widget Text"
    android:gravity="center"
    android:textAppearance="?android:attr/textAppearanceLarge" />

</LinearLayout>

widgetprovider.xml:

<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
android:minWidth="72dip"
android:minHeight="72dip"
android:updatePeriodMillis="100000"
android:configure="com.ntasher.afcon.SettingsPage"
android:initialLayout="@layout/widget_main"/> 

类:: SettingsPage.java(主要活动):

package com.ntasher.afcon;

import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.RemoteViews;
import android.widget.TextView;
import android.widget.Toast;

public class SettingsPage extends Activity {

int thisWidgetId = AppWidgetManager.INVALID_APPWIDGET_ID;
public static String ACTION_WIDGET_CONFIGURE = "WIDGET_CONFIGURED";
public static String ACTION_WIDGET_UPDATE = "WIDGET_UPDATED";
SharedPreferences customSharedPreference;
EditText ed = null;
Button save = null;
TextView widgetId = null;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    ed = (EditText) findViewById(R.id.editText1);
    save = (Button) findViewById(R.id.button1);
    widgetId = (TextView) findViewById(R.id.id_tv);

    save.setOnClickListener(new OnClickListener() {
        @Override
        public void onClick(View arg0) {
            //updateWidget();
            if (ed.getText().toString().trim().length() > 0) {
                saveToPreferences("Widget" + thisWidgetId, ed.getText()
                        .toString().trim());

                updateWidget(thisWidgetId);

                setResultDataToWidget(RESULT_OK);
            } else
                setResultDataToWidget(RESULT_CANCELED);
        }
    });

    getIdOfCurrentWidget(savedInstanceState);

}

/** Get the Id of Current Widget from the intent of the Widget **/
void getIdOfCurrentWidget(Bundle savedInstanceState) {

    setResult(RESULT_CANCELED);

    Bundle extras = getIntent().getExtras();

    if (extras != null) {
        thisWidgetId = extras.getInt(AppWidgetManager.EXTRA_APPWIDGET_ID,
                AppWidgetManager.INVALID_APPWIDGET_ID);
        if (getWidgetData("Widget" + thisWidgetId) != null) {
            save.setText("Update");
            ed.append(getWidgetData("Widget" + thisWidgetId));
        }

        widgetId.setText("Widget ID = " + thisWidgetId);
    }

    // If they gave us an intent without the widget id, just bail.
    if (thisWidgetId == AppWidgetManager.INVALID_APPWIDGET_ID) {
        finish();
    }

}

/**
 * Update the Current Widget - This is very important to ensure the widget
 * is enabled
 **/
void updateWidget(int thisWidgetId) {
    //Intent clickIntent=new Intent();
    /*Intent clickIntent = getIntent();
    //clickIntent.setClass(getBaseContext(), MyAppWidgetProvider.class);
    clickIntent.setAction(ACTION_WIDGET_UPDATE);
    remoteViews.setTextViewText(R.id.textView1, ed.getText().toString()
            .trim());
    clickIntent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, thisWidgetId);
    //PendingIntent pendingIntent = PendingIntent.getActivity(this,
      //      0, clickIntent, 0);
    PendingIntent pendingIntent = PendingIntent.getActivity(this,
            thisWidgetId, clickIntent, 0);
    remoteViews.setOnClickPendingIntent(R.id.widget_root, pendingIntent);
    // update this widget
    appWidgetManager.updateAppWidget(thisWidgetId, remoteViews);*/
    Intent updateIntent=new Intent(this, MyAppWidgetProvider.class);
    updateIntent.setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE);
    updateIntent.setData(Uri.withAppendedPath(Uri.parse("abcdef" + "://widget/id/"), String.valueOf(thisWidgetId)));
    //updateIntent.setClass(getBaseContext(), MyAppWidgetProvider.class);
    updateIntent.putExtra("ID",thisWidgetId);
    sendBroadcast(updateIntent);
    Toast.makeText(this,"upd Widget", 
            Toast.LENGTH_SHORT).show();


}

void setResultDataToWidget(int result) {
    Intent resultValue = new Intent();
    resultValue.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, thisWidgetId);
    setResult(result, resultValue);
    finish();
}

@SuppressLint("WorldWriteableFiles")
public void saveToPreferences(String file_name, String data) {
    @SuppressWarnings("deprecation")
    SharedPreferences myPrefs = getSharedPreferences("Data",
            MODE_WORLD_WRITEABLE);
    SharedPreferences.Editor prefsEditor = myPrefs.edit();
    prefsEditor.putString(file_name, data);
    prefsEditor.commit();
}

@SuppressLint("WorldReadableFiles")
@SuppressWarnings("deprecation")
public String getWidgetData(String file_name) {
    SharedPreferences myPrefs = getSharedPreferences("Data",
            MODE_WORLD_READABLE);
    return (myPrefs.getString(file_name, null));
}

}

最后是MyAppWidgetPRovider.java

package com.ntasher.afcon;

import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.Uri;
import android.util.Log;
import android.widget.RemoteViews;
import android.widget.Toast;

public class MyAppWidgetProvider extends AppWidgetProvider {

@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager,
        int[] appWidgetIds) {
Log.i("onUpdate", "AAA");
Toast.makeText(context,"OnUpdate", 
        Toast.LENGTH_SHORT).show();
ComponentName thisWidget = new ComponentName(context,
        MyAppWidgetProvider.class);
int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);
    for (int widgetId : allWidgetIds) {

        RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
          R.layout.widget_main);
      // Set the text - from saved sharedpreferences
     String widgetText=getWidgetData(context,"Widget" + widgetId);  
      remoteViews.setTextViewText(R.id.textView1, widgetText+String.valueOf(widgetId));

      // Register an onClickListener
      Intent intent = new Intent(context, MyAppWidgetProvider.class);

//*****THE FOLLOWING IS A MUST!!!
//if no intent.setData to something very specific, the intents for each     widget are UNIFIED into one intent and
//this intent will be the original intent with no ID at all
//************************************
      intent.setData(Uri.withAppendedPath(Uri.parse("abc" + "://widget/id/"), String.valueOf(widgetId)));
//************************************

      intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, appWidgetIds); //<<<<CHECK IF NEEDED
      intent.putExtra("ID",widgetId);// <<this is used by the onReceive to identify the widget pressed

      PendingIntent pendingIntent = PendingIntent.getBroadcast(context,
          0, intent, 0);

      remoteViews.setOnClickPendingIntent(R.id.widget_root, pendingIntent);
      appWidgetManager.updateAppWidget(widgetId, remoteViews);
    }


    super.onUpdate(context, appWidgetManager, appWidgetIds);

}

/*
 * This is called when an instance the App Widget is created for the first
 * time.
 */
@Override
public void onEnabled(Context context) {
    super.onEnabled(context);
    Log.i("onEnabled", "AAA");

}

/*
 * This is called for every broadcast and before each of the above callback
 * methods.
 */
@Override
public void onReceive(Context context, Intent intent) {
    int thisWidgetId=intent.getIntExtra("ID", -1);
    String widgetText=getWidgetData(context,"Widget" + thisWidgetId);
        Toast.makeText(context,"onReceive:"+Integer.toString(thisWidgetId)+widgetText, 
            Toast.LENGTH_SHORT).show();

/*the following is required for showing the right name when adding the widget otherwise the name will be null*/
    ComponentName thisWidget = new ComponentName(context, MyAppWidgetProvider.class);
    AppWidgetManager appWidgetManager= AppWidgetManager.getInstance(context);
    int[] allWidgetIds = appWidgetManager.getAppWidgetIds(thisWidget);

        for (int widgetId : allWidgetIds) {
            if (widgetId==thisWidgetId)
            {
                RemoteViews remoteViews = new RemoteViews(context.getPackageName(),
                      R.layout.widget_main);
                remoteViews.setTextViewText(R.id.textView1, widgetText+String.valueOf(thisWidgetId));
                appWidgetManager.updateAppWidget(thisWidgetId, remoteViews);

            }
        }
    super.onReceive(context, intent);
    Log.i("onReceive", "AAA");

}

/*
 * This is called When all instances of App Widget is deleted from the App
 * Widget host.
 */
@Override
public void onDisabled(Context context) {
    // Unschedule any timers and tasks
    super.onDisabled(context);
}

/*
 * This is called every time an App Widget is deleted from the App Widget
 * host.
 */
@Override
public void onDeleted(Context context, int[] appWidgetIds) {
    // Unschedule any timers and tasks
    super.onDeleted(context, appWidgetIds);
}
public String getWidgetData(Context context, String file_name) {
    @SuppressWarnings("deprecation")
    SharedPreferences myPrefs = context.getSharedPreferences("Data",Context.MODE_WORLD_READABLE);
    return (myPrefs.getString(file_name, null));
}


}