12

I want to start a new Intent dynamically. Therefore setClassName seems the best choice.

First, I define 3 activity in Manifest

<activity android:name="com.example.pkg2.Act" />
<activity android:name="com.example.pkg1.Act1" />
<activity android:name="com.example.pkg1.Act2" />

From com.example.pkg2.Act:

Intent intent = new Intent();
if(index == 0) intent.setClassName(Act.this, "com.example.pkg1.Act1");
else intent.setClassName(Act.this, "com.example.pkg1.Act2");
startActivity(intent);

And will get this exception:

Unable to find explicit activity class {com.example.pkg2.Act/com.example.pkg1.Act1}; have you declared this activity in your AndroidManifest.xml?

It looks like we can only use setClassName to dynamically start new Activity but within the same package.

Any idea to solve this issue? All help is appreciated.

anticafe
  • 6,816
  • 9
  • 43
  • 74

9 Answers9

22

setClassName take a Package Context as first param setClassName(Context packageContext, String className):

Intent intent = new Intent();
if(index == 0) {
  intent.setClassName("com.example.pkg1", "com.example.pkg1.Act1");
} else {
  intent.setClassName("com.example.pkg1", "com.example.pkg1.Act2");
  startActivity(intent);
}

and in

<activity android:name="com.example.pkg2.Act" />
<activity android:name="com.example.pkg1.Act1" />
<activity android:name="com.example.pkg1.Act2" />

or you try this :

if(index == 0) {
  Intent intent = new Intent(Intent.ACTION_MAIN)
    .addCategory(intent.CATEGORY_LAUNCHER)
    .setClassName("com.example.pkg1", "com.example.pkg1.Act1")
    .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
    .addFlags(Intent.FLAG_FROM_BACKGROUND)
    .setComponent(new ComponentName("com.example.pkg1", "com.example.pkg1.Act1"));
  getApplicationContext().startActivity(intent);
} else {
  Intent intent  = new Intent(Intent.ACTION_MAIN)
    .addCategory(intent.CATEGORY_LAUNCHER)
    .setClassName("com.example.pkg1", "com.example.pkg1.Act2")
    .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
    .addFlags(Intent.FLAG_FROM_BACKGROUND)
    .setComponent(new ComponentName("com.example.pkg1", "com.example.pkg1.Act2"));
  getApplicationContext().startActivity(intent);
}
Sky Kelsey
  • 19,192
  • 5
  • 36
  • 77
ρяσѕρєя K
  • 132,198
  • 53
  • 198
  • 213
7

The first param is the applicationId located in the build.gradle file

The second param is full path to of the class with its package. for example: intentObj.setClassName("applicatioId", "com.youCompany.yourAppName.YourClassName")

1

You can use the following method to create the intent in the package context:

    Intent intent = new Intent(this, MyActivity.class);
    intent.setAction(Intent.ACTION_VIEW);
    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    startActivity(intent);

This way you keep on generic code.

HTH

Simon
  • 509
  • 7
  • 25
1

You can also launch Activities in this manner. Try this

Intent intent = new Intent();
Class<?> activityClass = Class.forName("your.application.package.name." + NameOfClassToOpen); 
intent.setClass(this, activityClass);

And in order to use setClassName. You should supply it with packageName and its class path too like

intent.setClassName("your.application.package.name", "your.application.package.name.activityClass");
Xar-e-ahmer Khan
  • 1,314
  • 15
  • 23
0

intent.setClassName(packageName, className);

where
packageName - The name of the package implementing the desired component, i.e. the package where the caller belongs to.
className - fully qualified name of the class [from different package]

Calling from com.example.pkg2.Act:

intent.setClassName("com.example.pkg2", "com.example.pkg1.Act1");
0

Use this code and you'll be fine.

Intent intent = new Intent();
String resourcePackageName = getResources().getResourcePackageName(R.string.some_defined_resource);
intent.setClassName(getApplicationContext().getPackageName(),resourcePackageName + ".SubPackageName[/if any/].ClassName");
startActivity(intent);
Yan
  • 1,569
  • 18
  • 22
0

The most likely cause of the problem is that the given class name is not a class linked into pkg2. Here's snippet of code that I was using to start an intent in an AndroidInstumentationTest app.

    Intent intent = new Intent(Intent.ACTION_MAIN);
    intent.setClassName("com.xxx.android.app",
            "com.xxx.android.app.MainActivity")
            .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    mActivity = instrumentation.startActivitySync(intent);

This code works perfectly fine running it from my app module which has the MainActivity class in it. It does not work if I try to use it in a module that doesn't have MainActivity class linked to it. From my read of the original problem statement, that seem likely what user "anticafe" says he was trying to do. My guess is that internally there is a call to "Class.forName(className, classLoader) where classLoader is the ClassLoader for the given package. And of course that'll fail since that package is not linked in.

And yes, you do need to add the flag "FLAG_ACTIVITY_NEW_TASK", as others have suggested, at least for the situations where you do have the class linked in!

Tom Rutchik
  • 1,183
  • 1
  • 12
  • 15
0

Follow the syntax to write setClassName() method:

 setClassName( pkgName, className ) 
Paresh Mayani
  • 127,700
  • 71
  • 241
  • 295
-1
intent.setClassName(Act.this, Act1.class);
DaringLi
  • 409
  • 2
  • 6
  • 16