是否可以在try / catch中启动活动?

时间:2012-12-01 19:05:48

标签: android android-intent service android-activity try-catch

我有一个服务,假设启动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(“音乐”)部分的原因。它在try中的原因是因为这一行:

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

会出现错误,快速解决方法是将其包含在try / catch语句中。

1 个答案:

答案 0 :(得分:7)

这里有很多关于意图的误解,活动和BroadcastReceivers之间的区别,以及为这样的事情设置Android的一般方式。让我们看看我们是否可以清除其中一些内容。 :)

您已经创建了一个Intent,并且您尝试将其定位到特定的包,然后调用startActivity。但是您尝试将组件com.android.music.MediaButtonIntentReceiver作为目标,而不是活动。使用此Intent调用startActivity可能会失败。

但是,这比那更糟糕。即使你有精确的活动名称来发送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:

  • 我们希望推出一个“主要”动作而不是更专业的动作
  • 我们希望它是用户通常从Launcher(主屏幕)启动的活动
  • 我们希望它成为一个宣传自己能够播放音乐的应用
  • 我们希望它在新任务中启动,或者如果该应用程序的任务已经存在,请将其置于最前面。

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

所有这一切,你还提到你正在从一项服务开始一项活动。如果这种情况不可能发生,而不是响应用户采取的行