Android总结篇系列:Android Service
Service通常总是称之为“后台服务”,其中“后台”一词是相对于前台而言的,具体是指其本身的运行并不依赖于用户可视的UI界面,因此,从实际业务需求上来理解,Service的适用场景应该具备以下条件:
1.并不依赖于用户可视的UI界面(当然,这一条其实也不是绝对的,如前台Service就是与Notification界面结合使用的);
2.具有较长时间的运行特性。
1.Service AndroidManifest.xml 声明
一般而言,从Service的启动方式上,可以将Service分为Started Service和Bound Service。无论哪种具体的Service启动类型,都是通过继承Service基类自定义而来。在使用Service时,要想系统能够找到此自定义Service,无论哪种类型,都需要在AndroidManifest.xml中声明,语法格式如下:
1 <service android:enabled=["true" | "false"] 2 android:exported=["true" | "false"] 3 android:icon="drawable resource" 4 android:isolatedProcess=["true" | "false"] 5 android:label="string resource" 6 android:name="string" 7 android:permission="string" 8 android:process="string" > 9 . . . 10 </service>
其中,android:exported属性上一篇博文中对此已进行详尽描述,android:name对应Service类名,android:permission是权限声明,android:process设置具体的进程名称。需要注意的是Service能否单独使用一个进程与其启动方式有关,本后下面会给出具体说明。其他的属性此处与其他组件基本相同,不再过多描述。
注:如果自定义Service没有在AndroidManifest.xml中声明,当具体使用时,不会像Activity那样直接崩溃报错,对于显式Intent启动的Service,此时也会给出waring信息“IllegalArgumentException: Service not registered”,有时候不容易发现忘了声明而一时定位不到问题。
2.Started Service
Started Service相对比较简单,通过context.startService(Intent serviceIntent)启动Service,context.stopService(Intent serviceIntent)停止此Service。当然,在Service内部,也可以通过stopSelf(…)方式停止其本身。
1)Started Service自定义
下面代码片段显示的是一个最基本的Started Service的自定义方式:
1 public class MyService extends Service { 2 3 public static final String TAG = "MyService"; 4 5 @Override 6 public IBinder onBind(Intent intent) { 7 return null; 8 } 9 10 @Override 11 public void onCreate() { 12 super.onCreate(); 13 Log.w(TAG, "in onCreate"); 14 } 15 16 @Override 17 public int onStartCommand(Intent intent, int flags, int startId) { 18 Log.w(TAG, "in onStartCommand"); 19 Log.w(TAG, "MyService:" + this); 20 String name = intent.getStringExtra("name"); 21 Log.w(TAG, "name:" + name); 22 return START_STICKY; 23 } 24 25 @Override 26 public void onDestroy() { 27 super.onDestroy(); 28 Log.w(TAG, "in onDestroy"); 29 } 30 }
其中,onBind(…)函数是Service基类中的唯一抽象方法,子类都必须重写实现,此函数的返回值是针对Bound Service类型的Service才有用的,在Started Service类型中,此函数直接返回 null 即可。onCreate(…)、onStartCommand(…)和onDestroy()都是Started Service相应生命周期阶段的回调函数。
2) Started Service使用
1 public class MainActivity extends Activity { 2 3 public static final String TAG = "MainActivity"; 4 5 private Button startServiceBtn; 6 private Button stopServideBtn; 7 private Button goBtn; 8 9 private Intent serviceIntent; 10 11 @Override 12 protected void onCreate(Bundle savedInstanceState) { 13 super.onCreate(savedInstanceState); 14 setContentView(R.layout.activity_main); 15 16 startServiceBtn = (Button) findViewById(R.id.start_service); 17 stopServideBtn = (Button) findViewById(R.id.stop_service); 18 goBtn = (Button) findViewById(R.id.go); 19 20 startServiceBtn.setOnClickListener(new View.OnClickListener() { 21 @Override 22 public void onClick(View v) { 23 serviceIntent = new Intent(MainActivity.this, MyService.class); 24 startService(serviceIntent); 25 } 26 }); 27 28 stopServideBtn.setOnClickListener(new View.OnClickListener() { 29 @Override 30 public void onClick(View v) { 31 stopService(serviceIntent); 32 } 33 }); 34 35 goBtn.setOnClickListener(new View.OnClickListener() { 36 @Override 37 public void onClick(View v) { 38 Intent intent = new Intent(MainActivity.this, BActivity.class); 39 startActivity(intent); 40 } 41 }); 42 43 } 44 45 @Override 46 protected void onDestroy() { 47 super.onDestroy(); 48 Log.w(TAG, "in onDestroy"); 49 } 50 }
如上代码片段,
当Client调用startService(Intent serviceIntent)后,如果MyService是第一次启动,首先会执行 onCreate()回调,然后再执行onStartCommand(Intent intent, int flags, int startId),当Client再次调用startService(Intent serviceIntent),将只执行onStartCommand(Intent intent, int flags, int startId),因为此时Service已经创建了,无需执行onCreate()回调。无论多少次的startService,只需要一次stopService()即可将此Service终止,执行onDestroy()函数(其实很好理解,因为onDestroy()与onCreate()回调是相对的)。
下面重点关注下onStartCommand(Intent intent, int flags, int startId)方法。
其中参数flags默认情况下是0,对应的常量名为START_STICKY_COMPATIBILITY。startId是一个唯一的整型,用于表示此次Client执行startService(…)的请求请求标识,在多次startService(…)的情况下,呈现0,1,2….递增。另外,此函数具有一个int型的返回值,具体的可选值及含义如下:
START_NOT_STICKY:当Service因为内存不足而被系统kill后,接下来未来的某个时间内,即使系统内存足够可用,系统也不会尝试重新创建此Service。除非程序中Client明确再次调用startService(…)启动此Service。
START_STICKY:当Service因为内存不足而被系统kill后,接下来未来的某个时间内,当系统内存足够可用的情况下,系统将会尝试重新创建此Service,一旦创建成功后将回调onStartCommand(…)方法,但其中的Intent将是null,pendingintent除外。
START_REDELIVER_INTENT:与START_STICKY唯一不同的是,回调onStartCommand(…)方法时,其中的Intent将是非空,将是最后一次调用startService(…)中的intent。
START_STICKY_COMPATIBILITY:compatibility version of {@link #START_STICKY} that does not guarantee that {@link #onStartCommand} will be called again after being killed。此值一般不会使用,所以注意前面三种情形就好。
以上的描述中,”当Service因为内存不足而被系统kill后“一定要非常注意,因为此函数的返回值设定只是针对此种情况才有意义的,换言之,当认为的kill掉Service进程,此函数返回值无论怎么设定,接下来未来的某个时间内,即使系统内存足够可用,Service也不会重启。
小米手机针对此处做了变更:
另外,需要注意的是,小米手机针对此处做了一定的修改。在“自启动管理”中有一个自启动应用列表,默认情况下,只有少应用(如微信、QQ、YY、360等)默认是可以自启动的,其他应用默认都是禁止的。用户可以手动添加自启动应用,添加后的应用中如果Started Service onStartCommand(…)回调返回值是START_STICKY或START_REDELIVER_INTENT,当用户在小米手机上长按Home键结束App后,接下来未来的某个时间内,当系统内存足够可用时,Service依然可以按照上述规定重启。当然,如果用户在 设置 >> 应用 >> 强制kill掉App进程,此时Service是不会重启的。
注:以上实验结论基于小米2S亲测。
3) Started Service生命周期及进程相关
1.onCreate(Client首次startService(..)) >> onStartCommand >> onStartCommand - optional … >> onDestroy(Client调用stopService(..))
注:onStartCommand(..)可以多次被调用,onDestroy()与onCreate()想匹配,当用户强制kill掉进程时,onDestroy()是不会执行的。
2.对于同一类型的Service,Service实例一次永远只存在一个,而不管Client是否是相同的组件,也不管Client是否处于相同的进程中。
3.Service通过startService(..)启动Service后,此时Service的生命周期与Client本身的什么周期是没有任何关系的,只有Client调用stopService(..)或Service本身调用stopSelf(..)才能停止此Service。当然,当用户强制kill掉Service进程或系统因内存不足也可能kill掉此Service。
4.Client A 通过startService(..)启动Service后,可以在其他Client(如Client B、Client C)通过调用stopService(..)结束此Service。
5.Client调用stopService(..)时,如果当前Service没有启动,也不会出现任何报错或问题,也就是说,stopService(..)无需做当前Service是否有效的判断。
6.startService(Intent serviceIntent),其中的intent既可以是显式Intent,也可以是隐式Intent,当Client与Service同处于一个App时,一般推荐使用显示Intent。当处于不同App时,只能使用隐式Intent。
当Service需要运行在单独的进程中,AndroidManifest.xml声明时需要通过android:process指明此进程名称,当此Service需要对其他App开放时,android:exported属性值需要设置为true(当然,在有intent-filter时默认值就是true)。
1 <service 2 android:name=".MyService" 3 android:exported="true" 4 android:process=":MyCorn" > 5 <intent-filter> 6 <action android:name="com.example.androidtest.myservice" /> 7 </intent-filter> 8 </service>
4)Started Service Client与Service通信相关
当Client调用startService(Intent serviceIntent)启动Service时,Client可以将参数通过Intent直接传递给Service。Service执行过程中,如果需要将参数传递给Client,一般可以通过借助于发送广播的方式(此时,Client需要注册此广播)。
3.Bound Service
相对于Started Service,Bound Service具有更多的知识点。Bound Service的主要特性在于Service的生命周期是依附于Client的生命周期的,当Client不存在时,Bound Service将执行onDestroy,同时通过Service中的Binder对象可以较为方便进行Client-Service通信。Bound Service一般使用过程如下:
1.自定义Service继承基类Service,并重写onBind(Intent intent)方法,此方法中需要返回具体的Binder对象;
2.Client通过实现ServiceConnection接口来自定义ServiceConnection,并通过bindService (Intent service, ServiceConnection sc, int flags)方法将Service绑定到此Client上;
3.自定义的ServiceConnection中实现onServiceConnected(ComponentName name, IBinder binder)方法,获取Service端Binder实例;
4.通过获取的Binder实例进行Service端其他公共方法的调用,以完成Client-Service通信;
5.当Client在恰当的生命周期(如onDestroy等)时,此时需要解绑之前已经绑定的Service,通过调用函数unbindService(ServiceConnection sc)。
在Bound Service具体使用过程中,根据onBind(Intent intent)方法放回的Binder对象的定义方式不同,又可以将其分为以下三种方式,且每种方式具有不同的特点和适用场景:
1).Extending the Binder class
这是Bound Service中最常见的一种使用方式,也是Bound Service中最简单的一种。
局限:Clinet与Service必须同属于同一个进程,不能实现进程间通信(IPC)。否则则会出现类似于“android.os.BinderProxy cannot be cast to xxx”错误。
下面通过代码片段看下具体的使用:
1 public class MyBindService extends Service { 2 3 public static final String TAG = "MyBindService"; 4 5 private MyBinder mBinder = new MyBinder(); 6 7 public class MyBinder extends Binder { 8 MyBindService getService() { 9 return MyBindService.this; 10 } 11 } 12 13 @Override 14 public void onCreate() { 15 super.onCreate(); 16 Log.w(TAG, "in onCreate"); 17 } 18 19 @Override 20 public IBinder onBind(Intent intent) { 21 Log.w(TAG, "in onBind"); 22 return mBinder; 23 } 24 25 @Override 26 public boolean onUnbind(Intent intent) { 27 Log.w(TAG, "in onUnbind"); 28 return super.onUnbind(intent); 29 } 30 31 @Override 32 public void onDestroy() { 33 super.onDestroy(); 34 Log.w(TAG, "in onDestroy"); 35 } 36 }
1 public class BActivity extends Activity { 2 3 public static final String TAG = "BActivity"; 4 5 private Button bindServiceBtn; 6 private Button unbindServiceBtn; 7 8 private Button startIntentService; 9 10 private Intent serviceIntent; 11 12 private ServiceConnection sc = new MyServiceConnection(); 13 private MyBinder mBinder; 14 private MyBindService mBindService; 15 private boolean mBound; 16 17 private class MyServiceConnection implements ServiceConnection { 18 19 @Override 20 public void onServiceConnected(ComponentName name, IBinder binder) { 21 Log.w(TAG, "in MyServiceConnection onServiceConnected"); 22 mBinder = (MyBinder) binder; 23 mBindService = mBinder.getService(); 24 25 mBound = true; 26 } 27 28 @Override 29 public void onServiceDisconnected(ComponentName name) { 30 // This is called when the connection with the service has been 31 // unexpectedly disconnected -- that is, its process crashed. 32 Log.w(TAG, "in MyServiceConnection onServiceDisconnected"); 33 mBound = false; 34 } 35 36 } 37 38 @Override 39 protected void onCreate(Bundle savedInstanceState) { 40 super.onCreate(savedInstanceState); 41 setContentView(R.layout.b); 42 43 bindServiceBtn = (Button) findViewById(R.id.bind_service); 44 unbindServiceBtn = (Button) findViewById(R.id.unbind_service); 45 startIntentService = (Button) findViewById(R.id.start_intentservice); 46 47 bindServiceBtn.setOnClickListener(new View.OnClickListener() { 48 @Override 49 public void onClick(View v) { 50 Intent intent = new Intent(BActivity.this, MyBindService.class); 51 bindService(intent, sc, Context.BIND_AUTO_CREATE); 52 } 53 }); 54 55 unbindServiceBtn.setOnClickListener(new View.OnClickListener() { 56 @Override 57 public void onClick(View v) { 58 excuteUnbindService(); 59 } 60 }); 61 62 startIntentService.setOnClickListener(new View.OnClickListener() { 63 @Override 64 public void onClick(View v) { 65 Intent intent = new Intent(BActivity.this, MyIntentService.class); 66 startService(intent); 67 } 68 }); 69 70 } 71 72 private void excuteUnbindService() { 73 if (mBound) { 74 unbindService(sc); 75 mBound = false; 76 } 77 } 78 79 @Override 80 protected void onDestroy() { 81 super.onDestroy(); 82 Log.w(TAG, "in onDestroy"); 83 excuteUnbindService(); 84 } 85 }
首次点击bindServiceBtn进行bindService(..)时,依次回调顺序如下:
1 MyBindService(13457): in onCreate 2 MyBindService(13457): in onBind 3 BActivity(13457): in MyServiceConnection onServiceConnected
再次点击bindServiceBtn按钮时,发现没有任何输出,说明MyBindService没有进行任何回调。
点击unbindServiceBtn进行unbindService(..)时,回调顺序为:
1 MyBindService(13457): in onUnbind 2 MyBindService(13457): in onDestroy
注:在四大基本组件中,需要注意的的是BroadcastReceiver不能作为Bound Service的Client,因为BroadcastReceiver的生命周期很短,当执行完onReceive(..)回调时,BroadcastReceiver生命周期完结。而Bound Service又与Client本身的生命周期相关,因此,Android中不允许BroadcastReceiver去bindService(..),当有此类需求时,可以考虑通过startService(..)替代。
2)Using a Messenger
Messenger,在此可以理解成”信使“,通过Messenger方式返回Binder对象可以不用考虑Clinet - Service是否属于同一个进程的问题,并且,可以实现Client - Service之间的双向通信。极大方便了此类业务需求的实现。
局限:不支持严格意义上的多线程并发处理,实际上是以队列去处理
下面直接看下具体的使用:
1 public class MyMessengerService extends Service { 2 3 public static final String TAG = "MyMessengerService"; 4 5 public static final int MSG_FROM_CLIENT_TO_SERVER = 1; 6 public static final int MSG_FROM_SERVER_TO_CLIENT = 2; 7 8 private Messenger mClientMessenger; 9 private Messenger mServerMessenger = new Messenger(new ServerHandler()); 10 11 @Override 12 public IBinder onBind(Intent intent) { 13 Log.w(TAG, "in onBind"); 14 return mServerMessenger.getBinder(); 15 } 16 17 class ServerHandler extends Handler { 18 @Override 19 public void handleMessage(Message msg) { 20 Log.w(TAG, "thread name:" + Thread.currentThread().getName()); 21 switch (msg.what) { 22 case MSG_FROM_CLIENT_TO_SERVER: 23 Log.w(TAG, "receive msg from client"); 24 mClientMessenger = msg.replyTo; 25 26 // service发送消息给client 27 Message toClientMsg = Message.obtain(null, MSG_FROM_SERVER_TO_CLIENT); 28 try { 29 Log.w(TAG, "server begin send msg to client"); 30 mClientMessenger.send(toClientMsg); 31 } catch (RemoteException e) { 32 e.printStackTrace(); 33 } 34 break; 35 default: 36 super.handleMessage(msg); 37 } 38 } 39 } 40 41 @Override 42 public boolean onUnbind(Intent intent) { 43 Log.w(TAG, "in onUnbind"); 44 return super.onUnbind(intent); 45 } 46 47 @Override 48 public void onDestroy() { 49 Log.w(TAG, "in onDestroy"); 50 super.onDestroy(); 51 } 52 }
1 public class CActivity extends Activity { 2 3 public static final String TAG = "CActivity"; 4 5 private Button bindServiceBtn; 6 private Button unbindServiceBtn; 7 private Button sendMsgToServerBtn; 8 9 private ServiceConnection sc = new MyServiceConnection(); 10 private boolean mBound; 11 12 private Messenger mServerMessenger; 13 14 private Handler mClientHandler = new MyClientHandler(); 15 private Messenger mClientMessenger = new Messenger(mClientHandler); 16 17 private class MyClientHandler extends Handler { 18 @Override 19 public void handleMessage(Message msg) { 20 if (msg.what == MyMessengerService.MSG_FROM_SERVER_TO_CLIENT) { 21 Log.w(TAG, "reveive msg from server"); 22 } 23 } 24 } 25 26 private class MyServiceConnection implements ServiceConnection { 27 28 @Override 29 public void onServiceConnected(ComponentName name, IBinder binder) { 30 Log.w(TAG, "in MyServiceConnection onServiceConnected"); 31 mServerMessenger = new Messenger(binder); 32 33 mBound = true; 34 } 35 36 @Override 37 public void onServiceDisconnected(ComponentName name) { 38 // This is called when the connection with the service has been 39 // unexpectedly disconnected -- that is, its process crashed. 40 Log.w(TAG, "in MyServiceConnection onServiceDisconnected"); 41 42 mBound = false; 43 } 44 } 45 46 @Override 47 protected void onCreate(Bundle savedInstanceState) { 48 super.onCreate(savedInstanceState); 49 setContentView(R.layout.c); 50 51 bindServiceBtn = (Button) findViewById(R.id.bind_service); 52 unbindServiceBtn = (Button) findViewById(R.id.unbind_service); 53 sendMsgToServerBtn = (Button) findViewById(R.id.send_msg_to_server); 54 55 bindServiceBtn.setOnClickListener(new View.OnClickListener() { 56 @Override 57 public void onClick(View v) { 58 Intent intent = new Intent(CActivity.this, MyMessengerService.class); 59 bindService(intent, sc, Context.BIND_AUTO_CREATE); 60 } 61 }); 62 63 unbindServiceBtn.setOnClickListener(new View.OnClickListener() { 64 @Override 65 public void onClick(View v) { 66 excuteUnbindService(); 67 } 68 }); 69 70 sendMsgToServerBtn.setOnClickListener(new View.OnClickListener() { 71 @Override 72 public void onClick(View v) { 73 sayHello(); 74 } 75 }); 76 77 new Handler().postDelayed(new Runnable() { 78 @Override 79 public void run() { 80 Intent intent = new Intent(CActivity.this, MyAlarmBroadcastReceiver.class); 81 sendBroadcast(intent); 82 } 83 }, 3 * 1000); 84 85 } 86 87 public void sayHello() { 88 if (!mBound) 89 return; 90 // Create and send a message to the service, using a supported 'what' value 91 Message msg = Message.obtain(null, MyMessengerService.MSG_FROM_CLIENT_TO_SERVER, 0, 0); 92 // 通过replyTo把client端的Messenger(信使)传递给service 93 msg.replyTo = mClientMessenger; 94 try { 95 mServerMessenger.send(msg); 96 } catch (RemoteException e) { 97 e.printStackTrace(); 98 } 99 } 100 101 private void excuteUnbindService() { 102 if (mBound) { 103 unbindService(sc); 104 mBound = false; 105 } 106 } 107 108 @Override 109 protected void onDestroy() { 110 super.onDestroy(); 111 Log.w(TAG, "in onDestroy"); 112 excuteUnbindService(); 113 } 114 }
其中,需要注意的几点是:
1.MyMessengerService自定中,通过new Messenger(new ServerHandler())创建Messenger对象,在onBind(..)回调中,通过调用Messenger对象的getBinder()方法,将Binder返回;
2.Client在ServiceConnection的onServiceConnected(..)的回调中,通过new Messenger(binder)获取到Service传递过来的mServerMessenger;
3.接下来,就可以通过mServerMessenger.send(msg)方法向Service发送message,Service中的Messenger构造器中的Handler即可接收到此信息,在handleMessage(..)回调中处理;
4.至此只是完成了从Client发送消息到Service,同样的道理,想实现Service发送消息到Client,可以在客户端定义一个Handler,并得到相应的Messenger,在Clinet发送消息给Service时,通过msg.replyTo = mClientMessenger方式将Client信使传递给Service;
5.Service接收到Client信使后,获取此信使,并通过mClientMessenger.send(toClientMsg)方式将Service消息发送给Client。
至此,完成了Client - Service之间的双向通信流程。
3).AIDL(Android Interface Definition Language)
一般情况下,Messenger这种方式都是可以满足需求的,当然,通过自定义AIDL方式相对更加灵活。
这种方式需要自己在项目中自定义xxx.aidl文件,然后系统会自动在gen目录下生成相应的接口类文件,接下来整个的流程与Messenger方式差别不大,网上也有不少实例,在此不再具体给出。
注:无论哪种方式的Bound Service,在进行unbind(..)操作时,都需要注意当前Service是否处于已经绑定状态,否则可能会因为当前Service已经解绑后继续执行unbind(..)会导致崩溃。这点与Started Service区别很大(如前文所述:stopService(..)无需做当前Service是否有效的判断)。
4.Local Service VS Remote Service
Local Service:不少人又称之为”本地服务“,是指Client - Service同处于一个进程;
Remote Service:又称之为”远程服务“,一般是指Service处于单独的一个进程中。
其他使用上上文中基本上都有所述。
5.Service特性
1.Service本身都是运行在其所在进程的主线程(如果Service与Clinet同属于一个进程,则是运行于UI线程),但Service一般都是需要进行”长期“操作,所以经常写法是在自定义Service中处理”长期“操作时需要新建线程,以免阻塞UI线程或导致ANR;
2.Service一旦创建,需要停止时都需要显示调用相应的方法(Started Service需要调用stopService(..)或Service本身调用stopSelf(..), Bound Service需要调用unbindService(..)),否则对于Started Service将处于一直运行状态,对于Bound Service,当Client生命周期结束时也将因此问题。也就是说,Service执行完毕后,必须人为的去停止它。
6.IntentService
IntentService是系统提供给我们的一个已经继承自Service类的特殊类,IntentService特殊性是相对于Service本身的特性而言的:
1.默认直接实现了onBind(..)方法,直接返回null,并定义了抽象方法onHandlerIntent(..),用户自定义子类时,需要实现此方法;
2.onHandlerIntent(..)主要就是用来处于相应的”长期“任务的,并且已经自动在新的线程中,用户无语自定义新线程;
3.当”长期“任务执行完毕后(也就是onHandlerIntent(..)执行完毕后),此IntentService将自动结束,无需人为调用方法使其结束;
4.IntentService处于任务时,也是按照队列的方式一个个去处理,而非真正意义上的多线程并发方式。
下面是一个基本的继承自IntentService的自定义Service:
1 public class MyIntentService extends IntentService { 2 3 public static final String TAG = "MyIntentService"; 4 5 public MyIntentService() { 6 super(TAG); 7 } 8 9 public MyIntentService(String name) { 10 super(name); 11 } 12 13 @Override 14 protected void onHandleIntent(Intent intent) { 15 Log.w(TAG, "in onHandleIntent"); 16 Log.w(TAG, "thread name:" + Thread.currentThread().getName()); 17 } 18 19 }
7.前台Service
Android中Service接口中还提供了一个称之为”前台Service“的概念。通过Service.startForeground (int id, Notification notification)方法可以将此Service设置为前台Service。在UI显示上,notification将是一个处于onGoing状态的通知,使得前台Service拥有更高的进程优先级,并且Service可以直接notification通信。
下面是一个简单的前台Service使用实例:
1 public class MyService extends Service { 2 3 public static final String TAG = "MyService"; 4 5 @Override 6 public IBinder onBind(Intent intent) { 7 return null; 8 } 9 10 @Override 11 public void onCreate() { 12 super.onCreate(); 13 Log.w(TAG, "in onCreate"); 14 } 15 16 @Override 17 public int onStartCommand(Intent intent, int flags, int startId) { 18 Log.w(TAG, "in onStartCommand"); 19 Log.w(TAG, "MyService:" + this); 20 String name = intent.getStringExtra("name"); 21 Log.w(TAG, "name:" + name); 22 23 24 Notification notification = new Notification(R.drawable.ic_launcher, "test", System.currentTimeMillis()); 25 Intent notificationIntent = new Intent(this, DActivity.class); 26 PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntesnt, 0); 27 notification.setLatestEventInfo(this, "title", "content", pendingIntent); 28 startForeground(1, notification); 29 30 31 return START_REDELIVER_INTENT; 32 } 33 34 @Override 35 public void onDestroy() { 36 super.onDestroy(); 37 Log.w(TAG, "in onDestroy"); 38 } 39 }
</div>
<div class = "postDesc">posted @ <span id="post-date">2014-12-23 21:51</span> <a href='http://www.cnblogs.com/lwbqqyumidi/'>Windstep</a> 阅读(<span id="post_view_count">...</span>) 评论(<span id="post_comment_count">...</span>) <a href ="https://i.cnblogs.com/EditPosts.aspx?postid=4181185" rel="nofollow">编辑</a> <a href="#" onclick="AddToWz(4181185);return false;">收藏</a></div>
</div>
<script type="text/javascript">var allowComments=true,cb_blogId=122301,cb_entryId=4181185,cb_blogApp=currentBlogApp,cb_blogUserGuid='e6cf342b-cfcb-e111-aa3f-842b2b196315',cb_entryCreatedDate='2014/12/23 21:51:00';loadViewCount(cb_entryId);</script>