提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
Service分为两种:一种是普通的Service,一种是IntentService。
启动Service的方式也有两种:一种是StartService()启动,一种是BindService()启动。本文重点介绍两种Service的区别和两种启动方式的区别。
本文主要是代码居多,通过代码运行的log打印,观察service的生命周期和特性来达到理解service的目的
一、startservice启动service
启动:
it = new Intent(MainActivity.this, StartFiring.class);
startService(it);
关闭:stopService(it);
StartFiring.java
public class StartFiring extends Service {
public StartFiring() {
}
//该方法是Service都必须实现的方法,该方法会返回一个 IBinder对象,app通过该对象与Service组件进行通信!
//不需要通信时不会调用此方法
@Override
public IBinder onBind(Intent intent) {
Log.d("StartFiring", "onBind()");
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
//当Service第一次被创建后立即回调该方法,该方法在整个生命周期 中只会调用一次!
@Override
public void onCreate() {
super.onCreate();
Log.d("StartFiring", "onCreate()");
}
// 1.使用startService启动servic时调用
// 2.多次使用startService启动servic时,不会创建新的Service对象(也就是不会多次调用onCreate方法),但是会多次调用onStartCommand()方法
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("StartFiring", "onStartCommand()");
return super.onStartCommand(intent, flags, startId);
}
//当Service被关闭时会回调该方法,该方法只会回调一次!
@Override
public void onDestroy() {
Log.d("StartFiring", "onDestroy()");
super.onDestroy();
}
}
二、bindservice启动service
bindservice启动稍微复杂一点,直接上代码,文章最后会有对比总结
MainActivity.java
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private TextView bt;
private TextView bt2;
private TextView bt3;
private Intent it = null;
MyService.MyBinder binder;
private ServiceConnection conn = new ServiceConnection() {
//Service服务被意外销毁时调用,如内存资源不足
@Override
public void onServiceDisconnected(ComponentName name) {
Log.d("MainActivity", "onServiceDisconnected()断开连接");
}
//Activity与Service连接成功时回调该方法
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.d("MainActivity", "onServiceConnected()连接成功");
binder = (MyService.MyBinder) service; //获取servicer的数据
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
bt = (TextView) findViewById(R.id.bt);
bt2 = (TextView) findViewById(R.id.bt2);
bt3 = (TextView) findViewById(R.id.tex);
bt3.setOnClickListener(this);
bt.setOnClickListener(this);
bt2.setOnClickListener(this);
it = new Intent(MainActivity.this, MyService.class);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bt:
//绑定service
bindService(it, conn, Service.BIND_AUTO_CREATE);
break;
case R.id.bt2:
//解除绑定
unbindService(conn);
break;
case R.id.tex:
Log.d("MainActivity", "count值为:" + binder.getCount());
break;
}
}
MyService.java
public class MyService extends Service {
private int count;
private boolean quit = true;
/*
1.自定义一个内部类继承Binder,类中定义读取service数据的方法,将servie要传递给activity的数据放入Binder对象中
2.创建内部类对象,onBind方法返回这个对象
3.activity中通过ServiceConnection的回调方法onServiceConnected()拿到service传递的binder对象
4.activity调用binder对象中的方法读取servie传递的数据
*/
//自定义一个内部类继承Binder,类中定义读取service数据的方法,将
public class MyBinder extends Binder {
//定义读取service数据的方法
public int getCount() {
return count;
}
}
private MyBinder binder = new MyBinder();
//与activity交互,返回给activity一个IBinder对象
//
@Override
public IBinder onBind(Intent intent) {
Log.d("MyService", "onBind()");
return binder;
}
@Override
public void onCreate() {
super.onCreate();
Log.d("MyService", "onCreate()");
new Thread() {
public void run() {
while (quit) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
count++;
}
}
}.start();
}
@Override
public void onDestroy() {
Log.d("MyService", "onDestroy()");
super.onDestroy();
}
@Override
public boolean onUnbind(Intent intent) {
quit = false;
Log.d("MyService", "onUnbind()");
return super.onUnbind(intent);
}
@Override
public void onRebind(Intent intent) {
super.onRebind(intent);
Log.d("MyService", "onRebind()");
}
}
三、Intentservice
MainActivity.java :做了三个启动按钮,每个启动携带的参数不一样,更直观的看到Intentservice的生命周期
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button bt;
private Button tex;
private Button bt2;
private Intent it = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
bt = (Button) findViewById(R.id.bt);
tex = (Button) findViewById(R.id.tex);
bt2 = (Button) findViewById(R.id.bt2);
bt.setOnClickListener(this);
tex.setOnClickListener(this);
bt2.setOnClickListener(this);
it = new Intent(this, MyIntentService.class);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bt:
Bundle bd = new Bundle();
bd.putString("a", "a");
it.putExtras(bd);
startService(it);
break;
case R.id.tex:
Bundle bd2 = new Bundle();
bd2.putString("a", "b");
it.putExtras(bd2);
startService(it);
break;
case R.id.bt2:
Bundle bd3 = new Bundle();
bd3.putString("a", "c");
it.putExtras(bd3);
startService(it);
break;
}
}
}
MyIntentService.java :可通过Intent传递的不同数据执行不同的代码块
public class MyIntentService extends IntentService {
//必须实现父类的构造方法
public MyIntentService() {
super("MyIntentService");
}
//必须重写的核心方法,通过activity传递的intent数据执行不同的代码
@Override
protected void onHandleIntent(Intent intent) {
Log.d("MyIntentService", "onHandleIntent");
String actin = intent.getExtras().getString("a");
if (actin.equals("a")) {
Log.d("MyIntentService", "第一个启动按钮");
new Thread(new Runnable() {
@Override
public void run() {
//执行具体事务
try {
Thread.sleep(10000);
Log.d("MyIntentService", "Thread1停止");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
} else if (actin.equals("b")) {
Log.d("MyIntentService", "第二个启动按钮");
new Thread(new Runnable() {
@Override
public void run() {
//执行具体事务
try {
Thread.sleep(10000);
Log.d("MyIntentService", "Thread2停止");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
} else if (actin.equals("c")) {
Log.d("MyIntentService", "第三个启动按钮");
new Thread(new Runnable() {
@Override
public void run() {
//执行具体事务
try {
Thread.sleep(10000);
Log.d("MyIntentService", "Thread3停止");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
} else {
Log.d("MyIntentService", "其他");
}
}
@Override
public IBinder onBind(Intent intent) {
Log.d("MyIntentService", "onBind");
return super.onBind(intent);
}
@Override
public void onCreate() {
Log.d("MyIntentService", "onCreate");
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("MyIntentService", "onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void setIntentRedelivery(boolean enabled) {
super.setIntentRedelivery(enabled);
Log.d("MyIntentService", "setIntentRedelivery");
}
@Override
public void onDestroy() {
Log.d("MyIntentService", "onDestroy");
super.onDestroy();
}
}
四、Intentservice和全局变量结合使用
首先MainActivity还是与上文Intentservice一样三个启动按钮,每个启动按钮启动携带不同的参数,创建一个Handler和计时器定时读取全局变量的值
然后创建一个实体类:EntityTest.java
public class EntityTest{
public static int a = 0;
public static int b = 0;
public static int c = 0;
}
最后是Intentservice中的核心代码(部分需要重写的方法没有贴上)
public class MyIntentService extends IntentService {
private boolean x = true;
private boolean m = true;
private boolean y = true;
//必须实现父类的构造方法
public MyIntentService() {
super("MyIntentService");
}
//必须重写的核心方法,通过activity传递的intent数据执行不同的代码
@Override
protected void onHandleIntent(Intent intent) {
Log.d("MyIntentService", "onHandleIntent");
String actin = intent.getExtras().getString("a");
if (actin.equals("a")) {
Log.d("MyIntentService", "第一个启动按钮");
new Thread(new Runnable() {
@Override
public void run() {
//执行具体事务
while (x) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
MyBinder.a++;
if (MyBinder.a == 20) {
x = false;
}
}
}
}).start();
} else if (actin.equals("b")) {
Log.d("MyIntentService", "第二个启动按钮");
new Thread(new Runnable() {
@Override
public void run() {
//执行具体事务
while (m) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
MyBinder.b++;
if (MyBinder.b == 20) {
m = false;
}
}
}
}).start();
} else if (actin.equals("c")) {
Log.d("MyIntentService", "第三个启动按钮");
new Thread(new Runnable() {
@Override
public void run() {
//执行具体事务
while (y) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
MyBinder.c++;
if (MyBinder.c == 20) {
y = false;
}
}
}
}).start();
} else {
Log.d("MyIntentService", "其他");
}
}
@Override
public IBinder onBind(Intent intent) {
Log.d("MyIntentService", "onBind");
return null;
}
}
五、前台服务的实现
前台服务启动和关闭同样与讲解的启动方式一样,这里贴一下service的代码
MyService.java
public class MyService extends Service {
String id = "logcat";
String name = null;
NotificationManager ntmg = null;
NotificationChannel notcl;
NotificationCompat.Builder bud;
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
//当Service第一次被创建后立即回调该方法,该方法在整个生命周期 中只会调用一次!
@Override
public void onCreate() {
super.onCreate();
Log.d("StartFiring", "onCreate()");
//发送log打开的通知
name = getString(R.string.app_name);
ntmg = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
// 1.创建NotificationChannel对象,传入id name 和 重要级别
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
notcl = new NotificationChannel(id, name, NotificationManager.IMPORTANCE_HIGH);
// 2.创建通知的通道
ntmg.createNotificationChannel(notcl);
}
Intent intents = new Intent(MyService.this, MainActivity.class);
PendingIntent pits = PendingIntent.getActivity(MyService.this, 0, intents, 0);
bud = new NotificationCompat.Builder(MyService.this, id);
bud.setContentTitle("前台service服务端")
.setContentText("正在运行...")
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.mipmap.ic_launcher)
.setLargeIcon(BitmapFactory.decodeResource(MyService.this.getResources(), R.drawable.ic_launcher_foreground))
.setContentIntent(pits);
//发送通知( id唯一,可用于更新通知时对应旧通知; 通过mBuilder.build()拿到notification对象 )
startForeground(1,bud.build());
ntmg.notify(1, bud.build());
}
// 1.使用startService启动servic时调用
// 2.多次使用startService启动servic时,不会创建新的Service对象(也就是不会多次调用onCreate方法),但是会多次调用onStartCommand()方法
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("StartFiring", "onStartCommand()");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
Log.d("StartFiring", "onDestroy()");
super.onDestroy();
}
}
六、后台服务的实现
同样只贴service核心代码,以下代码执行流程:在activity中打开一次service,进入到service后执行具体的事物,并且间隔两秒发送一个广播,收到广播后再次自动启动service,如此形成循环,涉及到广播的内容下一篇讲解
/*
手动打开一次线程后,执行具体的事务,然后间隔2秒进入广播,进入广播后在广播中再次启动线程,如此形成循环操作
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//这里开辟一条线程,用来执行具体的逻辑操作:
new Thread(new Runnable() {
@Override
public void run() {
//循环执行的事务
Log.d("BackService", new Date().toString());
}
}).start();
manager = (AlarmManager) getSystemService(ALARM_SERVICE);
//设置循环时间,每隔两秒循环一次
int anHour = 2 * 1000;
long triggerAtTime = SystemClock.elapsedRealtime() + anHour;
Intent i = new Intent(this, MyReceiver.class);
pi = PendingIntent.getBroadcast(this, 0, i, 0);
manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pi);
return super.onStartCommand(intent, flags, startId);
}
总结
startservice启动普通service:无法通信,可以启动多次,多次启动仅执行一次onCreate方法,但执行多次onStartCommand方法
startservice启动IntentService:可通过inten传递数据到service
bindservice启动普通service:颗获取service中的数据,只能启动一次
bindservice启动IntentService:无实际应用
启动IntentService:
1.activity可以通过inten传递数据到service
2.service通过传递过来的不同参数执行不同操作
3.service执行完毕后会自动关闭