在 android 平台上启动服务

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2301057/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 05:19:19  来源:igfitidea点击:

Starting a service on android platform

androidandroid-service

提问by mudit

I am starting a service using startService(Intent intent)method. When i call this function it reaches the onCreateof service but it is unable to call onStartCommand. Here is my code--

我正在使用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);

    }

}

Service Code --

服务代码——

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 --

清单.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>

采纳答案by tony gil

larsVogel solves this problem (and many others like it) in this excellent post.

larsVogel在这篇优秀的帖子中解决了这个问题(还有很多其他人喜欢它)。

this is how i adapted his code to create a connectivity receiver that monitors when the user connects to a WIFI network so as to batch upload usage data:

这就是我修改他的代码以创建一个连接接收器的方式,该接收器可以监控用户何时连接到 WIFI 网络以便批量上传使用数据:

in the Manifest file, place a receiver and declare a service right before the end tag for your < / application >:

在 Manifest 文件中,在您的 </ 应用程序的结束标记之前放置一个接收器并声明一个服务:

    <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>

create a broadcast receiver class in a separate file called ConnMonitor.java (please uncomment the Log calls to be able to properly monitor the flow)

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

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+"'"   );
        }
    }
}

and, finally, create a service BatchUploadGpsData.java like this:

最后,像这样创建一个服务 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;
    }

}

this is not pseudocode, this is actual code, tested and running on android 2.2 and up.

这不是伪代码,这是实际代码,在 android 2.2 及更高版本上测试和运行。

the way to test this service is to shut down and restart your WIFI services on your android (powering off the wifi router will also do the trick). BUT this code does not verify if you are effectively connected to the net. for that, i recomend that you make an httpclient request and check out the result of the call. beyond the scope of this discussion.

测试此服务的方法是在您的 android 上关闭并重新启动您的 WIFI 服务(关闭 wifi 路由器的电源也可以解决问题)。但是此代码不会验证您是否有效连接到网络。为此,我建议您发出 httpclient 请求并查看调用结果。超出了本讨论的范围。

NOTE: since services run on the same thread as the UI, i highly recommend that you implement the uploading proper on a separate thread or asynctask, depending your specific needs. you can also run the whole service on a separate thread, but that is once again not the scope of this discussion, despite being standard practice in these cases.

注意:由于服务在与 UI 相同的线程上运行,我强烈建议您在单独的线程或异步任务上正确实现上传,具体取决于您的特定需求。您也可以在单独的线程上运行整个服务,但这再次不是本讨论的范围,尽管在这些情况下是标准做法。

回答by srinivas Nidadavolu

  1. Unbound Service: it runs in the background indefinitely even started activity with service ends also.
  2. Bound Service : it will run till life time of activity.

Activity can start service via startService()and it will stop via stopService(). If activity wants to interact with service, it can use bindService().

First onCreate()is called, after onStartCommandis called with the intent data provided by the activity.

  1. Unbound Service:它无限期地在后台运行,甚至在服务结束时也开始活动。
  2. 绑定服务:它将一直运行到活动的生命周期。

Activity 可以通过 启动服务startService(),它将通过 停止stopService()。如果活动想要与服务交互,它可以使用bindService().

FirstonCreate()被调用,afteronStartCommand被 Activity 提供的意图数据调用。

Source

来源

回答by Jimmy

First you should add @Overridebefore onStartCommand(..)then make sure that the target for the Android project is higher than 2.0.

首先,你应该添加@OverrideonStartCommand(..)确认为Android项目的目标是高于2.0

回答by JaydeepW

I believe, that you cannot access any UI components like Dialog or even a Toast in a service.

我相信,您无法访问任何 UI 组件,例如服务中的 Dialog 甚至 Toast。

try this.

尝试这个。

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.");
}

回答by JPM

First of all name your class to something else is my recommendation to avoid confusion down the line. Second here is an example of my manifest call of a service I have that works. I use full path names when calling services and such since they are not in the same package as my application.

首先,将您的课程命名为其他名称是我的建议,以避免混淆。第二个是我的服务清单调用的一个例子,我有一个有效的服务。我在调用服务等时使用完整路径名,因为它们与我的应用程序不在同一个包中。

<service android:name="com.public.service.UploaderService" android:icon="@drawable/vgbio"></service>

Here is the gist of my service class,

这是我的服务类的要点,

package com.public.service;
....
public class UploaderService extends Service{
....
}

Third make sure you use @Override to the onStartCommand().

第三,确保对 onStartCommand() 使用 @Override。