【问题标题】:How to keep service running in background如何保持服务在后台运行
【发布时间】:2014-06-26 21:33:29
【问题描述】:

我正在创建一个应用程序,只要用户按下电源按钮 3 次,它就会启动一个活动。经过一番研究,我发现要做到这一点,首先你需要创建一个服务来启动一个广播接收器来检查屏幕的开/关状态。

基本上,即使应用程序关闭,我也希望它能够运行。按下电源按钮 3 次或更多次后,它应该会立即开始另一个活动。

如果您知道解决方案,请给我完整的代码或答案链接。

我以某种方式设法编写了这段代码,但它不起作用:

UpdateService.java

这是我使用的服务类:

import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.IBinder;
import android.util.Log;
import android.widget.Toast;

public class UpdateService extends Service {

   BroadcastReceiver mReceiver;

   @Override
   public void onCreate() {
      super.onCreate();
     // register receiver that handles screen on and screen off logic
      IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
      filter.addAction(Intent.ACTION_SCREEN_OFF);
      mReceiver = new MyReceiver();
      registerReceiver(mReceiver, filter);
   }

   @Override
   public void onDestroy() {

      unregisterReceiver(mReceiver);
      Log.i("onDestroy Reciever", "Called");

      super.onDestroy();
   }

   @Override
   public void onStart(Intent intent, int startId) {
      boolean screenOn = intent.getBooleanExtra("screen_state", false);
      if (!screenOn) {
         Log.i("screenON", "Called");
         Toast.makeText(getApplicationContext(), "Awake", Toast.LENGTH_LONG)
            .show();
      } else {
         Log.i("screenOFF", "Called");
         Toast.makeText(getApplicationContext(), "Sleep",
    Toast.LENGTH_LONG)
    .show();
      }
}

@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
 return null;
 }
}

MyReceiver.java

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

public class MyReceiver extends BroadcastReceiver {
private boolean screenOff;

@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
    screenOff = true;
} else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
    screenOff = false;
}
Intent i = new Intent(context, UpdateService.class);
i.putExtra("screen_state", screenOff);
context.startService(i);
 }
}

mainfest.xml

<receiver android:name=".MyReceiver">
<intent-filter>
<action android:name="android.intent.action.SCREEN_OFF"/>
<action android:name="android.intent.action.SCREEN_ON"/>
</intent-filter>
</receiver>
<service android:name=".UpdateService" />

如果我必须在我的mainactivity.java 文件或重定向到的活动中包含任何内容,请同时说明。

我已经使用了这些权限:

<uses-permission android:name="com.android.alarm.permission.SET_ALARM" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

【问题讨论】:

  • 这是正确的方法还是我必须使用其他方法
  • 请帮助我无法让它在后台服务中工作,但更新服务没有显示

标签: android android-intent android-service android-broadcast


【解决方案1】:

没有你确定完整的代码,但让我做一个有根据的猜测:

你没有实现应用程序或活动是吗?

我认为您至少需要其中一个来在 onCreate() onResume() 回调中注册接收器,只需在清单中声明接收器可能不起作用。

在 Eclipse 或任何其他带有 android 集成的 IDE 中进行调试非常有帮助,因为它显示了您的应用程序的进程,并且您可以确定它们是否被启动。稍微调试一下就会告诉你你的接收器是否工作正常。

如果您愿意分享更多代码,我们当然可以进一步讨论。

【讨论】:

  • 你建议我应该怎么做
  • 在 Eclipse 中连接您的代码并调试 ypur 接收器?如果运气不好,请尝试在运行时使用应用程序或活动以编程方式注册接收器?
【解决方案2】:

试试这个?

MyService
public class MyService extends Service {
    @Override
    public void onCreate() {
        super.onCreate();

        ...

        if (!registered) {
            MyReceiver mybroadcast = new MyReceiver() {
            registerReceiver(mybroadcast, new IntentFilter(Intent.ACTION_SCREEN_ON));
            registerReceiver(mybroadcast, new IntentFilter(Intent.ACTION_SCREEN_OFF));
        }
    }
}

MyReceiver
public class MyReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        ...
    }
}

BootStartUpReciever
public class BootStartUpReciever extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        // Start Service On Boot Start Up
        Intent service = new Intent(context, MyService.class);
        context.startService(service);
    }
}



Manifest

<service android:name="my.package.MyService" />
<receiver
    android:name="my.package.BootStartUpReciever" android:enabled="true" android:exported="true" >
    <intent-filter>
        <action android:name="android.intent.action.BOOT_COMPLETED" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</receiver>

【讨论】:

  • 语法错误或tokkens,构造错误,也必须添加绑定方法
  • 我给出了最低代码。你看……?那将被您的逻辑代码替换。
【解决方案3】:

我认为您的要求不需要服务类。因为您将在调用 screen on action 时启动一个活动。请参考我的以下实现并分享您的想法。

//Application class.
    public class MyApplication extends Application {
        static String TAG = "MyApplication";
        @Override
        public void onCreate() {
            super.onCreate();

            IntentFilter intentFilter = new IntentFilter(Intent.ACTION_SCREEN_ON);
            intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
            registerReceiver(new BroadcastReceiver() {
                @Override
                public void onReceive(Context context, Intent intent) {
                    // screen off
                    if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
                        Log.d(TAG, Intent.ACTION_SCREEN_OFF);
                        //screen on
                    } else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
                        Log.d(TAG, Intent.ACTION_SCREEN_ON);
                        // To open your main activity.
                        Intent i = new Intent();
                        i.setClass(context, MainActivity.class);
                        i.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                        i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                        context.startActivity(i);
                    }
                }
            }, intentFilter);
        }

    }

    // Manifest.xml

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

        <uses-sdk
            android:minSdkVersion="8"
            android:targetSdkVersion="19" />

        <application
            android:name=".MyApplication"
            android:allowBackup="true"
            android:icon="@drawable/ic_launcher"
            android:label="@string/app_name"
            android:theme="@style/AppTheme" >
            <activity
                android:name="com.hopabit.wakeup.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>
        </application>

    </manifest>

【讨论】:

    【解决方案4】:

    为了让您的服务保持运行,您需要放入一个线程。确保service 在额外的线程中,因为服务本身不是额外的进程或线程。这可以做到,例如使用Handler

    HandlerThread thread = new HandlerThread(SERVICE_THREAD_NAME);
    thread.start();
    handlerThreadId = thread.getId();
    serviceLooper = thread.getLooper();
    serviceHandler = new ServiceHandler(serviceLooper);
    

    【讨论】:

      【解决方案5】:

      我看到了你的代码。您非常接近解决方案。

      在您的 Activity 的 onCreate() 中注册您的广播接收器,以便在屏幕关闭和屏幕开启时同时显示事件

      if (!registered) {
                  MyReceiver mybroadcast = new MyReceiver() {
                  registerReceiver(mybroadcast, new IntentFilter(Intent.ACTION_SCREEN_ON));
                  registerReceiver(mybroadcast, new IntentFilter(Intent.ACTION_SCREEN_OFF));
      }
      

      在共享首选项或其他任何地方维护一个 int 计数器,首先将其初始化为 0,然后在 onReceive() 中递增该计数器:

      public class MyReceiver extends BroadcastReceiver {
      private boolean screenOff;
      
      @Override
      public void onReceive(Context context, Intent intent) {
      
      int counter = get counter value from shared preference.
      
      if (intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
          screenOff = true;
          //increment the counter++
      
      } else if (intent.getAction().equals(Intent.ACTION_SCREEN_ON)) {
          screenOff = false;
          //increment the counter++
      }
      
      if(counter>3){
      Intent i = new Intent(context, UpdateService.class);
      i.putExtra("screen_state", screenOff);
      context.startService(i);
      }
       }
      }
      

      【讨论】:

        【解决方案6】:

        您可以启动服务并经常重复它,也可以在启动时监听事件。您可以使用此链接,它的服务一直在运行。 https://github.com/commonsguy/cwac-wakeful 它可以帮助您解决问题。

        【讨论】:

          【解决方案7】:

          我认为你需要的是使用 IntentService。

          我会告诉你原因:

          服务在 UI 线程上运行(即使在后台),因此这更适合与 UI 交互,但另一方面,它们不应该像您想要的那样长时间运行。 另外,IntentService 正在另一个线程上运行,因此最好将它们用于较长的后台任务。

          您应该做的是在内存(使用 Application 对象)或另一个 Singleton 上保存屏幕 ON/OFF 状态的次数。

          如果您需要更多帮助,请告诉我

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2018-12-15
            • 2020-05-01
            • 1970-01-01
            • 1970-01-01
            • 2023-03-23
            • 1970-01-01
            • 2021-06-24
            相关资源
            最近更新 更多