AppWidgetHost 不更新小部件

Posted

技术标签:

【中文标题】AppWidgetHost 不更新小部件【英文标题】:AppWidgetHost not updating widgets 【发布时间】:2014-05-14 15:46:08 【问题描述】:

我可以在Fragment 中使用AppWidgetHost 吗?我无法将大多数小部件添加到我的 AppWidgetHost 以进行更新。这是我的场景..

LauncherActivity.java

非常简单,只需调用带有布局的 setContentView 即可。

ma​​in.xml

包含几个片段,其中一个包含 AppWidgetHost。

CodeRedWidgetHostFragment.java

onCreateView 创建 AppWidgetHost 和 AppWidgetManager 的实例 使用我存储在首选项中的小部件 ID 创建和设置我的主机视图

onStart() appWidgetHost.startListening()

onStop() appWidgetHost.stopListening()

当我获得 AppWidgetHost 和 AppWidgetManager 的实例时,我正在使用 getActivity() 来获取 Fragments 托管活动。我想知道这是否是我的小部件没有更新的原因?

某些小部件实际上会更新,例如模拟时钟,但是,Youtube 小部件不会自动循环播放视频缩略图。

我应该提到,我在另一个活动中选择了我想要在我的 AppWidgetHost 中的小部件,该活动将所选小部件的 id 存储在 SharedPreferences 中。

这是我的 Fragment 类的代码。

package com.brockoli.android.codered.widgethost;

import android.app.Fragment;
import android.appwidget.AppWidgetHost;
import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import com.brockoli.android.codered.R;

public class CodeRedWidgetHostFragment extends Fragment 
private static final String TAG = CodeRedWidgetHostFragment.class.getSimpleName();

public static final String CODERED_WIDGET_ID = "CODERED_WIDGET_ID";

private SharedPreferences mSharedPrefsWidgets;

AppWidgetManager mAppWidgetManager;
AppWidgetHost mAppWidgetHost;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) 
    View parentView = inflater.inflate(R.layout.widget_host, null);

    mSharedPrefsWidgets = getActivity().getSharedPreferences("codered_widgets", 0);

    mAppWidgetManager = AppWidgetManager.getInstance(getActivity());
    mAppWidgetHost = new AppWidgetHost(getActivity(), R.id.APPWIDGET_HOST_ID);

    createWidget(parentView);

    return parentView;


@Override
public void onStart() 
    super.onStart();
    mAppWidgetHost.startListening();


@Override
public void onStop() 
    super.onStop();
    mAppWidgetHost.stopListening();



@Override
public void onResume() 
    super.onResume();
    createWidget(getView());


/**
 * Creates the widget and adds to our view layout.
 */
public void createWidget(View v) 
    if (v != null) 
        // Remove any existing widgets from the widget host
        ((ViewGroup) v).removeAllViews();
        int appWidgetId = mSharedPrefsWidgets.getInt(CODERED_WIDGET_ID, -1);
        if (appWidgetId > -1) 
            AppWidgetProviderInfo appWidgetInfo = mAppWidgetManager.getAppWidgetInfo(appWidgetId);
            AppWidgetHostView hostView = mAppWidgetHost.createView(getActivity(), appWidgetId, appWidgetInfo);
            hostView.setAppWidget(appWidgetId, appWidgetInfo);
            ((ViewGroup) v).addView(hostView);
            Log.i(TAG, "The widget size is: " + appWidgetInfo.minWidth + "*" + appWidgetInfo.minHeight);
           
    


【问题讨论】:

我刚刚尝试从link 运行 WidgetHostExample 代码,发现它也没有更新小部件。所以,更多信息。我在 Jynxbox M6 Android 电视盒上运行它。操作系统 4.1.2 也许有人可以指出一些实现 AppWidgetHost 并实际更新小部件的开源代码?我尝试了几个项目,这些项目是如何使用 AppWidgetHost 的示例,但它们都有相同的行为,即不更新附加的小部件。 【参考方案1】:

基于 Clemens 的回答,AppWidgetHost 应该在应用程序的整个生命周期中都处于活动状态。这意味着无论 Activity 是什么,您都应该在您的应用可以轻松访问的地方拥有 AppWidgetHost 和 AppWidgetManager 的实例。

public class YourApp extends Application 

    private static final int HARDCODED_ID = 0; 

    private static AppWidgetHost appWidgetHost;
    private static AppWidgetManager appWidgetManager;

    @Override
    public void onCreate() 
        super.onCreate();

        appWidgetManager = AppWidgetManager.getInstance(getApplicationContext());
        appWidgetHost = new AppWidgetHost(getApplicationContext(), HARDCODED_ID);
        appWidgetHost.startListening();
    

    @Override
    public void onTerminate() 
        super.onTerminate();

        appWidgetHost.stopListening();
        appWidgetHost = null;
    

    public static AppWidgetHost getAppWidgetHost()  return appWidgetHost; 

    public static AppWidgetManager getAppWidgetManager()  return appWidgetManager; 


我当前的实现已正确更新。测试了许多需要“实时”更新的应用程序,比如我的音乐播放器小部件。

请记住,应用程序上下文用于确保 AppWidgetHost 和 AppWidgetManager 的上下文始终可用。

另外,在其小部件中使用 AppCompat 库的较新小部件目前在 com.android.support:appcompat-v7:23.1.1 依赖项中存在错误。为了避免在调用以下内容时使用应用程序上下文。

AppWidgetHostView hostView = YourApp.getAppWidgetHost()
            .createView(context.getApplicationContexxt(), appWidgetId, info);

【讨论】:

【参考方案2】:

如果您的某些小部件确实更新了,我相信您的 getActivity() 可能是问题所在。

尝试在您的片段中创建一个引用,例如:

private Activity activity;

并在你的 onAttach() 中设置它

@Override
public void onAttach(Activity activity) 
    super.onAttach(activity);
    this.activity = activity; 

这样,它应该始终指向您当前的托管活动。

【讨论】:

似乎没有帮助。我这样做并更新了所有 getActivity() 调用以使用我的参考,但大多数小部件仍未更新。我什至不知道如何调试这个问题。时钟小部件更新很奇怪,但几乎没有其他小部件更新。【参考方案3】:

我找到了问题的原因,对于将来会卡住的人,这里是解释:

AppwidgetManager 实际上是一个系统服务,调用 AppwidgetManger.getInstance(Context context) 时不会得到新的实例,而是对单个实例的引用,这在其他任何地方都是相同的(跨活动、服务..)。

AppwidgetManger 来源:

public static AppWidgetManager getInstance(Context context) 
     return (AppWidgetManager) context.getSystemService(Context.APPWIDGET_SERVICE);
 

所以对我来说,我的问题是我有两个活动,每个活动都引用 AppwidgetManager,根据文档,他们在 onStart() 中调用 AppwidgetManger.startListening(),在 onStop() 中调用 onStopListening()。

但是当我切换到第二个活动时,这是造成错误的原因:

Activity1:onPause() Activity2:onCreate() Activity2:onStart() startListening() Activity1:onStop() stopListening() Activity1:onDestroy() Activity2:onResume()

所以活动 2 正确调用了 startListening(),但在后台,活动 1 仍然处于活动状态并调用 stopListening() 到同一个 AppwidgetManager 实例。

此外,你应该改变这个

mAppWidgetHost = new AppWidgetHost(getActivity(), R.id.APPWIDGET_HOST_ID);

mAppWidgetHost = new AppWidgetHost(getActivity().getApplicationContext(), R.id.APPWIDGET_HOST_ID);

它将阻止系统继续引用您的活动并使其远离 GC(传递活动会造成内存泄漏)

【讨论】:

【参考方案4】:

我遇到了同样的问题,但我还没有解决(目前),但似乎是AppWidgetHost 的问题。在我的情况下,我让它工作的唯一方法是禁用stopListening() 或在AppWidgetHost 的新实例中重新创建AppWidgetHostViews... 在您的情况下,在onStart()(甚至onResume())中重新创建mAppWidgetHost 可能会有所帮助......

【讨论】:

【参考方案5】:

由于您正在编写启动器,我建议您查看official Android Launcher。 与文档相比,它使用以下机制:

@Override
protected void onCreate(final Bundle savedInstanceState) 
    super.onCreate();
    // ...
    appWidgetManager = AppWidgetManager.getInstance(this);
    appWidgetHost = new AppWidgetHost(this, HOST_WIDGET_ID);
    appWidgetHost.startListening();


@Override
protected void onDestroy() 
    super.onDestroy();
    // ...
    appWidgetHost.stopListening();
    appWidgetHost = null;

请务必在您的代码中删除所有其他 stopListeningstartListening 实例。

【讨论】:

【参考方案6】:

您应该在拨打mAppWidgetHost.stopListening() 之后从parentView 拨打ViewGroup.removeAllViews()

【讨论】:

以上是关于AppWidgetHost 不更新小部件的主要内容,如果未能解决你的问题,请参考以下文章

主屏幕小部件文本视图未更新

通过 AppWidgetManager 更新我自己的小部件时,电源控制小部件显示一小会儿,这是啥问题?

权限拒绝:getIntentSender()

Android 小部件不更新

当 Android 中的 Activity 内容更改时,小部件不更新

提供者不更新文本小部件