在Android平台上启动服务

4

我正在使用 startService(Intent intent) 方法启动一个服务。当我调用这个函数时,它会到达服务的 onCreate,但无法调用 onStartCommand。以下是我的代码--

@Override
public void onReceive(Context context, Intent intent) {
    // Send a text notification to the screen.
    Log.e("mudit", "Action: " + intent.getAction());

    try {
        ConnectivityManager connManager = (ConnectivityManager) context
                .getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo info = connManager.getActiveNetworkInfo();
        Log.e("mudit", "getType: " + info.getType());
        Log.e("mudit", "isConnected: " + info.isConnected());
        if (info.isConnected()) {

            Intent newinIntent = new Intent(context, service.class);
            context.startService(newinIntent);
        }

    } catch (Exception e) {
        e.printStackTrace();
        Intent newinIntent = new Intent(context, service.class);
        context.stopService(newinIntent);

    }

}

服务代码 --

package com.android.service;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.widget.Toast;

public class service extends Service {

    @Override
    public IBinder onBind(Intent arg0) {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        Toast.makeText(this, "Service created...", Toast.LENGTH_LONG).show();
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Toast.makeText(this, "Service destroyed ...", Toast.LENGTH_LONG).show();
    }

    public int onStartCommand(Intent intent, int flags, int startId) {

        Toast.makeText(this, "onStartCommand...", Toast.LENGTH_LONG).show();
        return 1;
    }

}  

Manifest.xml --

<receiver class=".AReceiver" android:name=".AReceiver">
        <intent-filter>
            <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
        </intent-filter>
    </receiver>
    <service class=".service" android:name=".service"
        android:enabled="true" android:icon="@drawable/icon">
    </service>

为了调试目的,我宁愿使用LOG而不是TOAST。首先通过决策过程使您的代码正常工作。@JPM给出的一个明智的建议是不要将您的服务命名为“service”。如果您想保持模糊,请称其为“myService”。 - tony gil
5个回答

3
  1. 非绑定式服务:它会在后台无限期运行,即使启动服务的活动已经结束。
  2. 绑定式服务:它将在活动的生命周期内一直运行。

活动可以通过 startService() 启动服务,并可通过 stopService() 停止服务。 如果活动想要与服务进行交互,则可以使用 bindService()

首先调用 onCreate(),然后由活动提供的意图数据调用 onStartCommand()

来源


2

larsVogel解决了这个问题(以及许多类似的问题)在这篇优秀的文章中

这是我如何改编他的代码以创建一个连接接收器,用于监视用户何时连接到WIFI网络,以便批量上传使用数据:

在清单文件中,在您的</application>结束标记之前放置一个接收器并声明一个服务:

    <receiver android:name=".ConnMonitor" android:enabled="true">
        <intent-filter>
            <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
        </intent-filter>
    </receiver>
    <service android:name=".BatchUploadGpsData" ></service>

</application>

在一个名为ConnMonitor.java的单独文件中创建广播接收器类(请取消注释Log调用以便能够正确监视流量)

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.util.Log;

public class ConnMonitor extends BroadcastReceiver {
    private String TAG = "TGtracker";

    @Override
    public void onReceive(Context context, Intent intent) {
        //String typeName = "";
        String state = "";
        int type = -1;
        ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService( Context.CONNECTIVITY_SERVICE );
        NetworkInfo test = (NetworkInfo) connectivityManager.getActiveNetworkInfo();
        //Log.v(TAG,"there has been a CONNECTION CHANGE -> "+intent.getExtras().get(ConnectivityManager.EXTRA_NETWORK_INFO));
        try {
            //typeName = test.getTypeName().toString();
            type = test.getType();
            state = test.getState().toString();
            //Log.i(TAG,"type -> '"+typeName +"'  state -> '"+state+"'"   );
        } catch (Exception e) {
            //typeName = "null";
            type = -1;
            state = "DISCONNECTED";
            //Log.i(TAG,"type -> error1 "+e.getMessage()+ "   cause = "+e.getCause()   );
        }

        if ( (type == 1)  &&  (state == "CONNECTED") ) {
            //Log.i(TAG, "I am soooo friggin uploadin on this beautiful WIFI connection ");
            Intent batchUploadDataService = new Intent(context, BatchUploadGpsData.class);
            context.startService(batchUploadDataService);
        } else {
            //Log.e(TAG,"NO FOUND MATCH type -> '"+typeName +"'  state -> '"+state+"'"   );
        }
    }
}

最后,创建一个名为BatchUploadGpsData.java的服务,代码如下:

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;

public class BatchUploadGpsData extends Service {
    final String TAG = "TGtracker";

    @Override
    public void onCreate() {
        Log.e(TAG, "here i am, rockin like a hurricane.   onCreate service");
    // this service tries to upload and terminates itself whether it is successful or not 
    // but it only effectively DOES anything while it is created 
    // (therefore, you can call 1 million times if uploading isnt done, nothing happens)
    // if you comment this next line, you will be able to see that it executes onCreate only the first it is called
    // the reason i do this is that the broadcast receiver is called at least twice every time you have a new change of connectivity state with successful connection to wifi
        this.stopSelf();
    }
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        //Log.i(TAG, "Received start id " + startId + ": " + intent);
        Log.e(TAG, "call me redundant BABY!  onStartCommand service");
        // this service is NOT supposed to execute anything when it is called
        // because it may be called inumerous times in repetition
        // all of its action is in the onCreate - so as to force it to happen ONLY once
        return 1;
    }
    @Override
    public IBinder onBind(Intent intent) {
        // TODO Auto-generated method stub
        return null;
    }

}

这不是伪代码,这是实际的代码,在Android 2.2及以上版本上经过测试并运行。

测试此服务的方法是关闭并重新启动Android上的WIFI服务(关闭WIFI路由器也可以)。但是此代码不验证您是否真正连接到网络。为此,我建议您发出一个httpclient请求并检查调用的结果。这超出了本讨论的范围。

注意:由于服务在与UI相同的线程上运行,我强烈建议您根据具体需求在单独的线程或异步任务中实现适当的上传。您还可以在单独的线程上运行整个服务,但这再次超出了本讨论的范围,尽管这在这些情况下是标准做法。


2

首先,在onStartCommand(..)之前添加@Override,然后确保Android项目的目标版本高于2.0


1

我相信,在服务中您无法访问任何UI组件,例如对话框甚至Toast。

试试这个。

public int onStartCommand(Intent intent, int flags, int startId) {

/*    Toast.makeText(this, "onStartCommand...", Toast.LENGTH_LONG).show();
    return 1; */

    Log.i("YourService", "Yes this works.");
}

0
首先,我的建议是把你的类命名为其他名称,以避免后续混淆。其次,这是我调用服务清单的一个示例,它已经能够正常工作。由于服务不在我的应用程序包中,所以在调用服务时,我使用完整路径名等方式。
<service android:name="com.public.service.UploaderService" android:icon="@drawable/vgbio"></service>

这是我的服务类的要点,
package com.public.service;
....
public class UploaderService extends Service{
....
}

第三步,请确保在onStartCommand()方法中使用@Override注解。


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