part1持久的前台android服务,由UI启动,在睡眠模式下工作,也在手机重启时启动



Status:--- 同样接受Karakuri和Sharad Mhaske的回答,但由于Sharad Mhaske的回答开始赏金,所以赏金应该归他。

part2 made: part2持久的前台android服务,由UI启动,在睡眠模式下工作,也在手机重启时启动

stack overflow中,只有一个答案可以被接受。我看到两个答案都是可接受的,但必须选择一个(我随机选择)。

观众邀请向上/向下投票答案/问题以感谢的努力!我为Karakuri的回答点赞,以补偿声誉。

Scenario:---

  1. 我想让用户点击一个开始/停止按钮和从UI活动开始/停止服务。我已经制作了UI,所以不用关心这个。只是Button click事件的逻辑。

  2. Do not希望服务绑定到UI活动。如果activity关闭,服务应该继续运行

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

  4. 除非停止按钮被点击我的应用程序的UI, 不希望它被停止(或应该重新启动自己),即使android回收内存。我和电话的使用者都意识到这一点。服务是最重要的。即使在睡梦中。

    details= my app执行一些操作,休眠用户提供的时间(通常为15分钟),唤醒并再次执行操作。没完没了)

    如果我需要AlarmManager,如何实现?或者其他方式?或者只是把操作在永无止境的while loop and sleep for 15 minuts结束?

  5. 服务启动时(通过点击开始按钮)。

QUESTION:---

Primary Question:

  1. 只是不能得到一个最优策略的场景…还有被困在一小段代码上,不知道该用哪一个,怎么用。

  2. 从stackoverflow.com的问题,developer.android.com和一些谷歌结果收集的点点滴滴,但不能实现集成

  3. 请读出请求部分

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

启动/停止服务的Activity 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 -实现start前台服务?指向答案1、示例代码。

尝试在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 not preferred by me.

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

Requests:---

我认为这个问题是大多数与服务打交道的人的正常做法。在这个愿景中,请只回答如果你有这个场景的经验,并且可以全面地解释的方面和策略与最大的样例代码作为完整版本,所以它将是一个帮助社区以及。

对那些分享了他们的观点、时间和经验并帮助了我和社区的人(有责任地)投票赞成或反对。

Que:希望尽最大努力使服务持久,并且在任何情况下都不会停止。将给予它最大的权重并将其作为forgroundservice运行,因为它具有更高的重要性层次。

答案:你需要使用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;
}

问:如果我需要AlarmManager,如何实现?或者其他方式?或者只是把这些操作放到一个无休止的while循环中,最后睡15分钟?

答:需要在服务中注册alarmmanager用于某个任务之后的时间。//在service中注册alarm manager .

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

//现在有一个broadcastreceiver来接收这个intent。

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

//在manifest中注册这个类用于接收告警

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 intent注册这个receiver希望这有助于你清除的东西:)

如果你启动一个服务与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来禁用接收器。在您的Activity中:

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相同的方法禁用它。

我自己也做过类似的东西,但在开发过程中我学到了很多东西,发现让服务整天运行并不是完全必要的。我所做的如下:

实现一个响应事件的服务。尤其是我,我想自动化我的Wifi和移动数据连接。所以我对wifi连接和断开,屏幕打开和关闭等事件做出反应。因此,该服务执行任何需要执行的响应此事件,然后停止,如果需要的话,与AlarmManager调度任何进一步的操作。

现在,这个事件可以像你自己说的每15分钟做一些事情并睡觉,这听起来对我来说,你真的不希望服务24/7运行,而只是每15分钟执行一些事情。这是完全可以实现与AlarmManager不保持您的服务永远运行。

我建议从commonsware的WakefulIntentService派生实现这个服务。

这个类已经为你处理了wakeLock,这样即使手机处于睡眠状态,你也可以执行代码。它将简单地唤醒execute并返回睡眠。

。关于您关于启动和停止服务的活动的问题。您可以在按钮中实现启动或取消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!");
    }
  }
}

你的Manifest可以像这样:

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

最新更新