调用 notifyAppWidgetViewDataChanged 后,在 RemoteViewsFactory 中不调用 onDataSetChanged

Posted

技术标签:

【中文标题】调用 notifyAppWidgetViewDataChanged 后,在 RemoteViewsFactory 中不调用 onDataSetChanged【英文标题】:onDataSetChanged is not called in RemoteViewsFactory after notifyAppWidgetViewDataChanged is called 【发布时间】:2016-02-25 11:16:51 【问题描述】:

我正在尝试使用小部件实现 android 应用程序,但在 nexus 5 设备上发现了奇怪的行为(我有两个 - 一个带有棒棒糖,一个带有棉花糖)。如果我调用 AppWidgetManager.notifyAppWidgetViewDataChanged,小部件的 ListView 内容会在其他设备(Nexus 3、ASUS K010)上刷新,但在这两个设备上没有任何反应。找不到任何相关信息。

这是我的代码:MainActivity.java。

public class MainActivity extends AppCompatActivity 
    public static final String PREFS_TAG = "StringList";

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

        View v = findViewById(R.id.fill);
        v.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View v) 
                fillWidget();
            
        );

        v= findViewById(R.id.clear);
        v.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View v) 
                clearWidget();
            
        );
    

    private void fillWidget()
        SharedPreferences preferences = getSharedPreferences(WidgetRemoteService.class.getSimpleName(), Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = preferences.edit();
        Set<String> strings = new HashSet<>();
        strings.add("111111111111111");
        strings.add("222222222222222");
        strings.add("333333333333333");
        strings.add("444444444444444");
        strings.add("555555555555555");
        strings.add("666666666666666");
        strings.add("777777777777777");
        strings.add("888888888888888");
        strings.add("999999999999999");
        editor.putStringSet(PREFS_TAG, strings);
        editor.commit();
        AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this);
        ComponentName componentName = new ComponentName(getApplicationContext(),WidgetProvider.class);
        int[] appWidgetIds = appWidgetManager.getAppWidgetIds(componentName);
        appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIds, R.id.listView);
    

    private void clearWidget()
        SharedPreferences preferences = getSharedPreferences(WidgetRemoteService.class.getSimpleName(), Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = preferences.edit();
        editor.remove(PREFS_TAG);
        editor.commit();
        AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(this);
        ComponentName componentName = new ComponentName(getApplicationContext(),WidgetProvider.class);
        int[] appWidgetIds = appWidgetManager.getAppWidgetIds(componentName);
        appWidgetManager.notifyAppWidgetViewDataChanged(appWidgetIds, R.id.listView);
    

WidgetProvider.java

public class WidgetProvider extends AppWidgetProvider 
    private static final String TAG = WidgetProvider.class.getSimpleName();

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) 
        super.onUpdate(context, appWidgetManager, appWidgetIds);
        for (int appWidgetId : appWidgetIds) 
            appWidgetManager.updateAppWidget(appWidgetId,createRemoteViews(context, appWidgetId));
        
    

    public static RemoteViews createRemoteViews(Context context, int appWidgetId)
        Log.e(TAG, "Creating remote views");

        Intent intent = new Intent(context, WidgetRemoteService.class);
        // Add the app widget ID to the intent extras.
        Log.e(TAG, "Creating remote views for widget #"+appWidgetId);
        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);
        intent.setData(Uri.parse(intent.toUri(Intent.URI_INTENT_SCHEME)));

        RemoteViews result = new RemoteViews(WidgetProvider.class.getPackage().getName(),R.layout.widget_layout);
        result.setRemoteAdapter(R.id.listView,intent);
        return result;
    

WidgetRemoteService.java

public class WidgetRemoteService extends RemoteViewsService 
    private static final String TAG = WidgetRemoteService.class.getSimpleName();

    @Override
    public RemoteViewsFactory onGetViewFactory(Intent intent) 
        int appWidgetID = intent.getIntExtra(AppWidgetManager.EXTRA_APPWIDGET_ID,
                AppWidgetManager.INVALID_APPWIDGET_ID);
        return new WidgetViewsFactory(getApplicationContext(), appWidgetID);
    

    public static class WidgetViewsFactory implements RemoteViewsService.RemoteViewsFactory
        private Context context;
        private String[] strings;
        private int appWidgetId;

        public WidgetViewsFactory(Context context, int appWidgetId)
            Log.e(TAG, "Factory created");
            this.context = context;
            this.appWidgetId = appWidgetId;
        

        @Override
        public void onCreate() 

        

        @Override
        public void onDataSetChanged() 
            Log.e(TAG, "Dataset changed");
            SharedPreferences preferences = context.getSharedPreferences(WidgetRemoteService.class.getSimpleName(), Context.MODE_PRIVATE);
            Set<String> stringSet = preferences.getStringSet(MainActivity.PREFS_TAG, new HashSet<String>());
            strings = stringSet.toArray(new String[]);
        

        @Override
        public void onDestroy() 

        

        @Override
        public int getCount() 
            if (strings==null)
                return 0;
            else
                return strings.length;
        

        @Override
        public RemoteViews getViewAt(int position) 
            RemoteViews result = new RemoteViews(getClass().getPackage().getName(),R.layout.widget_item);
            result.setTextViewText(R.id.textTitle,"This is title");
            result.setTextViewText(R.id.textContent,strings[position]);
            return result;
        

        @Override
        public RemoteViews getLoadingView() 
            return null;
        

        @Override
        public int getViewTypeCount() 
            return 1;
        

        @Override
        public long getItemId(int position) 
            return 0;
        

        @Override
        public boolean hasStableIds() 
            return false;
        
    

在这里,我尝试从 MainActivity 更新小部件,但不知何故,它在我的 nexus 5 设备上不起作用 - 根据日志,onDataSetChanged() 永远不会在此设备上调用,但在其他设备上它可以工作。也许我误解了指南中的某些内容,并且它不应该工作,并且仅因为某些错误而在其他设备上工作,这些错误已在以后的 android 版本中修复?

【问题讨论】:

你找到解决办法了吗?? @Albert James Teddy 不幸的是,没有 【参考方案1】:

尝试添加

android:permission="android.permission.BIND_REMOTEVIEWS"

到你的AndroidManifest.xml中的RemoteViewsService,我今天也遇到了这个问题。

【讨论】:

【参考方案2】:

我设置了一个断点,想知道为什么 onDataSetChanged 没有被调用。事实证明它被调用了,但只有在我将应用程序后台化并且小部件可见之后!

【讨论】:

以上是关于调用 notifyAppWidgetViewDataChanged 后,在 RemoteViewsFactory 中不调用 onDataSetChanged的主要内容,如果未能解决你的问题,请参考以下文章

系统调用与函数调用

java三种调用方式(同步调用/回调/异步调用)

LINUX系统调用

引用调用 vs 复制调用调用

RPC 调用和 HTTP 调用的区别

js方法调用