WorkManager - 当我们同时使用默认初始化和自定义初始化时,是否应该移除默认初始化器?

30

我升级了 WorkManager 从 "2.2.0" 到 "2.3.0-rc01",现在出现了以下新错误:

当我导出 APK 时,会出现此错误。

C:\app: Error: Remove androidx.work.impl.WorkManagerInitializer from your AndroidManifest.xml when using on-demand initialization. [RemoveWorkManagerInitializer]

   Explanation for issues of type "RemoveWorkManagerInitializer":
   If an android.app.Application implements
   androidx.work.Configuration.Provider,
   the default androidx.work.impl.WorkManagerInitializer needs to be removed
   from the
   AndroidManifest.xml file.

我不确定为什么在2.2.0中没有出现这样的错误,因为“按需初始化”是自2.1.0以来引入的。

根据https://developer.android.com/topic/libraries/architecture/workmanager/advanced/custom-configuration#remove-default的说法

我不太确定是否应该在我的AndroidManifest.xml中包含以下内容。

<provider
    android:name="androidx.work.impl.WorkManagerInitializer"
    android:authorities="${applicationId}.workmanager-init"
    tools:node="remove" />

目前,以下是我的Application类。

MyApplication类


public class MyApplication extends MultiDexApplication implements Configuration.Provider {
    private static MyApplication me;

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

        me = this;
    }

    public static MyApplication instance() {
        return me;
    }

    @NonNull
    @Override
    public Configuration getWorkManagerConfiguration() {
        return new Configuration.Builder()
                .build();
    }
}

如何构建 WorkManager

public static WorkManager getWorkManager() {
    MyApplication myApplication = MyApplication.instance();
    if (myApplication == null) {
        // Very rare edge case. Not sure how it happens. But, it happens :)
        return WorkManager.getInstance();
    } else {
        return WorkManager.getInstance(myApplication);
    }
}
似乎在Application类为空时,“默认初始化”(WorkManager.getInstance())也有少数机会被执行。
我可以通过包含以下provider来轻松消除APK导出期间的错误。但是,这样做是否正确?
<provider
    android:name="androidx.work.impl.WorkManagerInitializer"
    android:authorities="${applicationId}.workmanager-init"
    tools:node="remove" />

1
在提供者标签内设置以下属性并再次检查。android:enabled="false",android:exported="false"。 - Radhey
你是从哪里调用了getWorkManager方法? - Sir Codesalot
似乎 tools:node="remove" 是正确的方法。我们的团队早就采用了文档中提到的方法,所以这并不是什么新鲜事。 - azizbekian
错误提示的措辞应该更具体,以便说明“删除”androidx.work.impl.WorkManagerInitializer的含义。我原本认为这意味着从我的清单中删除代码,但实际上您正在更新提供程序 - lasec0203
4个回答

21
如果在更新至WorkManager 2.6.0或更高版本后出现此错误,您需要在清单文件中使用以下代码片段:
<provider
    android:name="androidx.startup.InitializationProvider"
    android:authorities="${applicationId}.androidx-startup"
    android:exported="false"
    tools:node="merge">

    <meta-data
        android:name="androidx.work.WorkManagerInitializer"
        android:value="androidx.startup"
        tools:node="remove" />

</provider>

Koin和WorkManager文档都没有提到这一点,谢谢。 - Abed

11
我们在WorkManager 2.3.0-*版本中引入了此lint检查规则。我们试图通过这个Lint规则解决的问题是:如果您同时拥有WorkManagerInitializer ContentProviderApplication子类型实现Configuration.Provider(用于按需初始化)- ContentProvider将始终优先。

这可能会令人意外,特别是当您有其他Configuration时,由于ContentProvider始终使用默认配置,因此这些配置不会生效。

您真正需要做的就是删除默认提供程序。这样初始化将不再急切,而是按需进行。


7

如果要使用按需初始化,就必须删除默认的工作管理器初始化程序,就像您所做的那样。因此,请在您的清单中保留以下代码:

<provider
   android:name="androidx.work.impl.WorkManagerInitializer"
   android:authorities="${applicationId}.workmanager-init"
   tools:node="remove" />

上述文档清楚地表明,您不应该调用WorkManager.getInstance()(没有Context参数):

注意:如果在WorkManager初始化之前调用已弃用的无参数WorkManager.getInstance()方法,该方法会抛出异常。即使您没有自定义WorkManager,也应始终使用WorkManager.getInstance(Context)方法。

查看 androix/work 的更改日志后,您将发现在版本 2.3.0-beta02 中添加了一个新功能:

  • 新增了一个lint规则,确保在使用按需初始化时从AndroidManifest.xml中移除内容提供程序androidx.work.impl.WorkManagerInitializer。(aosp/1167007
由于Android团队添加了RemoveWorkManagerInitializerDetector, 您从版本2.2.0升级到2.3.0.rc1后出现此错误的原因是,在构建时会引发您在以下拉取请求中收到的异常。
现在让我们谈一下源代码,建议您将getWorkManager方法与应用程序直接绑定,如下所示:
import androidx.annotation.NonNull;
import androidx.work.Configuration;
import androidx.work.WorkManager;

public class App extends MultiDexApplication implements Configuration.Provider {
    private static App APP_INSTANCE;

    @Override
    public void onCreate() {
        super.onCreate();
        APP_INSTANCE = this;
    }

    public static App getInstance() {
        return APP_INSTANCE;
    }

    @NonNull
    @Override
    public Configuration getWorkManagerConfiguration() {
        return new Configuration.Builder()
                .build();
    }

    public static WorkManager getWorkManager() {
        return WorkManager.getInstance(APP_INSTANCE);
    }
}

每当您在应用程序源代码中需要时,只需调用App.getWorkManager()

如果有的话,您也可以对ContentProvider执行类似操作。

附注:有关Java或Kotlin的有趣的codelabs教程,请参见javakotlin


不错的例子。我明白你建议使用App.getWorkManager()。但是getWorkManagerConfiguration()呢?它什么时候被初始化或使用? - AJW

1

WorkManagerInitializer 用于为 WorkManager 提供上下文。这是因为内容提供程序在 Application 之前初始化(请参见 this question)。这就是为什么如果您进行自定义初始化,需要自己提供上下文的原因。因此,如果您使用自定义初始化,则不需要它。

如果您从 内容提供程序 调用 getWorkManager 方法,则应用程序实例将为 null。要解决此问题,只需通过在内容提供程序中调用 getContext 将上下文作为参数传递给该方法:

public static WorkManager getWorkManager(Context context) {
    return WorkManager.getInstance(context);
}

public class MyContentProvider extends ContentProvider {
    @Override
    public boolean onCreate() {
        WorkManager workManager = getWorkManager(getContext());
        ...
    }
    ...
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接