Android服务在单独进程中

4
我正在运行一个只有一个活动的应用程序,并在onStart中调用startService(new Intent(this,TCPClient.class));。此外,我在服务的onCreate()中启动线程,以建立与我的服务器的TCP连接。服务在单独的进程中运行。它工作得很好,直到我重新启动应用程序(当应用程序关闭时,我不会停止服务)。这样做后,我会从同一IP地址获得1个以上的连接。因此,我有两个客户端连接到同一设备和同一IP。问题是:如何防止创建更多的服务?
清单:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.sample.servicetest" >

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/MainActivityTheme" >
        <!-- android:theme="@style/AppTheme" > -->
        <service android:name=".TCPClient"
            android:process=":service">
        </service>
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:theme="@style/MainActivityTheme" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

OnStart:

@Override
    protected void onStart() {
        super.onStart();

        Log.v(TAG, "onStart");
        startService(new Intent(this, TCPClient.class));
    }

onStartCommand:

public int onStartCommand(Intent intent, int flags, int startId) {
        if (intent != null) {
            Bundle bundle = intent.getExtras();
            if (bundle != null) {
                if (bundle.containsKey("stop"))
                {
                    stopClient();
                }
            }
        }
        Log.v(TAG, "onStartCommand...");
        return TCPClient.START_STICKY;
    }

停止客户端:
private void stopClient() {

        // send mesage that we are closing the connection
        sendCmd(CLOSED_CONNECTION);

        mRun = false;

        SharedPreferences prefSettings = getSharedPreferences("settings", MODE_PRIVATE);
        Editor settingsEd = prefSettings.edit();
        settingsEd.putInt("connected", 0);
        settingsEd.apply();

        if (mBufferOut != null) {
            mBufferOut.flush();
            mBufferOut.close();
        }

        mBufferIn = null;
        mBufferOut = null;
        mServerMessage = null;
    }

3
据我所知,startService() 只能启动一个服务实例。第一次调用 startService() 将触发 Service.onCreate() 事件,然后是 onStartCommand()。后续的 startService() 调用将仅触发 onStartCommand()。请检查您的代码,确保在 onStartCommand() 上不会启动不必要的东西(例如线程或处理程序)。 - Mixaz
@Mixaz,我在Service的onCreate中启动了一个线程。你可以在我的帖子中看到onStartCommand()的完整源代码。 - Alex Hide
是的,很抱歉我错过了那个。无论如何,我认为只应该存在一个服务实例。你怎么知道有两个服务实例? - Mixaz
但这并不意味着有两个服务实例。正如@beworker所写,你可能应该检查你的连接/断开逻辑。服务不是线程,但telnet很可能使用一个线程,并且可能会创建由同一个服务创建的2个线程实例。 - Mixaz
@Mixaz,你可能是对的。但这意味着 onCreate() 被调用而不是 onStartCommand()。 - Alex Hide
显示剩余2条评论
4个回答

5
当我这样做时,会创建一个带服务的新进程。
打开进程视图(例如DDMS透视图 -> 设备),并检查启动了多少个服务。我敢打赌只有一个。
所以,我有两个从同一设备和同一IP连接的客户端。问题是:如何防止创建更多的服务?
我怀疑您需要检查服务内的连接/断开逻辑,因为Android仅允许启动一个服务实例。当服务启动时,将调用“onCreate()”。所有后续的“startService()”命令都传入服务的“onStartCommand()”方法中。只需在服务“onCreate()”和“onStartCommand()”中设置断点,并查看发生了什么即可。

3

好的,我搞清楚了:当我从最近使用的应用程序中滑动我的应用程序时,两个进程(主进程和服务)都被关闭,然后服务重新启动。我通过在我的服务的onCreate中添加startForeground(R.string.app_name, new Notification());来解决这个问题(一个任务管理器可以杀死一个服务吗?)。感谢大家 :)


这是我一直在寻找的一个很棒的技巧(从最近应用程序列表中删除应用后保持服务运行)。 - VSB

3

android:process 应当谨慎使用

(以下内容摘自下方链接)

Android 中一个鲜为人知且似乎未被记录的行为是,每个应用程序进程都有其自己的 Application 实例。

因此,若您有一个位于不同进程中运行的服务,在调用 startService() 时会初始化您应用程序的 Application 类。

更多信息请参见 - Starting Service in Android calls Applications onCreate


0

当你在Android中启动一个服务时,它不是一个独立的进程。 来自Android文档:

大多数关于Service类的困惑实际上都围绕着它不是什么而产生:

  • Service不是一个独立的进程。Service对象本身并不意味着它在自己的进程中运行;除非另有规定,否则它将在与其所属应用程序相同的进程中运行。
  • Service不是一个线程。它本身不是在主线程之外执行工作的手段(以避免应用程序无响应错误)。

我假设您正在尝试创建一个仅运行服务的非UI应用程序。请参考官方文档,它可以很清楚地了解服务的生命周期和相关概念。它还有一些值得一看的示例实现。

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


3
如果我们想让这个服务在一个远程进程中运行(而不是其.apk文件的标准进程),我们可以在其清单标记中使用android:process来指定一个进程。 - Alex Hide
1
请注意:由于服务在其自己的进程中运行,您需要使用一些进程间通信(IPC)来与其他部分进行通信。即使服务在其自己的进程中运行,您仍然需要使用异步处理来执行网络访问,因为Android不允许在进程的主线程中进行网络访问。 - nkz

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