Reputation: 31
In Android API
level, 26 (Oreo) and above I am getting this error. If I run dynamic feature from android studio direct to the device, the dynamic feature works fine, but when I upload app bundle on play store and try to run dynamic feature from the app which downloaded from play store I am getting
Runtime Exception: Resources$ NotFoundException on every resource (string.xml, atrr.xml etc).
Below Android API level, 26 its working fine.
Error Log:
2018-08-27 18:23:41.097 20926-20926/? E/AndroidRuntime: FATAL EXCEPTION: main Process: com.ak.ta.dainikbhaskar.activity.release, PID: 20926 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.ak.ta.dainikbhaskar.activity.release/com.dainik.bhaskar.fitness.activities.EntryActivity}: android.content.res.Resources$NotFoundException: String resource ID
0x7e0b000e
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2792) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2870) at android.app.ActivityThread.-wrap11(Unknown Source:0) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1601) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loop(Looper.java:172) at android.app.ActivityThread.main(ActivityThread.java:6590) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807) Caused by: android.content.res.Resources$NotFoundException: String resource ID #0x7e0b000e at android.content.res.Resources.getText(Resources.java:339) at android.content.res.Resources.getString(Resources.java:433) at android.content.Context.getString(Context.java:556) at com.dainik.bhaskar.fitness.activities.base.BaseActivity.onCreate(BaseActivity.java:34) at com.dainik.bhaskar.fitness.activities.EntryActivity.onCreate(EntryActivity.java:31) at android.app.Activity.performCreate(Activity.java:7023) at android.app.Activity.performCreate(Activity.java:7014) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1215) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2745) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2870) at android.app.ActivityThread.-wrap11(Unknown Source:0) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1601) at android.os.Handler.dispatchMessage(Handler.java:106) at android.os.Looper.loop(Looper.java:172) at android.app.ActivityThread.main(ActivityThread.java:6590) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
code:
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
SplitInstallManager installManager;
String EpaperModuleName = "epaper_dynamic_lib";
private final String EPaperLauncherclassName = "com.bhaskar.epaper.ui.SplashActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
(findViewById(R.id.btn_epaper)).setOnClickListener(this);
installManager = SplitInstallManagerFactory.create(this);
installManager.registerListener(splitInstallStateUpdatedListener);
}
private void loadAndLaunchModule(String moduleName, String launcherclassName) {
// Skip loading if the module already is installed. Perform success action directly.
if (installManager.getInstalledModules().contains(moduleName)) {
Toast.makeText(getApplicationContext(), "onSuccessfulLoad " + moduleName, Toast.LENGTH_LONG).show();
onSuccessfulLoad(moduleName, launcherclassName, true);
return;
}
// Create request to install a feature module by name.
SplitInstallRequest request = SplitInstallRequest.newBuilder()
.addModule(moduleName)
.build();
// Load and install the requested feature module.
installManager.startInstall(request);
Toast.makeText(getApplicationContext(), "startInstall " + moduleName, Toast.LENGTH_LONG).show();
}
private final SplitInstallStateUpdatedListener splitInstallStateUpdatedListener = new SplitInstallStateUpdatedListener() {
@Override
public void onStateUpdate(SplitInstallSessionState splitInstallSessionState) {
List<String> splitModules = splitInstallSessionState.moduleNames();
boolean multiInstall = splitModules.size() > 1;
Toast.makeText(getApplicationContext(), "multiInstall " + multiInstall, Toast.LENGTH_LONG).show();
for (String moduleName : splitModules) {
int status = splitInstallSessionState.status();
if (status == SplitInstallSessionStatus.DOWNLOADING) {
Toast.makeText(getApplicationContext(), "Downloading " + moduleName, Toast.LENGTH_LONG).show();
} else if (status == SplitInstallSessionStatus.REQUIRES_USER_CONFIRMATION) {
try {
Toast.makeText(getApplicationContext(), "REQUIRES_USER_CONFIRMATION " + moduleName, Toast.LENGTH_LONG).show();
startIntentSender(splitInstallSessionState.resolutionIntent().getIntentSender(), null,
0, 0, 0);
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
} else if (status == SplitInstallSessionStatus.INSTALLED) {
onSuccessfulLoad(moduleName, EPaperLauncherclassName, true);
Toast.makeText(getApplicationContext(), "INSTALLED " + moduleName, Toast.LENGTH_LONG).show();
} else if (status == SplitInstallSessionStatus.INSTALLING) {
Toast.makeText(getApplicationContext(), "INSTALLING " + moduleName, Toast.LENGTH_LONG).show();
} else if (status == SplitInstallSessionStatus.FAILED) {
Toast.makeText(getApplicationContext(), "FAILED " + moduleName, Toast.LENGTH_LONG).show();
Log.e(this.getClass().getName(), "Error: " + splitInstallSessionState.errorCode() + "for module " + moduleName);
}
}
}
};
/**
* Request uninstall of all features.
*/
private void requestUninstall(final String moduleName) {
Toast.makeText(getApplicationContext(), "Requesting uninstall of all modules." +
"This will happen at some point in the future.", Toast.LENGTH_LONG).show();
final Set<String> installedModules = installManager.getInstalledModules();
installManager.deferredUninstall(new ArrayList<String>(installedModules)).addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
Toast.makeText(getApplicationContext(), "Uninstalling " + moduleName, Toast.LENGTH_LONG).show();
}
});
}
/**
* Define what to do once a feature module is loaded successfully.
*
* @param moduleName The name of the successfully loaded module.
* @param launch `true` if the feature module should be launched, else `false`.
*/
private void onSuccessfulLoad(String moduleName, String launcherclassName, boolean launch) {
if (launch) {
Toast.makeText(getApplicationContext(), "onSuccessfulLoad " + moduleName,
Toast.LENGTH_LONG).show();
launchActivity(launcherclassName);
}
}
/**
* Launch an activity by its class name.
*/
private void launchActivity(String className) {
try {
Intent intent = new Intent();
intent.setClassName(this.getPackageName(), className);
startActivity(intent);
} catch (
Exception e)
{
Toast.makeText(getApplicationContext(), e.getMessage() + " ", Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
}
@Override
protected void onDestroy() {
installManager.unregisterListener(splitInstallStateUpdatedListener);
super.onDestroy();
}
@Override
public void onClick(View view) {
if (view.getId() == R.id.btn_epaper) {
loadAndLaunchModule(EpaperModuleName, EPaperLauncherclassName);
}
}
Upvotes: 2
Views: 3076
Reputation: 21
I can confirm that the solution provided by @pfmaggi is correct.
It works when you pass the application context, so you have do something like:
class MyApplication: SplitCompatApplication() {
...
override fun attachBaseContext(newBase: Context?) {
super.attachBaseContext(newBase)
SplitCompat.install(this)
}
...
}
and then add the application name in Manifest of your base module ( Note: add application name to the manifest file in your module named 'app' or the module with apply plugin: 'com.android.application'
in its build.gradle file )
Upvotes: 2
Reputation: 6476
You can take a look at how Dynamic Features are implemented in this sample.
There's sample code on how to open some resources, located in a dynamic module, from the base module.
Plus, the samples includes others dynamic modules with activities implemented in Java/Kotlin and native.
Keep in mind that playcore v1.3.4 includes a fix a similar bug. Be sure to use v1.3.4 or newer. The other requirement is to override the attachBaseClassContext
in the activities you've in the dynamic modules:
override fun attachBaseContext(newBase: Context?) {
super.attachBaseContext(newBase)
SplitCompat.install(this)
}
This is shown in the sample with this abstract class.
Upvotes: 1
Reputation: 297
If the Activity is defined in the dynamic feature, you need to call SplitCompat.install(this)
in the attachBaseContext
method to make sure that all new resources are available to your app.
Upvotes: 3