讲解Service之前,先了解一下进程优先级
在Android系统中,当系统资源(内存资源)不足时,系统会自动清理一部分应用程序占用的内存,以释放出更多的可用内存空间,运行当前需要执行的应用程序
当系统自动清理应用程序占用的内存时,会按照进程的优先级,从低到高进行清理,即优先级较低的进程则最优先被清理,而优先级较高的则越不容易被清理
进程的优先级,从高到低依次是: 1、前台进程,表现为进程中存在可见并可控的Activity 2、可见进程,表现为进程中存在局部可见却不可控的Activity 3、服务进程,表现为存在正在运行的Service 4、后台进程,表现为该进程中的所有Activity均已被置于后台,即不可见也不可控 5、空进程,表现为已经退出的进程
如果我正在使用QQ,那么QQ属于前台进程,如果回到桌面,就是后台进程,如果直接按返回键退出,那么QQ就是空进程
Service是Android系统的核心组件之一
Service是没有界面的,后台工作(看不见)的类
Service是运行在主线程的,所以,虽然Service适合做长期的任务,但是,也必须开始子线程来完成相关任务
Service是单例的(实例唯一:在同一时间内只存在一个对象)
启动Service 调用startService(Intent)方法即可启动Service
停止Service 1、在Service类以外,调用stopService(intent)方法即可停止Service 2、在Service类内部,调用stopSelf()方法,即可停止当前Service
onCreate():当第一次创建Service对象时被调用 onStartCommand():每次激活Service组件时被调用 onDestroy():销毁服务
栗子1
新增 WorkService
import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.support.annotation.Nullable; import android.util.Log; public class WorkService extends Service { @Override public void onCreate() { super.onCreate(); Log.d("Service","WorkService@"+hashCode()+".onCreate()"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.d("Service","WorkService@"+hashCode()+".onStartCommand()"); return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { Log.d("Service","WorkService@"+hashCode()+".onDestroy()"); super.onDestroy(); } @Nullable @Override public IBinder onBind(Intent intent) { return null; } }在AndroidManifest中注册
<service android:name=".WorkService"/>activity_main布局文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.siliconvalley.xy.sms.MainActivity" android:orientation="vertical"> <Button android:id="@+id/btn_start_service" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="激活Service"/> <Button android:id="@+id/btn_stop_service" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="停止Service"/> </LinearLayout>MainActivity
public class MainActivity extends Activity implements View.OnClickListener{ private Button btnStart; private Button btnStop; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btnStart = (Button) findViewById(R.id.btn_start_service); btnStart.setOnClickListener(this); btnStop = (Button) findViewById(R.id.btn_stop_service); btnStop.setOnClickListener(this); } @Override public void onClick(View v) { Intent intent = new Intent(this, WorkService.class); switch (v.getId()){ case R.id.btn_start_service: startService(intent); break; case R.id.btn_stop_service: stopService(intent); break; } } }Log
当点击激活Service按钮时
WorkService@15788440.onCreate() WorkService@15788440.onStartCommand()再次点击激活Service按钮时
WorkService@15788440.onStartCommand()点击停止Service时
WorkService@15788440.onDestroy()Service可以用于在后台执行的操作,例如检查版本更新,长时间的任务
开始这里的内容之前,你应该知道Activity和Activity之间是如何传递数据的,Intent在Android系统的作用
下面的栗子是根据,上面课程基础上修改的
栗子
写一个WorkServicce,继承Service
注意 写完Service要先注册
<service android:name=".WorkService"/>WorkService
public class WorkService extends Service { @Override public void onCreate() { super.onCreate(); Log.d("Service","WorkService@"+hashCode()+".onCreate()"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { Log.d("Service","WorkService@"+hashCode()+".onStartCommand()"); String u = intent.getStringExtra("_username"); String g = intent.getStringExtra("_gender"); int a = intent.getIntExtra("_age",0); Log.d("Service","姓名:"+u+" 性别:"+g+" 年龄:"+a); return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { super.onDestroy(); Log.d("Service","WorkService@"+hashCode()+".onDestroy()"); } @Nullable @Override public IBinder onBind(Intent intent) { return null; } }activity_main
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context="com.siliconvalley.xy.sms.MainActivity" android:padding="15dp"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="请输入用户名" /> <EditText android:id="@+id/et_username" android:layout_width="match_parent" android:layout_height="wrap_content" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="请选择性别" /> <RadioGroup android:id="@+id/rg_male" android:layout_width="match_parent" android:layout_height="wrap_content"> <RadioButton android:id="@+id/rb_male" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="男" /> <RadioButton android:id="@+id/rb_female" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="女" /> </RadioGroup> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:text="请输入年龄" /> <EditText android:id="@+id/et_age" android:layout_width="match_parent" android:layout_height="wrap_content" android:inputType="number"/> <Button android:id="@+id/btn_submit" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="提交"/> </LinearLayout>MainActivity
public class MainActivity extends Activity implements View.OnClickListener { private EditText etUserName; private RadioButton rbGenderMale; private EditText etAge; private Button btnSubmit; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); etUserName = (EditText) findViewById(R.id.et_username); rbGenderMale = (RadioButton) findViewById(R.id.rb_male); etAge = (EditText) findViewById(R.id.et_age); btnSubmit = (Button) findViewById(R.id.btn_submit); btnSubmit.setOnClickListener(this); } @Override public void onClick(View v) { Toast.makeText(this,"clicked",Toast.LENGTH_SHORT).show(); String username = etUserName.getText().toString().trim(); String gender = rbGenderMale.isChecked()?"男":"女"; int age = Integer.parseInt(etAge.getText().toString()); Intent intent = new Intent(this,WorkService.class); intent.putExtra("_username",username); intent.putExtra("_gender",gender); intent.putExtra("_age",age); startService(intent); } }LOG
姓名:Lily 性别:女 年龄:11其中WorkService的onStartCommand()方法的第一个参数就是Intent直接取值即可
在第一个栗子中,我们点击激活Service按钮,查看Log日志
WorkService@68964290.onCreate() WorkService@68964290.onStartCommand()当我们在DDMS中停掉当前进程
过一会儿之后,发现日志中又多了
WorkService@68964290.onCreate() WorkService@68964290.onStartCommand()Service又回来了
Service的粘性表现为当Service意外终止后,在一定时间后会自动重新启动,根本停不下来…
Service是否粘性,由onStartCommand()方法的返回值决定,取值可以是
Service.START_STICKY–>粘性Service.START_NOT_STICKY–>非粘性Service.START_STICKY_COMPATIBILITY–>兼容模式粘性Service.START_REDELIVER_INTENT–>粘性的,且重启时还拥有此前的Intent数据(重新传递Intent)【小结】 如果希望Service是非粘性的,取值为Service.START_NOT_STICKY 如果希望Service是粘性的,则使用父类方法返回值
如果Service是粘性的,默认情况下,每次自动重启时,并不会携带Intent对象,即自动重启时,第一个参数Intent,为null
例如,第一次启动时
WorkService@76449015.onCreate() WorkService@76449015.onStartCommand(),intent->Intent { cmp=com.siliconvalley.xy.sms/.WorkService }当我们强制关掉进程,当Service重启时,intent变为了null
WorkService@68964290.onCreate() WorkService@68964290.onStartCommand(),intent->null如果希望Service是粘性的,且自动重启时还拥有此前的Intent数据,则取值为Service.START_REDELIVER_INTENT
栗子,我们修改栗子1的代码
激活Service时,我们传递一个值
Intent intent = new Intent(this, WorkService.class); intent.putExtra("date","2018-2-12");WorkService的onStartCommand()方法修改为
@Override public int onStartCommand(Intent intent, int flags, int startId) { Log.d("Service", "WorkService@" + hashCode() + ".onStartCommand(),intent->" + intent); if (intent != null) { Log.d("Service", "date->" + intent.getStringExtra("date")); } else { Log.d("Service", "null"); } return super.onStartCommand(intent, flags, startId); }第一次激活Service的Log
WorkService@76449015.onCreate() WorkService@76449015.onStartCommand(),intent->Intent { cmp=com.siliconvalley.xy.sms/.WorkService (has extras) } date->2018-2-12强制停掉,然后Servce自动重启时
WorkService@68964290.onCreate() WorkService@68964290.onStartCommand(),intent->null null现在把onStartCommand()方法的返回值修改为
return START_REDELIVER_INTENT;第一次激活时Log
WorkService@76449015.onCreate() WorkService@76449015.onStartCommand(),intent->Intent { cmp=com.siliconvalley.xy.sms/.WorkService (has extras) } date->2018-2-12强制停掉,然后Servce自动重启时
WorkService@68964290.onCreate() WorkService@68964290.onStartCommand(),intent->Intent { cmp=com.siliconvalley.xy.sms/.WorkService (has extras) } date->2018-2-12绑定Service是激活Service的一种方式,称之为“绑定模式”
而上面说到的startService是启动Service,是激活Service的一种方式,称之为“启动模式”
绑定模式激活的Service组件,可以用于实现组件间通信
组件->Activity、Service、BroadcastReceiver、ContentProvider 控件->TextView、ImageView 等可操控的view
栗子
1、首先创建WorkService继承Service
public class WorkService extends Service { @Override public void onCreate() { super.onCreate(); Log.d("Service", "WorkService@" + hashCode() + ".onCreate()"); } @Nullable @Override public IBinder onBind(Intent intent) { InnerIBinder binder = new InnerIBinder(); Log.d("Service", "WorkService@" + hashCode() + ".onBind()"); return binder; } private class InnerIBinder extends Binder { } }2、注册Service
<service android:name=".WorkService"/>对代码的一些解释
要想绑定成功,在WorkService中的onBind()方法需要返回一个非null的值 其中IBinder是接口(从名字上也很容易看出来Interface),所以我们写一个内部InnerIBinder来实现这个接口 然而,我们查看IBinder的注释,发现它告诉我们不要直接实现这个接口,而是要extends Binder
activity_main
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.siliconvalley.xy.sms.MainActivity" android:orientation="vertical"> <Button android:id="@+id/btn_bind_service" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="绑定Service"/> </LinearLayout>MainActivity
public class MainActivity extends Activity implements View.OnClickListener { private Button btnBindService; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btnBindService = (Button) findViewById(R.id.btn_bind_service); btnBindService.setOnClickListener(this); } @Override public void onClick(View v) { //绑定Service Intent service = new Intent(this,WorkService.class); ServiceConnection conn = new InnerServiceConnection(); int flags = BIND_AUTO_CREATE;//该取值表示:绑定Service时自动创建Service对象 bindService(service, conn, flags); Log.d("Service","MainActivity.onClick()->使用bindService激活了Service组件"); } private class InnerServiceConnection implements ServiceConnection{ @Override public void onServiceConnected(ComponentName name, IBinder service) { Log.d("Service","MainActivity.onServiceConnected()->当Activity和Service连接好后执行这个方法"); } @Override public void onServiceDisconnected(ComponentName name) { } } }LOG
MainActivity.onClick()->使用bindService激活了Service组件 WorkService@205845759.onCreate() WorkService@205845759.onBind() MainActivity.onServiceConnected()->当Activity和Service连接好后执行这个方法【小结】