在 AppWidgetProvider 中执行 UnregisterReceiver() 时出错

Posted

技术标签:

【中文标题】在 AppWidgetProvider 中执行 UnregisterReceiver() 时出错【英文标题】:Error when executing UnregisterReceiver() in AppWidgetProvider 【发布时间】:2018-12-06 01:51:05 【问题描述】:

在我的应用程序中,我正在注册一个广播接收器,如果在小部件更新时没有网络连接,它会监听连接变化,并且如果在更新时有互联网连接,我想取消注册它。我正在努力解决的问题是让相同的接收器实例取消注册它,因为当应用程序更新时,会构建一个新的 appwidgetprovide 实例,所以我没有对该实例的引用。我尝试将其存储在 SharedPreferences 中,但这给了我一个错误:接收器未注册。

    public void decideBroadcastState(Context context)
    // get the network receiver from shared preferences
    preferencesReceiver = Preferences.getSavedObjectFromPreference(context, Constants.SHARED_BROADCAST, this.getBroadcastKey(), NetworkReceiver.class);
    // If there is an internet connection, turn off the broadcast
    if(isInternetConnection)
        // stop listening for a connectivity change
        // If a broadcast was registered, cancel it.
        if(preferencesReceiver != null)
            context.unregisterReceiver(preferencesReceiver);
            Preferences.deleteCurrencyPref(context, Constants.SHARED_BROADCAST, this.getBroadcastKey());
        

    // If there's no internet connection, create a new broadcast
    else
        // Create an intent that will look for a network connection, and will update the
        // widgets, once there is one.

        // if it doesn't exist, create one.
        if(preferencesReceiver == null)
            final String connectivityChange = "android.net.conn.CONNECTIVITY_CHANGE";
            IntentFilter intentFilter = new IntentFilter(connectivityChange);
            // register it
            // mReceiver is a new instance of the broadcast
            context.getApplicationContext()
                    .registerReceiver(mReceiver, intentFilter);
            // Store it in preferences
            Preferences.saveCurrencyPref(context, Constants.SHARED_BROADCAST, this.getBroadcastKey(), mReceiver);
        
    


这是我的 Preferences 类:

public class Preferences 

// Write the prefix to the SharedPreferences object for this widget.
public static void saveCurrencyPref(Context context, String filePlace, String preferenceKey, Object anObject) 

    SharedPreferences sharedPref = context.getSharedPreferences(filePlace, Context.MODE_PRIVATE);
    SharedPreferences.Editor editor = sharedPref.edit();

    Gson gson = new Gson();
    String json = gson.toJson(anObject);
    editor.putString(preferenceKey, json);
    editor.apply();



// Read the prefix from the SharedPreferences object for this widget.
public static <NetworkReceiver> NetworkReceiver  getSavedObjectFromPreference(Context context, String filePlace, String preferenceKey, Class<NetworkReceiver> classType) 
    SharedPreferences sharedPreferences = context.getSharedPreferences(filePlace, Context.MODE_PRIVATE);
    if (sharedPreferences.contains(preferenceKey)) 
        final Gson gson = new Gson();
        String json = sharedPreferences.getString(preferenceKey, "");
        NetworkReceiver obj = gson.fromJson(json, classType);
        return obj;
    
    return null;




static void deleteCurrencyPref(Context context, String filePlace, String preferenceKey) 
    SharedPreferences sharedPref = context.getSharedPreferences(filePlace, Context.MODE_PRIVATE);
    SharedPreferences.Editor editor = sharedPref.edit();
    editor.remove(preferenceKey);
    editor.apply();

【问题讨论】:

【参考方案1】:

当使用GSONSharedPreferences 中存储和检索对象时,您正在序列化和反序列化该对象。这样做不会为您提供相同的对象实例,而是为您提供具有相同值的对象副本。如果您想了解更多有关其工作原理的信息,请搜索序列化和 Java 堆。

您应该能够将BroadcastReceiver 存储在appWidgetProvider 的静态字段中。我不知道你到底在做什么,但你不应该需要超过 1 个 BroadcastReceiver 实例。

【讨论】:

【参考方案2】:

首先,AppWidgetProvider 是一个非常强大的 BroadcastReceiver,因此他的生命周期与 BroadcastReceiver 相同。 BroadcastReceiver 主要存活 15 秒(如果你不使用 goAsync()),在主线程上完成他的工作,然后死掉(所以你的进程也会死掉)。因此,在 AppWidgetProvider 中注册一个动态 BroadcastReceiver 并不是最好的主意,因此 Android 为您提供了使用 Service(带有 Android O 通知的前台服务)来注册您的动态接收器并监听某种事件。

【讨论】:

以上是关于在 AppWidgetProvider 中执行 UnregisterReceiver() 时出错的主要内容,如果未能解决你的问题,请参考以下文章

使用匕首 2 在 Kotlin 中的 AppWidgetProvider 中的字段注入

桌面小部件AppWidgetProvider简单分析

扩展 AppWidgetProvider 的 Widget 中是不是可以使用 TextView Marquee?

AppWidgetProvider - 每次对任何 AppWidget 文件进行更改时都会触发 onUpdate 吗?

在不同的包名称下移动 AppWidgetProvider 会破坏活动的小部件

AppWidgetProvider 中的 super.onUpdate() 推荐?