什么是Service:
可以长时间运行在后台的不可见的没有界面的组件
运行在主线程中
可以跨进程调用
为什么要使用service
因为service是Android中实现程序后台运行的解决方案,非常适合那些不需要与用户进行交互且需要长期运行的任务。
service启动方式有哪些
startService和bindService两种
使用startservice启动服务
1.新建类继承Service
public class MyService extends Service {
2.重写onCreate(),用来数据的初始化,在服务没有停止之前,只会执行一次
public void onCreate() {
super.onCreate();
Log.e(TAG+Thread.currentThread().toString(), "onCreate: " );
}
3.重写onStartCommand(),用来接收调用者传递过来的参数,可以编写需要的逻辑代码
当重复调用Service时,会重复执行
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
4.实现onBind()方法
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
Log.e(TAG, "onBind: " );
throw new UnsupportedOperationException("Not yet implemented");
//return mBinder;
}
5.重写onDestroy(),做释放资源的操作
public void onDestroy() {
super.onDestroy();
Log.e(TAG, "onDestroy: " );
}
6.注册Service(在创建时会帮你实现)
<service
android:name=".MyService"
android:enabled="true"
android:exported="true"></service>
7.在context环境中通过startService启动Service
startIntent = new Intent(MainActivity.this,MyService.class);
this.startService(startIntent);
8.在context环境中通过stopService停止Service
this.stopService(startIntent);
实例讲解:
效果展现:点击启动服务和停止服务两次
可以看到虽然我点击了启动服务两次,但是,只执行了onCreate一次,但onStartCommand执行了两次,还有就是我点击了两次停止服务,但只执行了一次onDestroy方法,这原因我在介绍Service已经说过了,还可以看到的是,当服务停止时,线程并没有停止,这是因为子线程必须要执行完才会停止,不受服务关闭的影响,因为我在打印时同时打印了线程名,于是你可以看到,启动子线程的两个名字并不一样,且两个子线程各干各的,互不干扰
代码实现步骤:
1.在布局文件中完成控件的添加和id的设置,三四按钮暂时用不到
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.example.administrator.servicetest.MainActivity">
<EditText
android:id="@+id/main_et"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:text=""
android:gravity="center"
android:textSize="30sp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/main_tv"/>
<Button
android:id="@+id/main_start_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="启动服务" />
<Button
android:id="@+id/main_stop_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="停止服务" />
<Button
android:id="@+id/main_bind_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="绑定服务" />
<Button
android:id="@+id/main_unbind_btn"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="取消绑定服务" />
</LinearLayout>
2.创建自定义类继承Service重写方法
public class MyService extends Service {
private static final String TAG = "MyService";
public MyService() {
}
//重写onCreate(),打印
@Override
public void onCreate() {
super.onCreate();
Log.e(TAG+Thread.currentThread().toString(), "onCreate: " );
}
//重写onStartCommand,打印,在里面写一个子线程,实现倒计时功能
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.e(TAG, "onStartCommand: " );
new Thread(new Runnable() {
@Override
public void run() {
for(int i=10;i>=0;i--){
Log.e(TAG+Thread.currentThread().toString(), "run: "+"----"+i);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
return super.onStartCommand(intent, flags, startId);
}
//重写onBind()方法
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
Log.e(TAG, "onBind: " );
throw new UnsupportedOperationException("Not yet implemented");
// return mBinder;
}
// private DownloadBinder mBinder = new DownloadBinder();
// class DownloadBinder extends Binder{
//
// public void startDownload (){
// Log.e(TAG, "startDownload: " );
//
// }
// public int getProgress(){
// Log.e(TAG, "getProgress: " );
// return 0;
// }
//
// }
//重写onDestroy()
@Override
public void onDestroy() {
super.onDestroy();
Log.e(TAG, "onDestroy: " );
}
}
在context环境启动服务
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button startBtn;
private Button stopBtn;
private Button bindBtn;
private Button unBindBtn;
private EditText editText;
private TextView textView;
private Intent startIntent;
// private MyService.DownloadBinder downloadBinder ;
// private ServiceConnection connection = new ServiceConnection() {
// @Override
// public void onServiceConnected(ComponentName name, IBinder service) {
// downloadBinder = (MyService.DownloadBinder) service;
// downloadBinder.startDownload();
// downloadBinder.getProgress();
//
// }
//
// @Override
// public void onServiceDisconnected(ComponentName name) {
//
// }
// };
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bangID();
}
private void bangID() {
startBtn = findViewById(R.id.main_start_btn);
stopBtn = findViewById(R.id.main_stop_btn);
bindBtn = findViewById(R.id.main_bind_btn);
unBindBtn = findViewById(R.id.main_unbind_btn);
editText = findViewById(R.id.main_et);
textView = findViewById(R.id.main_tv);
startBtn.setOnClickListener(this);
stopBtn.setOnClickListener(this);
bindBtn.setOnClickListener(this);
unBindBtn.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.main_start_btn:
//启动服务
startIntent = new Intent(MainActivity.this,MyService.class);
this.startService(startIntent);
break;
case R.id.main_stop_btn:
//关闭服务
this.stopService(startIntent);
break;
// case R.id.main_bind_btn:
// Intent bindIntent = new Intent(MainActivity.this,MyService.class);
// this.bindService(bindIntent,connection,BIND_AUTO_CREATE);
// break;
// case R.id.main_unbind_btn:
// unbindService(connection);
// break;
default:
}
}
}
对startservice启动服务的小节:
startservce使用特点:onCreate只会在创建service时执行一次,只要调用startService,onStartCommand一定会执行
startservice启动服务的优点:代码较为简洁,而缺点是,无法很好的控制服务,不能直接调用service中的方法,传值只能通过intent来传递。
使用bindservice启动service
效果展现:
效果分析:可以看到我点击了三次绑定服务,和取消绑定,在打印中可以看到只打印了一段话,那是因为bindservice的特点:onCreate,onBind只会执行一次,这是通过在context环境中创建service对象调用的。
代码实现:
1.首先我们要修改Myservice中的代码
//重写onBind()方法,返回管家对象
@Override
public IBinder onBind(Intent intent) {
Log.e(TAG, "onBind: ");
//throw new UnsupportedOperationException("Not yet implemented");
return guanjia;
}
@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
//创建管家对象
private Guanjia guanjia = new Guanjia();
//使用bindservice启动service,需要在MyService中添加自定义类,继承Binder类,返回MyService.this
//这里相当于创建了一个管家,获得了service的信任,以后就可以在context环境中通过管家获得service对象
class Guanjia extends Binder {
public MyService getServiceObject() {
return MyService.this;
}
}
我还在MyService中添加了一个自定义方法,用以验证bindservice可以直接调用service中的方法
public void printDemo() {
Log.e(TAG, "printDemo: " + "我挥舞着键盘,发誓要将这个世界写的明明白白");
}
2.修改MainActivity中的代码:创建ServiceConnection的匿名内部类,在onServiceConnected()方法及活动与服务成功绑定时调用的方法,通过向下转型onbind()中传过来的service,在调用自定义方法,获得service对象,这样我们就可以为所欲为了,只要有了service的对象,就可以调用service中的public方法
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.e(TAG, "onServiceConnected: " );
MyService myService = ((MyService.Guanjia) service).getServiceObject();
myService.printDemo();
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.e(TAG, "onServiceDisconnected: " );
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Log.e(TAG, "onCreate: "+"++" );
bangID();
}
private void bangID() {
startBtn = findViewById(R.id.main_start_btn);
stopBtn = findViewById(R.id.main_stop_btn);
bindBtn = findViewById(R.id.main_bind_btn);
unBindBtn = findViewById(R.id.main_unbind_btn);
toBBtn = findViewById(R.id.main_to_b_btn);
startBtn.setOnClickListener(this);
stopBtn.setOnClickListener(this);
bindBtn.setOnClickListener(this);
unBindBtn.setOnClickListener(this);
toBBtn.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.main_start_btn:
//启动服务
startIntent = new Intent(MainActivity.this,MyIntentService.class);
this.startService(startIntent);
break;
case R.id.main_stop_btn:
//关闭服务
this.stopService(startIntent);
break;
case R.id.main_bind_btn:
Log.e(TAG, "bindService: " );
//启动绑定服务
bindIntent = new Intent(MainActivity.this,MyService.class);
/**
* param:1:intent对对象
* param2:serviceconnection实例
* param3:标志位,这里意思是自动完成绑定后自动创建服务
*/
this.bindService(bindIntent,connection,BIND_AUTO_CREATE);
break;
case R.id.main_unbind_btn:
Log.e(TAG, "unbindService: " );
//停止绑定
unbindService(connection);
break;
case R.id.main_to_b_btn:
Intent intent = new Intent(this,BActivity.class);
startActivity(intent);
break;
default:
}
}
}
bindservice的特点:onCreate,onBind只会执行一次
使用优点:可以直接操作Service中的属性和方法。
缺点:创建service对象较为复杂
service的补充:IntentService
什么是IntentService
IntentService 是继承于 Service 并处理异步请求的一个类
IntentService的特点:
在 IntentService 内有一个工作线程来处理耗时操作,启动 IntentService 的方式和启动传统 Service 一样,同时,当任务执行完后,IntentService 会自动停止,而不需要我们去手动控制。另外,可以启动 IntentService 多次,而每一个耗时操作会以工作队列的方式在IntentService 的 onHandleIntent 回调方法中执行,并且,每次只会执行一个工作线程,执行完第一个再执行第二个,以此类推
优点:
首先,我们省去了在 Service 中手动开线程的麻烦,第二,当操作完成时,我们不用手动停止 Service
效果展现
效果分析,可以见到我点击了两次启动服务,按照之前的service,一到十的打印应该是互不影响,打印比较乱,可是在这个例子中,却看到子线程是排队打印的。
代码演示:
自定义类继承Intentservice,实现他的几个方法
public class MyIntentService extends IntentService{
private String TAG = "MyIntentService";
/**
* Creates an IntentService. Invoked by your subclass's constructor.
*
* @param name Used to name the worker thread, important only for debugging.
*/
public MyIntentService(String name) {
super(name);
}
//重新建一个默认的构造方法,要没有参数
public MyIntentService(){
super("");
}
//重写onHandleIntent方法,可以看到我们可以直接进行耗时操作,那是因为服务自带子线程
@Override
protected void onHandleIntent(@Nullable Intent intent) {
for(int i = 10;i>=0;i--){
Log.e(TAG, "onHandleIntent: " +i);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
最后添加执行语句就可以了。
public void onClick(View v) {
switch (v.getId()) {
case R.id.main_start_btn:
//启动服务
startIntent = new Intent(MainActivity.this,MyIntentService.class);
this.startService(startIntent);
break;
case R.id.main_stop_btn:
//关闭服务
this.stopService(startIntent);
break;
最后我们来总结一下IntentService和Servce的区别:
service:Service 不是一个单独的进程,它和应用程序在同一个进程中,Service 也不是一个线程,它和线程没有任何关系,所以它不能直接处理耗时操作。如果有耗时操作就必须开启一个单独的线程来处理
IntentService: 是继承于 Service 并处理异步请求的一个类,在 IntentService 内有一个工作线程来处理耗时操作,启动 IntentService 的方式和启动传统 Service 一样,同时,当任务执行完后,IntentService 会自动停止,而不需要我们去手动控制。另外,可以启动 IntentService 多次,而每一个耗时操作会以工作队列的方式在IntentService 的 onHandleIntent 回调方法中执行,并且,每次只会执行一个工作线程,执行完第一个再执行第二个,以此类推