【问题标题】:Check Widget is Placed on Android Screen检查小部件是否放置在 Android 屏幕上
【发布时间】:2012-01-12 14:31:14
【问题描述】:

谁能告诉我如何检查我的小部件是否已放置在主屏幕上?

我的应用中有一些代码只有在小部件放在主屏幕上时才应该运行。

【问题讨论】:

  • 您好,您看我的回答了吗?我认为这可能会有所帮助.. ;-)

标签: android widget homescreen


【解决方案1】:

只是说,但是...

    int ids[] = AppWidgetManager.getInstance(this).getAppWidgetIds(new ComponentName(this,MyAppWidgetProvider.class));

    Toast.makeText(this, "Number of widgets: "+ids.length, Toast.LENGTH_LONG).show();

【讨论】:

  • 这是正确的答案:查询 AppWidgetManager 并获取 id 是检查主屏幕中是否以及有多少小部件的正确方法。
  • 我也可以确认这是正确的答案。不要浪费时间关注 larsona1 的回答并最终维护脆弱的代码。
  • 唯一的问题是,有时即使没有显示任何小部件,它也会返回多个 id
  • 投了赞成票,但是...如果您从屏幕上删除小部件getAppWidgetIds() 仍然返回值
  • 如果使用小部件配置活动,您可以重现我的情况,如果您在没有创建小部件的情况下完成它,它无论如何都会在AppWidgetProvider 中调用onUpdate
【解决方案2】:

您需要自己存储这些信息。我通常使用应用程序首选项,但你可以使用任何东西。通常小部件使用服务进行通信,因此您的代码可能在服务中,但使用首选项允许您的应用程序的任何部分访问它。

在扩展 AppWidgetProvider 的小部件类中,当小部件放在主屏幕上时会调用 onEnabled,而(通常)在移除时调用 onDeleted。删除所有副本时调用 onDisabled。

所以在你的小部件提供者的代码中:

@Override
public void onEnabled(Context context) {
    super.onEnabled(context);
    setWidgetActive(true);
    context.startService(new Intent(appContext, WidgetUpdateService.class));
}

@Override
public void onDisabled(Context context) {
    Context appContext = context.getApplicationContext();
    setWidgetActive(false);
    context.stopService(new Intent(appContext, WidgetUpdateService.class));
    super.onDisabled(context);
}

private void setWidgetActive(boolean active){
    Context appContext = context.getApplicationContext();
    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(appContext);
    SharedPreferences.Editor edit = prefs.edit();
    edit.putBoolean(Constants.WIDGET_ACTIVE, active);
    edit.commit();
}

在代码的其他地方,您可以通过以下方式检查小部件是否处于活动状态:

public boolean isWidgetActive(Context context){
    Context appContext = context.getApplicationContext();
    SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
    return prefs.getBoolean(Constants.WIDGET_ACTIVE, false);
}

【讨论】:

  • 太好了!谢谢,没有想到onDisabled(),它只会在您从应用程序的主屏幕中删除所有小部件时运行,这正是我所需要的。我正在使用:onDeleted(),每次删除小部件时都会运行女巫。
  • 有些情况上面没有涵盖,我正在寻找解决方案:(1)用户清除共享首选项 - 有小部件,但你不知道它(2)用户在“添加小部件”和按“确定”之间感到遗憾 - 但是调用了启用,没有小部件
  • 请看下面的答案;-)
  • 在某些情况下将此标志存储在数据库或 SharedPreferences 中是很好的,当您想知道用户是否曾经使用或激活(不是当前)应用程序的小部件功能时。 (我知道这不是 SO 问题的直接答案)
【解决方案3】:

我知道这是一个老问题,但今天看到这个问题,我发现@larsona1 接受的答案存在一些问题:

  1. 如果用户清除了共享首选项 - 仍然有小部件,但应用不会知道它。
  2. 如果用户在“添加小部件”之间和按下“确定”之前感到遗憾 - 无论如何都会调用 onEnabled,并且即使没有小部件,小部件也会在主屏幕中注册,并且以后无法将其删除。 (这可能是 ADT 主页启动器中的错误)。

我找到了第一个问题的解决方案。 根本不需要共享偏好,因为无论如何它都是不可靠的。必须在运行时检查。

// in some class you define a static variable, say in S.java
static boolean sWidgetMayExist = true;

在您的小部件提供程序中:

// MyAppWidgetProvider.java
// to respond to runtime changes, when widgets are added and removed
@Override
public void onEnabled(Context context) {
    super.onEnabled(context);
    S.sWidgetMayExist = true;
}

@Override
public void onDisabled(Context context) {
    super.onDisabled(context);
    S.sWidgetMayExist = true;
}

并且,在您的服务代码中添加:

AppWidgetManager manager = null;
RemoteViews views = null;
ComponentName widgetComponent = null;

    // ..and in your update thread

    if (!S.sWidgetMayExist) { return; }

if (manager == null || widgetComponent == null) {
    widgetComponent = new ComponentName(c,
            MyAppWidgetProvider.class);
    manager = AppWidgetManager.getInstance(c);
}

if (manager.getAppWidgetIds(widgetComponent) == null) {
    S.sWidgetMayExist = false;
}

【讨论】:

  • 根据此页面 [1] 问题 2 似乎是 Android 2.1 及更高版本修复的错误。我使用 Android 4.1.2 对其进行了测试,并且正确调用了 onDelete 和 onDisabled 方法。 [1]groups.google.com/forum/?fromgroups=#!topic/android-developers/…
  • 查看 Waza_Be 的答案,似乎可以工作并且需要更少的代码。
  • @WilliamT.Mallard 我的答案比 Waza 的大 6 个月。所以我在回答的时候没有检查它。但现在回顾一下,我不确定它是否涵盖了我所指的边缘情况。
【解决方案4】:

@Waza_Be 是正确的,因为查看“AppWidgetIds”列表以了解活动小部件(安装在主屏幕上的小部件)的数量是了解此信息的正确方法。

但是,请记住,您不必自己看这个。

查看官方 Android 文档以了解有关小部件的最佳实践: https://developer.android.com/guide/topics/appwidgets/index.html#AppWidgetProvider

正确的方法是仅覆盖 onUpdate() 方法并遍历“活动”小部件列表:

public class ExampleAppWidgetProvider extends AppWidgetProvider {

    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        final int N = appWidgetIds.length;

        // Perform this loop procedure for each App Widget that belongs to this provider
        for (int i=0; i<N; i++) {
            int appWidgetId = appWidgetIds[i];

            // Create an Intent to launch ExampleActivity
            Intent intent = new Intent(context, ExampleActivity.class);
            PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, 0);

            // Get the layout for the App Widget and attach an on-click listener
            // to the button
            RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.appwidget_provider_layout);
            views.setOnClickPendingIntent(R.id.button, pendingIntent);

            // Tell the AppWidgetManager to perform an update on the current app widget
            appWidgetManager.updateAppWidget(appWidgetId, views);
        }
    }
}

由于您自己的小部件提供程序会覆盖 AppWidgetProvider,因此如果您在主屏幕上没有活动小部件,您将不会进入 onUpdate() 方法!

查看已经为您检查“appWidgetIds.length > 0”的 Android AppWidgetProvider 的 onReceive() 代码:

public void onReceive(Context context, Intent intent) {
    // Protect against rogue update broadcasts (not really a security issue,
    // just filter bad broacasts out so subclasses are less likely to crash).
    String action = intent.getAction();
    if (AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)) {
        Bundle extras = intent.getExtras();
        if (extras != null) {
            int[] appWidgetIds = extras.getIntArray(AppWidgetManager.EXTRA_APPWIDGET_IDS);
            if (appWidgetIds != null && appWidgetIds.length > 0) {
                this.onUpdate(context, AppWidgetManager.getInstance(context), appWidgetIds);
            }
        }
    }

(...)
}

【讨论】:

    【解决方案5】:

    下面的呢:

    boolean widgetExists(Context context, int appWidgetId) {
        AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
        AppWidgetProviderInfo info = appWidgetManager.getAppWidgetInfo(appWidgetId);
        return (info != null);
    }
    

    来自the docsappWidgetManager.getAppWidgetInfo()

    如果 appWidgetId 尚未绑定到提供程序,或者您无权访问该 appWidgetId,则返回 null。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-06-23
      • 2023-03-26
      • 1970-01-01
      • 1970-01-01
      • 2021-09-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多