即使应用程序被强制停止,也要重新启动服务,并在关闭应用程序后继续在后台运行服务。如何实现?

18
我想在后台运行一个服务。我的应用程序会在用户勾选复选框时启动服务,在未勾选时停止服务。这个功能运行得非常好。但问题是当我从任务管理器中关闭应用程序时,也会停止该服务。我希望即使应用程序被从任务管理器中关闭,该服务仍然可以继续运行。唯一停止该服务的方法是由用户自己取消勾选该复选框。
如何实现这一点?
以下是我的代码:
我的主要活动
public class SampleServiceActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    final CheckBox cb = (CheckBox) findViewById(R.id.checkBox1);

    cb.setOnCheckedChangeListener(new OnCheckedChangeListener() {
        public void onCheckedChanged(CompoundButton buttonView,
                boolean isChecked) {

            if(isChecked) {
                Toast.makeText(getBaseContext(), "Checked", Toast.LENGTH_LONG).show();
                startService(new Intent(getBaseContext(), MyService.class));
            } else {
                Toast.makeText(getBaseContext(), "Unchecked", Toast.LENGTH_LONG).show();
                stopService(new Intent(getBaseContext(), MyService.class));
            }
        }

    });
}
}

我的服务类

public class MyService extends Service {
Notify n = new Notify();
@Override
public IBinder onBind(Intent arg0) {
    // TODO Auto-generated method stub
    return null;
}

public int onStartCommand(Intent intent, int flags, int startId) {
    Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show();
    n.initNotification(getBaseContext(), true);
    return START_STICKY;
}

//method to stop service
public void onDestroy() {
    super.onDestroy();
    n.cancelNotification(getBaseContext());
    Toast.makeText(this, "Service Stopped", Toast.LENGTH_LONG).show();
}
}

更新

我们该如何使这个服务运行得像gtalk服务?


你有没有找到什么线索?我也在寻找一种方法,在闹钟应用程序被强制停止后自动启动它。一个可以成功实现这一点的应用程序例子是Alarm Clock Xtreme。 - Koger
7个回答

21

我不确定您所指的“任务管理器”是哪个,因为不同的任务管理器将有不同的操作方式,因此我基于用户进入“设置”-->“管理应用程序”-->“强制停止”应用程序的方式来回答您的问题。 假设您的服务正在运行,并且如果用户强制停止了您的进程,则您将无法再次运行该服务,直到用户手动启动它,这在特定的3.0及以上版本(请检查您的版本)中尤其适用。当您想到有一个应用程序一直保持服务运行并以某种方式困扰用户时,这样做似乎很合理。因此,当用户强制停止应用程序时,它不应该重新启动服务来继续骚扰用户。
例如,想象一下如果您能够创建仅通过保持唤醒锁占用处理器时间的应用程序,您无法杀死它们。这将是可怕的,也是极大的安全灾难。
因此,在用户启动您的活动之前,您无法通过任何方式重新启动您的服务。
另外,据我所知,您无法禁用强制停止按钮。您应该认为设备上除了您的应用程序和(在有限程度上)您被授权访问的资源之外,其他任何东西都不受您的控制。
最后,即使是gtalk应用程序也会顺从您的意志,如果您想要强制停止,它只会在您使用Gtalk或其他使用gtalk服务的应用程序(例如PUSH Gmail,适用于没有gtalk作为固件组成部分的手机)时启动。还可以在此处查看Android C2DM:https://dev59.com/iGgu5IYBdhLWcg3wj3z5#11238779

3
您提出了很好的观点,但我不太明白为什么这是不可能的。在4.0版(ICS)中,即使我强制关闭了Google日历应用程序,它仍然会激活通知。我也想知道如何实现这一点。有什么想法吗? - Andy
1
@SofiSoftwareLLC:这些常量用于当运行时由于资源不足而终止服务的情况。如果用户在2.3及以上版本中强制停止应用程序,则无法自动重新启动服务。 - Akhil
1
您可以使用AlarmManager定期尝试重新启动您的服务。 - Marian Paździoch
1
警报在强制停止后被解除,从这个角度来看答案是正确的。但是,如果您尝试强制停止像GMail、G+等应用程序,它们仍将重新启动!我相信帐户同步是一个超越强制停止的机制。这是保持后台服务始终运行的一种方式。 - 3c71
1
@Akhil:你错了,我试过在运行5.0.2操作系统的Moto G上尝试过了, 强制停止Facebook应用程序,但其服务在约30-50分钟后重新启动, 请注意,这是在没有WiFi/数据连接的情况下进行的检查, 因此这次没有GCM通知。 - Jovin
显示剩余8条评论

6

是的,它在运行,Prasahant,但是你能告诉我现在如何启用它,如果我想卸载它,我该怎么做? - PankajAndroid
@Pankaj:如果您想重新启用它,请转到“设置”->“安全性”->“设备管理员”->并取消选中您的应用程序的复选框。 - PrashantAdesara

2
您无法在所有情况下阻止服务被终止。但是,您可以要求系统重新启动它。有两种情况:(1)进程由于某些异常原因而死亡(2)手机重新启动。在前者中,使用START_STICKY或START_REDELIVER_INTENT来重新启动服务。在后者中,您需要为android.intent.action.BOOT_COMPLETED添加一个BroadcastReceiver。
您的代码从onStartCommand返回START_STICKY,因此您选择了其中一条服务重启路径:“如果此服务的进程在启动后被杀死(从onStartCommand(Intent,int,int)返回后),则将其保留在已启动状态,但不要保留此传递的意图。稍后,系统将尝试重新创建服务...”
“这种模式对于需要明确启动和停止以运行任意时间段的事物(例如执行后台音乐播放的服务)是有意义的。”
您也可以使用START_REDELIVER_INTENT。
请注意,如果您的服务正在执行任何重要工作,则需要在后台线程中运行。

http://developer.android.com/reference/android/app/Service.html#START_STICKY


1

如果您只想启动一个隐藏的应用程序一次,请使用我的方法 我创建了一个透明的启动器活动,就像这样

<activity android:name=".MainActivity"
    android:label="@string/app_name"
    android:theme="@style/Theme.Transparent"
    android:excludeFromRecents="true"
    >
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity>

因此,我通过在oncreat()中放置以下代码来使应用程序在启动器中隐藏:

[代码]
PackageManager p = getPackageManager();
    ComponentName componentName = new ComponentName(this, MainActivity.class); // activity which is first time open in manifiest file which is declare as <category android:name="android.intent.category.LAUNCHER" />
p.setComponentEnabledSetting(componentName,PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);

因此,我使用此代码在启动器上显示应用程序图标,并使其在服务类中运行,该类使用广播接收器引导,并在网络连接广播接收器类中也是如此(autostart.java和networkConnectinCheck.java):

PackageManager p = context.getPackageManager();
    ComponentName componentName = new ComponentName(context, MainActivity.class);
    p.setComponentEnabledSetting(componentName, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);

现在用户可以手动运行应用程序,之后我使用我的接收器随时启动应用程序。

1
我不确定你是否可以防止应用程序被任务管理器关闭。如果你想一想,这样做是有道理的。想象一下,如果你有一个应用程序无法响应用户输入,也无法通过任务管理器被杀死,那就不好了。然而,我找到了this一个类似于你的问题的答案。此外,你可以按照这里(在该页面上向下滚动一点,直到“启动服务”之前)所述的方式自动重新启动你的服务。

2
我的问题是应用程序可以从任务管理器中关闭,但其服务不应该关闭。从该应用程序启动的服务只能由用户手动关闭。 - Om3ga
1
或者第二种方式是应用程序不应该在任务管理器的活动应用程序选项卡中可见。因此,无法从那里关闭它。就像Gtalk一样。当我们安装gtalk并登录后,它不会出现在任务管理器的活动应用程序选项卡中。但它在后台运行。 - Om3ga
嗯,它就像是你桌面上的任务管理器。它还允许你关闭系统应用程序。所以,我不明白为什么你要试图避免被杀死。我的意思是,Gmail服务也允许自己被关闭。我想你只能接受这个事实了。 - Kumar Bibek

0
让你的“Service”在单独的进程中运行。这个博客有一个很好的教程:this blog
您可以在<Service>标签中指定android:process属性,以使您的应用程序在自己的进程内运行。
<service
android:name="MyServiceName"
android:process="my_process" 
android:icon="@drawable/icon"
android:label="@string/service_name"
>
</service>

11
“Force Stop”不会关闭与应用程序相关的所有进程吗? - curioustechizen

-1

您可以尝试在服务的onDestroy事件中重新启动服务。使用一些标志来查找服务是由用户关闭还是被强制关闭。

请注意,不能保证每次都会调用onDestroy。


不能保证 onDestroy 方法每次都会被调用。请参考这个链接:https://dev59.com/R2w05IYBdhLWcg3wcReu - Ron

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