如何在服务库中从通知启动主活动而无需硬编码活动类

3
我正在使用以下代码在服务中打开主/启动器活动,该代码在我将此项目声明为库并创建使用此库的其他两个项目之前正常工作。
因此,在服务的onStartCommand中编写了此代码。
 final Notification notification = new Notification(R.drawable.ic_launcher, null, 0);   

    String notifTitle = "Service";
    String notifMessage = "Running";

    final Intent notificationIntent = new Intent(this,   MainActivity.class);
    notificationIntent.putExtra("extra", "value");
    notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP
                            | Intent.FLAG_ACTIVITY_SINGLE_TOP);
    notificationIntent.setAction("android.intent.action.MAIN");
    notificationIntent.addCategory("android.intent.category.LAUNCHER");

    final PendingIntent contentIntent = PendingIntent
                            .getActivity(this, 0, notificationIntent,0);



    notification.setLatestEventInfo(this, notifTitle, notifMessage, contentIntent);     
    startForeground(17, notification);

MainActivity.class是库的一部分,使用这个库的两个项目有它们自己的主活动MainActivityA和MainActivityB,它们都扩展了库的MainActivity。

现在的问题是当我点击服务的通知时,应该启动MainActivityA或MainActivityB,但目前什么也没有发生,但之前当库本身是一个项目时它是有效的。

任何想法都将非常感激,

谢谢,

4个回答

1

你正在硬编码你的意图

final Intent notificationIntent = new Intent(this,   MainActivity.class);

启动MainActivity.class而不是MainActivityA.class或MainActivityB.class。您必须将正确的类传递到服务中,或更改意图以更通用的方式,让Intent框架发现您的活动(这可能是您的应用程序独有的)。

我正在撰写有关意图过滤器的内容,但@smith324比我更快。

我建议使用元数据而不是类似于字符串资源的东西:

<meta-data android:name="com.foo.service.LaunchName" android:value="com.foo.MainActivityA"></meta-data>

这样做可以避免在添加其他库时发生第三方字符串名称冲突,并且我认为这样可以使开发人员的字符串文件更加清晰,因为这更多地是用于类的连接,而不是用户可能需要国际化/翻译的内容。

请参见:如何将用户定义的属性/值添加到Android清单文件中?


是的,我明白这一点,这就是为什么它不起作用的原因,我想知道的是如何使服务选择正确的意图活动,或通过其他方式启动正确的MainActivityA/B。 - Ahmed
正如你所说,将Intent变成通用的,这样框架就可以发现Activity。如何使其通用?提供代码示例会很有帮助。谢谢。 - Ahmed

1

有几种方法可以解决这个问题。

您可以在清单文件中的 Activity 上声明 Intent 过滤器并广播 Intent,但如果用户在设备上安装了两个版本,则可能会出现问题。(支持库中有本地广播可供使用docs

个人建议使用 Android 的资源系统动态加载类名。Intent 可以让您设置 ComponentName,这与给 Activity 类提供硬编码引用相同。

Intent i = new Intent();
String mPackage = ctx.getPackageName();
String mClass = ctx.getResources().getString(R.string.notification_class_name);
i.setComponent(new ComponentName(mPackage,mPackage+mClass));

图书馆项目的值可以被使用它们的项目覆盖,因此在这两个项目中,您都有一个与该应用程序通知活动对应的strings.xml中的值。
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="notification_class_name">.MainActivityA</string>
</resources>

然后,您可以使用此Intent与您的pendingIntent一起使用,它将在当前应用程序内打开活动。


我使用了你的方法来解决它,但是基于包名使用if else条件语句,感谢你的帮助。 - Ahmed
我们如何解决“无法找到显式活动类...您是否在AndroidManifest.xml中声明了此活动?”使用该库的项目中,该库的清单无法访问活动。 - BabyishTank

1

这是一个老问题,但我在尝试解决这个问题时遇到了它。我想出了一种更简单的方法来完成此操作,而无需配置任何字符串或传递任何参数。

String packageName = getPackageName();
Intent notificationIntent = getPackageManager().getLaunchIntentForPackage(packageName);

现在你已经有了意图,可以添加额外的内容等。

0

获取启动器活动的方法之一如下。

public static Class<?> GetLauncherActivity(Context context)
    {
        String packageName = context.getPackageName();
        Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(packageName);
        String className = launchIntent.getComponent().getClassName();
        try
        {
            return Class.forName(className);
        }
        catch (ClassNotFoundException e)
        {
            e.printStackTrace();
            return null;
        }
    }

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