Status:---
我同样接受Karakuri和Sharad Mhaske的回答,但由于Sharad Mhaske的回答在开始赏金,所以赏金应该归他。
part2 made: part2持久的前台android服务,由UI启动,在睡眠模式下工作,也在手机重启时启动
在stack overflow
中,只有一个答案可以被接受。我看到两个答案都是可接受的,但必须选择一个(我随机选择)。
观众被邀请向上/向下投票答案/问题以感谢的努力!我为Karakuri的回答点赞,以补偿声誉。
Scenario:---
-
我想让用户点击一个开始/停止按钮和从UI活动开始/停止服务。我已经制作了UI,所以不用关心这个。只是Button click事件的逻辑。
-
Do not希望服务绑定到UI活动。如果activity关闭,服务应该继续运行
-
希望尽最大努力使服务持久并且在任何情况下都不停止。将给予它最大的权重并将其作为
ForGroundSerice
运行,因为具有更高的重要性层次。 -
除非停止按钮被点击我的应用程序的UI, 不希望它被停止(或应该重新启动自己),即使android回收内存。我和电话的使用者都意识到这一点。服务是最重要的。即使在睡梦中。
details= my app执行一些操作,休眠用户提供的时间(通常为15分钟),唤醒并再次执行操作。没完没了)
如果我需要
AlarmManager
,如何实现?或者其他方式?或者只是把操作在永无止境的while loop and sleep for 15 minuts
结束? -
服务启动时(通过点击开始按钮)。
QUESTION:---
Primary Question:
-
只是不能得到一个最优策略的场景…还有被困在一小段代码上,不知道该用哪一个,怎么用。
-
从stackoverflow.com的问题,developer.android.com和一些谷歌结果收集的点点滴滴,但不能实现集成
-
请读出请求部分
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.htmlhttp://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>