由UI启动的第1部分持久foreGround android服务,也在睡眠模式下工作,也在手机重启时启动

时间:2013-06-09 02:27:57

标签: android android-intent android-service android-alarms android-backup-service

Status:--- 同样接受Karakuri和Sharad Mhaske的回答,但是自Sharad Mhaske回答开始赏金,赏金应归他所有。

第2部分:part-2 persistent foreGround android service that starts by UI, works at sleep mode too, also starts at phone restart

stack overflow中,只有一个答案可能已接受。我认为两个的答案都是可接受的,但必须选择一个(我随机选择)。

观众 受邀上/下投票答案/问题感谢您的努力!。我赞成Karakuri的答案来弥补声誉。

Scenario:---

  1. 我想让用户点击一个开始/停止按钮,然后从UI活动中启动/停止服务。我已经让用户界面这么关心了。但只是按钮点击事件的逻辑。

  2. 是否希望将服务绑定到UI活动。如果活动关闭,服务应继续运行。

  3. 想要尽最大努力 服务是持久的,并且在任何情况下都不会停止。将它赋予最大权重,并将其作为ForGroundSerice运行,因为它具有更高的重要性层次。(希望没问题?)

  4. 除非我的应用用户界面点击了停止按钮不希望它停止(或应该重启自己)即使android回收内存。我和手机用户都知道了。这项服务至关重要。 即使在睡觉。

    details =我的应用程序执行一些操作,为用户提供的时间(通常为15分钟)休眠,唤醒并再次执行操作。这永远不会结束)

    如果我需要AlarmManager,如何实现?或任何其他方式?或者只是将操作放在一个无休止的while loop and sleep for 15 minuts的末尾?

  5. 启动服务时(单击开始按钮)。它应该输入一个条目,以便在手机重启时自动启动。

  6. QUESTION:---

    Primary Question:

    1. 无法为方案获得最佳策略 ...而且坚持使用一小段代码,哪一个要使用以及如何使用。

    2. 来自stackoverflow.com问题,developer.android.com和一些谷歌搜索结果,但无法在集成中实现。

    3. 请宣读请求部分

    4. Secondary Question:

      我的代码中的评论是那些小问题。

      Research and Code:---

      策略

                  want this to happen every time the user opens the UI.
      
          //Start Button:-----
          //check if ForGroundService is running or not. if not running, make var/settings/etc "serviceStatus" as false 
                  <-------(how and where to stare this and below stated  boolean?)
          //start ForGroundService 
                  <-------(how?)
          //make "SericeStatus" as true
      
          //check if "ServiceStartOnBoot" is false
          //Put ForGroundService to start on boot -------(to make it start when ever the phone reboots/restarts) 
                  <-------(how?)
          //make "ServiceStartOnBoot" as true
                  // the boolean can also be used to check the service status.
      
      
      
          //Stop Button:------
          //makes SericeStatus and ServiceStartOnBoot as false
          //stops service and deletes the on boot entry/strategy
      

      启动/停止服务的活动UI类:

      public class SettingsActivity extends Activity {
      
          @Override
          protected void onCreate(Bundle savedInstanceState) {
              super.onCreate(savedInstanceState);
              setContentView(R.layout.activity_settings);
      
              //some button here to start / stop and their onClick Listners
      
      
      
          Intent mySericeIntent = new Intent(this, TheService.class);
          }
      
      
          private void startMyForGroundService(){
      
          startService(mySericeIntent);
      
          }
      
          private void stopMyForGroundSerice(){
              stopService(mySericeIntent);
                                /////// is this a better approach?. stopService(new Intent(this, TheService.class));          
                                /////// or making Intent mySericeIntent = new Intent(this, TheService.class);
                                /////// and making start and stop methods use the same?
      
                                /////// how to call stopSelf() here? or any where else? whats the best way?
          }
      
      }
      

      服务类:

        public class TheService extends Service{
      
            @Override
            public IBinder onBind(Intent arg0) {
                // TODO Auto-generated method stub
                return null;
            }
      
            @Override
              public int onStartCommand(Intent intent, int flags, int startId) {
                startForeground(1, new Notification());
                                        ////// will do all my stuff here on in the method onStart() or onCreat()?
      
                return START_STICKY;    ///// which return is better to keep the service running untill explicitly killed. contrary to system kill.
                                        ///// http://developer.android.com/reference/android/app/Service.html#START_FLAG_REDELIVERY
      
                //notes:-//  if you implement onStartCommand() to schedule work to be done asynchronously or in another thread, 
                //then you may want to use START_FLAG_REDELIVERY to have the system re-deliver an Intent for you so that it does not get lost if your service is killed while processing it
            }
      
            @Override
              public void onDestroy() {
                stop();
              }
      
            public void stop(){
                //if running
                // stop
                // make vars as false
                // do some stopping stuff
                stopForeground(true);
                                        /////// how to call stopSelf() here? or any where else? whats the best way?
      
            }
      
      
        }
      

      Menifest文件:

            <?xml version="1.0" encoding="utf-8"?>
            <manifest xmlns:android="http://schemas.android.com/apk/res/android"
            package="com.example.myapp"
            android:versionCode="1"
            android:versionName="1.0" >
      
            <uses-sdk
                android:minSdkVersion="10"
                android:targetSdkVersion="17" />
      
            <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
            <uses-permission android:name="android.permission.INTERNET" />
      
            <application
      
                android:allowBackup="true"
                android:debuggable="true"
                android:icon="@drawable/ic_launcher"
                android:label="@string/app_name"
                android:theme="@style/AppTheme" >
                <activity
                android:name="com.example.myapp.MainActivity"
                android:label="@string/app_name" >
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
      
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
                </activity>
                <activity
                android:name="com.example.myapp.SettingsActivity"
                android:label="@string/title_activity_settings" >
                </activity>
      
            </application>
      
            </manifest>
      

      References:---

      Android - implementing startForeground for a service?指出答案1,示例代码。

      Trying to start a service on boot on Android

      Android: Start Service on boot?

      http://developer.android.com/guide/components/services.html

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

      http://developer.android.com/training/run-background-service/create-service.html不是我提供的。

      http://developer.android.com/guide/components/processes-and-threads.html我的研究起点

      Requests:---

      对于大多数处理服务的人来说,我认为这个问题是正常的做法。 在该愿景中,请仅在您拥有该方案的经验时才能回答,并且可以使用最大样本代码作为完整版方面和策略>这样对社区也有帮助。

      对答案进行上下(有责任)投票,因为对我来说,分享他们的观点,时间和经验,帮助我和社区。

3 个答案:

答案 0 :(得分:3)

Que:想要尽最大努力保持服务的持久性并且在任何情况下都不会停止。将它赋予最大的权重并将其作为ForGroundSerice运行,因为它具有更高的重要性层次。 (希望没问题?)

答案:您需要使用START_STICKY Intent标志开始服务。

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

// We want this service to continue running until it is explicitly
// stopped, so return sticky.
return START_STICKY;
}

Que:如果我需要AlarmManager,如何实现?或任何其他方式?或者只是将操作放在一个无休止的while循环中并在结束时睡15分钟?

答案:您需要在服务中注册alarmmanager一段时间后执行某项任务。 //在服务中注册警报管理器。

PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, new         Intent("com.xxxxx.tq.TQServiceManager"), PendingIntent.FLAG_UPDATE_CURRENT);

        AlarmManager alarmManager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);

    alarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + 1000 , 30 * 1000 , pendingIntent);

//现在有一个广播接收者来接收这个意图。

class Alarmreceiver extends Broadcastreceiver
{
   //u can to task in onreceive method of receiver.
}

//在清单中注册此类以进行警报接收器操作。

Que:启动服务时(单击“开始”按钮)。它应该输入一个条目,以便在手机重启时自动启动。

答案:使用广播接收器来监听onboot完成的意图。

public class StartAtBootServiceReceiver extends BroadcastReceiver{

    @Override
    public void onReceive(Context context, Intent intent) {
        try {           
            if( "android.intent.action.BOOT_COMPLETED".equals(intent.getAction())) {                

                ComponentName comp = new ComponentName(context.getPackageName(), LicensingService.class.getName());
                ComponentName service = context.startService(new Intent().setComponent(comp));
                if (null == service){
                    // something really wrong here
                    //Log.Write("Could not start service " + comp.toString(),Log._LogLevel.NORAML);
                }
            }
            else {
                //Log.Write("Received unexpected intent " + intent.toString(),Log._LogLevel.NORAML);   
            }
        } catch (Exception e) {
            //Log.Write("Unexpected error occured in Licensing Server:" + e.toString(),Log._LogLevel.NORAML);
        }
    }
}

//需要在manifest.xml文件中为Action_BOOTCOMPLETED意图注册此接收器 希望这可以帮助你清除事情:)

答案 1 :(得分:2)

如果您使用startService()启动服务,即使活动关闭,它也会继续运行。它只会在您调用stopService()时停止,或者它曾调用stopSelf()(或者如果系统终止您的进程以回收内存)。

要在启动时启动服务,请创建一个只启动服务的BroadcastReceiver:

public class MyReceiver extends BroadcastReceiver {
    public void onReceive(Context context, Intent intent) {
        Intent service = new Intent(context, MyService.class);
        context.startService(service);
    }
}

然后将这些添加到您的清单中:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application ... >

    <receiver android:name="MyReceiver" 
        android:enabled="false" >
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
    </receiver>
</application>

请注意,首先未启用接收器。当用户启动服务时,使用PackageManager启用接收器。当用户停止服务时,使用PackageManager禁用接收器。在您的活动中:

PackageManager pm = getPackageManager();
ComponentName receiver = new ComponentName(this, MyReceiver.class);
pm.setComponentEnabledSetting(receiver, PackageManager.COMPONENT_ENABLED_STATE_ENABLED,  PackageManager.DONT_KILL_APP);

使用与PackageManager.COMPONENT_ENABLED_STATE_DISABLED相同的方法将其停用。

答案 2 :(得分:0)

我自己做了类似的事情,但是我在开发它的过程中学到了很多东西,并发现让服务整天耗尽你的电池并不是完全必要的。我所做的是以下内容:

实施对事件做出反应的服务。就我而言,我想自动化我的Wifi和移动数据连接。所以我对wifi连接和断开连接,屏幕打开和关闭等事件作出反应。所以这个服务执行响应此事件需要执行的事情然后停止,如果需要,使用AlarmManager安排任何进一步的操作。

现在,这个事件可以由像你这样的定时器每隔15分钟说出来做一些事情并且睡觉,这对我来说听起来你真的不希望服务全天候运行而只是每15分钟执行一次。使用AlarmManager可以完全实现,而不会让您的服务永远运行。

我建议实施源自commonsware's WakefulIntentService

的此服务

此类已经为您处理了wakeLock,因此即使手机处于睡眠状态,您也可以识别代码。它只会唤醒执行并重新入睡。

现在。关于有关启动和停止服务的活动的问题。您可以在启动按钮中实现或取消AlarmManager警报。您还可以使用sharedPreferences存储一个简单的布尔值,告诉您它是否已启用,因此下次运行服务时它可以读取值并知道它是应该继续还是停止。

如果你把它实现为事件反应服务,就像我说的那样,你的按钮甚至可以对广播意图作出反应,这样你的活动甚至不必直接调用服务只是广播一个意图,服务可以像其他事件。为此使用BroadcastReceiver。

我会尝试举例,但要小心你所要求的是将很多代码放在一个地方......

BootReceiver:

public class BootReceiver extends BroadcastReceiver
{
  private static final String TAG = BootReceiver.class.getSimpleName();

  @Override
  public void onReceive(final Context context, final Intent intent)
  {
    final Intent in = new Intent(context, ActionHandlerService.class);
    in.setAction(Actions.BOOT_RECEIVER_ACTION);  //start the service with a flag telling the event that triggered
    Log.i(TAG, "Boot completed. Starting service.");
    WakedIntentService.sendWakefulWork(context, in);
  }
}

服务:

public class ActionHandlerService extends WakedIntentService
{
  private enum Action
  {
    WIFI_PULSE_ON, WIFI_PULSE_OFF, DATA_PULSE_ON, DATA_PULSE_OFF, SCREEN_ON, SCREEN_OFF, WIFI_CONNECTS, WIFI_DISCONNECTS, WIFI_CONNECT_TIMEOUT, WIFI_RECONNECT_TIMEOUT, START_UP, BOOT_UP
  }

  public ActionHandlerService()
  {
    super(ActionHandlerService.class.getName());
  }

  @Override
  public void run(final Intent intent)
  {
    mSettings = PreferenceManager.getDefaultSharedPreferences(this);
    mSettingsContainer.enabled = mSettings.getBoolean(getString(R.string.EnabledParameter), false);
    if (intent != null)
    {
      final String action = intent.getAction();
      if (action != null)
      {
        Log.i(TAG, "received action: " + action);
        if (action.compareTo(Constants.Actions.SOME_EVENT) == 0)
        {
          //Do what ever you want
        }
        else
        {
          Log.w(TAG, "Unexpected action received: " + action);
        }
      }
      else
      {
        Log.w(TAG, "Received null action!");
      }
    }
    else
    {
      Log.w(TAG, "Received null intent!");
    }
  }
}

你的清单可能会是这样的:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.yourcompany.yourapp"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="7"
        android:targetSdkVersion="17" />

    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

    <application
        android:allowBackup="false"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >

        <activity
            android:name="com.yourcompany.yourapp.activities.HomeActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        <service android:name="com.yourcompany.yourapp.services.ActionHandlerService" />
        <receiver android:name="com.yourcompany.yourapp.receivers.BootReceiver" >
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <category android:name="android.intent.category.HOME" />
            </intent-filter>
        </receiver>

    </application>
</manifest>