【问题标题】:Starting a service on android platform在android平台上启动服务
【发布时间】:2010-02-20 04:31:26
【问题描述】:

我正在使用 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 的一个合理建议是不要将您的服务命名为“服务”。如果您想含糊其辞,请称其为“myService”。

标签: android android-service


【解决方案1】:
  1. 未绑定服务:它无限期地在后台运行,即使启动的活动也结束了服务。
  2. 绑定服务:它将一直运行到活动的生命周期。

Activity 可以通过startService() 启动服务,它将通过stopService() 停止。 如果activity想和service交互,可以使用bindService()

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

Source

【讨论】:

    【解决方案2】:

    larsVogel 解决了这个问题(以及许多其他类似的问题)in this excellent post

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

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

    在名为 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 在同一线程上运行,因此我强烈建议您根据您的特定需求在单独的线程或异步任务上实现正确的上传。您也可以在单独的线程上运行整个服务,但这又不是本次讨论的范围,尽管在这些情况下是标准做法。

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

        我相信,您无法访问任何 UI 组件,例如 Dialog 甚至是服务中的 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.");
        }
        

        【讨论】:

          【解决方案5】:

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

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

          这是我的服务类的要点,

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

          第三,确保你在 onStartCommand() 中使用了@Override。

          【讨论】:

            猜你喜欢
            • 2012-03-29
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2015-08-03
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-02-16
            相关资源
            最近更新 更多