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

时间:2013-06-22 14:21:56

标签: android android-intent android-service alarmmanager android-package-managers

Status:真的很感谢所有谁帮助并在这里和第1部分进行了指导! 我已将代码排除在研究和帮助之外,并且已将该工作代码放入EDIT-1 。欢迎批评以使代码更好。

Scenario:

我在第1部分中提到了问题,但由于某种原因,我可以坚持无法使设计正确的策略使用具有真正集成的代码和理智。

这是一个冗长的问题问题答案可能只是一个结束或最终确定插曲,所以我把这第二部分作为一个概要。

可能是我不称职或只是不安阅读这么多的scatered文档和不同策略的答案,或者答案是不同的观点/编码风格。

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

Question:

继承了我想要的东西,并在观察到不同答案后最终得出结论:

需要每15分钟运行一次代码甚至,当手机处于睡眠状态时)。 需要唤醒锁我想?

            //AT boot, check shared preferences to see boolean "serviceEnabled"?
                    //if true, set alarm manager to run a service every 15 minuts.
                    //if false, do nothing.

            //On "enable" button clicked.
                    //make "serviceEnabled" boolean true in shared preferences.
                    //start alarm manager to run a service every 15 minuts.

            //on "Disable" button clicked.
                    //make "serviceEnabled" boolean false in shared preferences.
                    //stop alarm manager and deregister it to run ever.

任何人都可以全面告诉我应该使用哪些代码......? 我很谦卑地感谢你对研究的头痛。

Requests:

如果您有信心并且有经验知道您在做什么,请回答。

EDIT-1-Start:

这是我到目前为止所取得的成就。请随时发表评论或批评。

在启动时运行的Booter类。

public class Booter extends BroadcastReceiver {

      public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();

        if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
          Log.e("boot-status","BOOT_COMPLETED=================================================");
        //  SharedPreferences prefs = context.getSharedPreferences("$MYPACKAGE_preferences",0);
        //  if (prefs.getBoolean("startatboot",false)) {
        if(true){
        Intent updateIntent = new Intent();
        updateIntent.setClass(context, TheService.class);

        PendingIntent pendingIntent = PendingIntent.getService(context, 0, updateIntent, 0);
        AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
        alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, java.lang.System.currentTimeMillis()+5000,5000, pendingIntent);

        }
        }
      }


}

服务类

public class TheService extends Service{

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

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

        pm = (PowerManager) getSystemService(Context.POWER_SERVICE);
        wl = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "My Tag");
        wl.acquire();


        startForeground(1, new Notification());

            ////// will do all my stuff here on in the method onStart() or onCreat()?

        Log.e("app-status","ping ====================================================");

        new Thread(new Runnable() {

            @Override
            public void run() {
                wl.release();
                stopSelf(); 
            }
        }).start();


        return START_STICKY;    
    }

    @Override
      public void onDestroy() {
        stop();
      }

    public void stop(){
        //if running
        // stop
        // make vars as false
        // do some stopping stuff
        stopForeground(true);


    }





}

GUI启动/停止

public class SettingsActivity extends Activity {
  // some code to initialize things

    buttonStop.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            Intent updateIntent = new Intent();
        updateIntent.setClass(SettingsActivity.this, TheService.class);

        PendingIntent pendingIntent = PendingIntent.getService(SettingsActivity.this, 0, updateIntent, PendingIntent.FLAG_UPDATE_CURRENT);
        AlarmManager alarmManager = (AlarmManager)SettingsActivity.this.getSystemService(Context.ALARM_SERVICE);
        alarmManager.cancel(pendingIntent);
        //make sharepred boolean as false

        }
    });

    buttonStart.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View v) {
            Intent updateIntent = new Intent();
        updateIntent.setClass(SettingsActivity.this, TheService.class);

        PendingIntent pendingIntent = PendingIntent.getService(SettingsActivity.this, 0, updateIntent, 0);
        AlarmManager alarmManager = (AlarmManager)SettingsActivity.this.getSystemService(Context.ALARM_SERVICE);
        alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, java.lang.System.currentTimeMillis()+5000,5000, pendingIntent);
        //make shared prefs boolean as true

        }
    });

Menifiest

  <?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" /> // irrelevent here
      <uses-permission android:name="android.permission.INTERNET" />        // my app uses these though in service class.
      <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
      <uses-permission android:name="android.permission.WAKE_LOCK" />

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

      <service android:name=".TheService" />
      <receiver android:name=".Booter" >
          <intent-filter>
          <action android:name="android.intent.action.BOOT_COMPLETED" />
          <category android:name="android.intent.category.HOME" />
          </intent-filter>
      </receiver>

      </application>

  </manifest>

EDIT-1-END.

1 个答案:

答案 0 :(得分:4)

如果您只需要每15分钟运行一次此代码。那么你真的不需要保持服务全天候运行。真的,不要这样做,这是个坏主意。你需要做的是:

  1. 使用AlarmManager每15分钟安排一次警报。然后使用BroadcastReceiver捕获此警报。此警报必须是RTC_WAKE_UP ,以便在深度睡眠时唤醒手机并且必须是实时的,因为它将使用深度睡眠计时器。

  2. 广播接收器必须启动服务。现在这个对服务的调用必须这样做:

    • 2.1在BroadcastReceiver中获取唤醒锁并获取()它。
    • 2.2启动 IntenetService (此类服务在工作完成后自行开始和结束)
    • 2.3发布服务中的wakelock
  3. 这里有一个很好的例子:commonsware's WakefulIntentService。您不必按原样使用它,您可以制作自己的服务和广播接收器。只需记住在调用服务之前获取锁定并在服务完成时释放它,否则服务可能不会被调用。

    1. 您的服务每15分钟执行您想执行的任何操作。然后你可以在另外15分钟内重新安排另一个电话。您还可以在执行和重新安排之前检查是否通过共享首选项启用了服务。
    2. 至于您控制服务的活动:

      1. 按下按钮时,检查共享首选项状态并保存相反的内容。
      2. 然后将广播发送到启动服务的同一接收方(如果已启用)(或将其安排在以后)。
      3. 如果已禁用,则取消该服务的所有计划。
      4. 至于你的启动要求:

        1. 在您的清单中声明,当调用操作android.intent.action.BOOT_COMPLETED时,将调用启动服务的同一接收者。
        2. 声明权限:android.permission.RECEIVE_BOOT_COMPLETED
        3. 示例清单:

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

          取消和安排警报的示例:

          public synchronized static void disableTimers(final Context context)
          {
            Log.i(TAG, "Canceling Alarms");
            final Intent in = new Intent(Constants.Actions.TIMER_ACTION);
            final PendingIntent pi = PendingIntent.getBroadcast(context, 0, in, PendingIntent.FLAG_UPDATE_CURRENT);
            ((AlarmManager) context.getSystemService(Context.ALARM_SERVICE)).cancel(pi);
          }
          
          public synchronized static void enableTimer(final Context context)
          {
            Log.i(TAG, "Enabling Alarm");
            final Intent in = new Intent(Constants.Actions.TIMER_ACTION);
            final PendingIntent pi = PendingIntent.getBroadcast(context, 0, in, PendingIntent.FLAG_UPDATE_CURRENT);
            ((AlarmManager) context.getSystemService(Context.ALARM_SERVICE)).set(AlarmManager.ELAPSED_REALTIME_WAKEUP, SystemClock.elapsedRealtime() + FIFTEEN_MINUTES, pi);
          }
          

          启动时启动服务的示例:

          @Override
          public void onReceive(final Context context, final Intent intent)
          {
            final Intent in = new Intent(context, MyService.class);
            in.setAction(Actions.BOOT_RECEIVER_ACTION);
            Log.i(TAG, "Boot completed. Starting service.");
            MyService.acquireLock();
            context.startService(in);
          }
          

          在服务上释放锁

          private static volatile WakeLock mStaticWakeLock = null;
          
          private synchronized static WakeLock getLock(final Context context)
          {
            if (mStaticWakeLock == null)
            {
              final PowerManager mgr = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
              mStaticWakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKE_LOCK_PARAMETER);
              mStaticWakeLock.setReferenceCounted(true);
            }
            return mStaticWakeLock;
          }
          
          @Override
          protected final void onHandleIntent(final Intent intent)
          {
            try
            {
              run(intent);
            }
            finally
            {
              final WakeLock lock = getLock(getApplicationContext());
              if (lock.isHeld())
              {
                lock.release();
                Log.i(TAG, "Releasing WakeLock");
              }
            }
          }
          

          就是这样。