2012-04-23 43 views
1

我有一个activity的onCreate方法调用Init函数(该函数调用一些涉及很多东西的本地代码并调用openSLES音频api)。问题的关键是,这个Init函数在再次调用时会导致应用程序崩溃,这种情况发生在屏幕旋转上,或者当我使用Back按钮关闭该活动并重新启动它时(但是如果在此期间该进程被终止,我没有麻烦)。我无法改变Init函数的承载。如何检查onCreate以前的android进程是否一样被杀死?

我发现当活动被破坏时我没有杀死这个进程,我在阅读文档后期待这样做,这是一件好事,因为 - 如果有一些音频信号正在播放 - 在活动结束后继续播放破坏了,这对我的目的有好处。

我试图执行使用了的onSaveInstanceState初始化状态的检查,但效果很好只能在屏幕旋转,当是的onSaveInstanceState叫那。当我按下后退按钮时,不会调用回调。

,所以我尝试使用共享偏好,执行状态的onPause节约。但是在这一点上,我有相反的问题:如果进程被终止,共享首选项值将保留,但在这种情况下,我需要再次执行Init以使应用程序正常工作。

我想我需要一种方法来知道,如果一个进程终止或不后创建我的活动,但此刻我看不出。我想在onPause方法中使用bundle实例,但我无法确定这是否可行。任何类型的提示都会非常感激。

+0

你不能在onPause/init onResume中释放那个东西吗?应该只有一个实例处于这种状态。或者把整个东西变成一个服务,因为这些东西总是单个实例 – zapl 2012-04-23 16:53:32

+0

我不能释放“那个东西”(这是一个很好的方式来命名:)),既不在onPause也不在其他任何地方,我只能依靠它在进程终止后安全地调用。服务选项听起来像是对我的需求矫枉过正,但我​​开始考虑它。 – athos 2012-04-23 17:04:10

+0

一个简单的本地(意图)服务只是一些代码行,你可以在一个活动中启动它,在下一个活动中停止它,因为它的生命周期不与活动相关联。它们非常适合背景音乐等不会中断的事物。尝试解决Activity生命周期当然是可能的,但我不认为这是一个干净的解决方案。 – zapl 2012-04-23 17:09:31

回答

0

有一个简单的解决这个问题。您无需在SharedPreferences中保存任何内容即可完成此操作。只需使用一个静态(类)变量。像这样:

public class Globals { 
    public static boolean initialized = false; 
} 

当类加载时变量initialized将被设置为false。只有一次。在您的代码,您再检查并设定这样的变量:

protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    // Initialize (but only once per process) 
    if (!Globals.initialized) { 
     init(); // Call init function that does things one time per process 
     Globals.initialized = true; // Remember we are initialized so we don't 
            // do it again 
    } 
    ... 
} 

即使所有的活动完成后,如果操作系统不杀你的过程变量initialized仍将是“真”,如果应用程序再次启动。一旦操作系统杀死进程,下次启动应用程序并创建新进程时,该变量将设置为“false”。

+0

如果您在另一个Activity中,此应用程序的进程被终止并稍后重新启动,这将不起作用。 – 2013-04-30 11:33:39

+0

@MaciejGórski你是什么意思“这不行”? OP询问了一个具体的案例。他需要确保他只在进程中调用一次'init()'方法。我的答案并不意味着这是一个普通用途“这是如何恢复一切,以防Android杀死你的进程” – 2013-04-30 11:58:27

+0

为了确保本地lib在使用之前被初始化,它不能被初始化在(第一次)活动正常运行当用户点击应用程序图标时。当进程在任何其他活动(思想Spash,菜单,游戏)上被终止并重新启动时,您将无法使用音频API,因此将不会有声音或应用程序崩溃。 – 2013-04-30 12:07:57

0

对于每个进程你有PID或进程ID。在您的init函数中,您可以轻松获取线程ID并可以将其保存为任何整数值。 。

Thread.currentThread()的getId()));

,只要您的活动将重新启动只是检查线程ID是相同或不同。如果线程ID不同,那么调用你的函数init函数。否则,你已经完成了。

+0

尝试使用进程ID。请参阅@ darkmist的回答。 – athos 2012-04-23 18:00:55

+0

你不必专注于不同的过程可以有相同的PID。有一次,一个线程ID将是唯一的。所以如果你的线程有id 1,那么当时其他子线程不能有相同的id。如果你使用Thread.currentThread()。getId()));在你的oncreate,那么你将有UIthread ID,但你需要该线程的init函数正在运行的ID,所以要么根据你的条件使用上面的语句到你的init函数的init函数中。将它保存在变量中并使用它。它应该工作。 – 2012-04-23 18:57:16

1
  1. 您可以将您的pid在共享偏好的过程。如果您在YourActivity.on中比较当前的pid和存储的pid,则可以确定何时必须初始化OpenSLES。
  2. 您可以在ApplicationApplication.onCreate中初始化应用程序派生类中的OpenSLES - 仅调用一次。

编辑:

即声明以下类:

public class YourApplication extends Application { 
    static private native synchronized void InitOpenSLES(); 

    public YourApplication() {} 

    // see http://developer.android.com/reference/android/app/Application.html#onCreate() for details 
    @Override 
    public void onCreate() { 
    super.onCreate(); 
    InitOpenSLES(); 
    } 
} 
+0

刚刚尝试了1.它似乎工作,但我会确定不同过程的PID将永远不同吗?我的意思是,在旧的死亡之后创建的新进程不可能获得相同的pid? 我不明白2,你能详细说明吗? – athos 2012-04-23 18:00:35

+0

1.你说得对,理论上操作系统可能会杀死你的进程,而不是你启动大量的进程来包装pid数,然后用相同的pid创建一个新的进程 - 在这种情况下,你不会执行初始化过程需要。但是这种情况的概率非常低=)关于用于为新创建的进程分配pid的算法,请参见例如这里:http://stackoverflow.com/questions/3446727/how-does-linux-determine-the-next- PID。 2.查看答案的更新。 – 2012-04-23 20:04:25

+0

接受了第2点;) – athos 2012-05-02 08:13:53