0

我有一个服务是假设启动 android 音乐应用程序,基本上是让音乐应用程序在屏幕上弹出。我试图这样做的方式是:

public void onStart(Intent intent, int startId) 
{
    // TODO Auto-generated method stub
    super.onStart(intent, startId);
    System.out.println("LOGS STARTED");
    ActivityManager am = (ActivityManager)this.getSystemService(ACTIVITY_SERVICE);
    List l = am.getRunningAppProcesses();
    Iterator i = l.iterator();
    PackageManager pm = this.getPackageManager();
    while(i.hasNext()) 
    {
        ActivityManager.RunningAppProcessInfo info = (ActivityManager.RunningAppProcessInfo)(i.next());
        try 
        {
            CharSequence c = pm.getApplicationLabel(pm.getApplicationInfo(info.processName, PackageManager.GET_META_DATA));
            Log.w("LABEL", c.toString());
            if(c.equals("Music"))
            {
                System.out.println("HELLO \n");
                                    Intent in = new Intent();
                in.setClassName("com.android.music", "com.android.music.MediaButtonIntentReceiver");
                startActivity(in);
            }
         }
        catch(Exception e) 
        {
            //Name Not FOund Exception
        }
    }

}

logcat 确实显示 Hello,但由于某种原因,音乐不会开始。但是当我将它移到另一个位置时,它确实开始了。有没有办法以这种方式做到这一点,还是我必须以另一种方式做到这一点?我希望用户单击图标后弹出音乐应用程序。这就是为什么我做了 if c.equals("Music") 部分。之所以在 try 里面是因为这一行:

CharSequence c = pm.getApplicationLabel(pm.getApplicationInfo(info.processName, PackageManager.GET_META_DATA));

会得到一个错误,快速修复是让它被 try/catch 语句包围。

4

1 回答 1

8

这里有很多关于 Intents、Activity 和 BroadcastReceivers 之间的区别以及 Android 为此类事情设置的一般方式的误解。让我们看看我们是否可以清除其中的一些。:)

您已经创建了一个 Intent 并尝试将其定位到特定的包,然后调用startActivity. 但是您正在尝试针对com.android.music.MediaButtonIntentReceiver不是 Activity 的组件。startActivity使用此 Intent调用可能会失败。

它比这更糟糕。即使你有准确的活动名称来发送com.android.music包的意图,安装了不同音乐应用程序的用户怎么办?许多 OEM 在设备上发布了他们自己的音乐播放器变体,这意味着明确定位该软件包名称将在他们的设备上失败。例如,Nexus 设备上的 Google Play 音乐使用包名称com.google.android.music,而不是您在上面指定的包。

基于匹配本地化应用标签字符串的过滤也会给您带来问题。您正在寻找一个简单标题为“音乐”的应用程序,但此字符串会根据特定的音乐应用程序和区域设置而有所不同。例如,Google Play 音乐使用字符串“Google Play 音乐”,而翻译成其他语言的“音乐”也不会匹配这个确切的字符串。

最后,您只需要使用 ActivityManager 查看正在运行的应用程序进程。这会给您带来问题,因为如果应用程序当前没有运行怎么办?Android 可以在后台终止应用程序进程以获取资源,用户不需要知道这一点。您正在编写的代码会为您的用户意外中断。

所以,你可以做什么?

意图是通用的。与其使用特定的人类可读标签字符串来抓取特定程序包的运行进程列表,不如告诉 Android 您要在语义上执行什么操作。您想启动音乐应用程序。

Intent musicIntent = new Intent(Intent.ACTION_MAIN)
        .addCategory(Intent.CATEGORY_LAUNCHER)
        .addCategory(Intent.CATEGORY_APP_MUSIC)
        .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(musicIntent);

逐行进行,我们在这里所做的是告诉 Android:

  • 我们想发起一个“主要”行动,而不是更专业的行动
  • 我们希望它是用户通常会从启动器(主屏幕)启动的 Activity
  • 我们希望它是一款宣传自己能够播放音乐的应用程序
  • 我们希望它在新任务中启动,或者如果该应用程序的任务已经存在,则将其置于最前面。

现在,我们以更少的代码行成功地以更通用的方式实现了这一点,这种方式更能抵抗边缘情况,并且还会自动遵循用户对音乐应用程序的偏好。(如果有多个应用程序与 Intent 匹配,系统会询问用户他们想要启动哪个应用程序,并且有机会将其设置为下次的默认设置。)

话虽如此,您还提到您正在从服务启动一个活动。如果这种情况突然发生而不是响应用户采取的行动,通常被认为是糟糕的用户体验设计,因此请记住这一点。

于 2012-12-01T21:08:24.960 回答