android - 第 2 部分 由 UI 启动的持久性前台 android 服务,也可以在 sleep 模式下工作,也可以在手机重启时启动

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

状态:非常感谢所有在此处和第 1 部分提供帮助和指导的人! 我已经根据研究和提供的帮助编写了代码,并且已将该工作代码放入 EDIT-1。欢迎批评,让代码变得更好。

场景:

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

这是一个冗长的问题问题答案都可以在一个结束或完成插曲,所以我将第二部分作为概要。

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

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

问题:

这是我想要的,在观察了不同的答案后最终得出的结论:

需要每 15 分钟运行一次代码(即使手机处于 sleep 状态)。 我认为需要唤醒锁吗?

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

谁能全面地告诉...我应该使用什么代码...? 满心头痛的研究让我谦虚地感谢。

请求:

请仅在您自信且有经验知道自己在做什么时才回答。

EDIT-1-开始:

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

启动时运行的启动类。

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

        }
    });

最小化

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

最佳答案

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

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

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

    • 2.1 在 BroadcastReceiver 中获取唤醒锁并获取它。
    • 2.2 启动一个IntenetService(此类服务在工作完成后自行启动和结束)
    • 2.3 释放服务中的wakelock

这里有一个很好的例子来说明如何实现这个:commonsware's WakefulIntentService .您不必按原样使用它,您可以制作自己的服务和广播接收器。请记住在调用服务之前获取锁并在服务完成时释放它,否则服务可能不会被调用。

  1. 您的服务每 15 分钟执行一次您想执行的任何操作。然后您可以在 15 分钟后重新安排另一个电话。您还可以在执行和重新安排之前通过共享首选项检查服务是否已启用。

至于控制服务的 Activity :

  1. 按下按钮时检查共享首选项状态并保存相反的状态。
  2. 然后向启动您的服务的同一个接收器发送广播(如果他们已启用它(或安排在以后使用))。
  3. 如果它被禁用,则取消该服务的任何计划。

至于您的启动要求:

  1. 在您的 list 中声明,当调用 android.intent.action.BOOT_COMPLETED 操作时,将调用启动您的服务的同一个接收器。
  2. 声明权限:android.permission.RECEIVE_BOOT_COMPLETED

list 示例:

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

就是这样。

关于android - 第 2 部分 由 UI 启动的持久性前台 android 服务,也可以在 sleep 模式下工作,也可以在手机重启时启动,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17251743/

相关文章:

android - 在 Android 上使用 Chrome 打开 android-app 方案

android - 蓝牙 LE 设备发现服务

java - 创建可滚动区域有哪些技术?

android - 导航组件的 popUpTo 不删除向上按钮

android - 应用程序退出而不是进入下一个 Activity

Android IntentService - 防止同一请求的多个实例

java - UI线程或后台的Android音乐播放器

android - 如何有意地在 whatsapp 中打开与特定号码的对话

android - 如何在android应用程序中使用现有的.so文件

android - Intent 对象未触发 Intent 过滤器