首先,Service适合做的事:后台稳定运行不需要界面或不想让人看见的。
Service有两种启动方式:
一. startService :
1.首先,新建一个类,让它继承Service,重写
onCreate( )
onStartCommand(Intent intent, int flags, int startId)
onDestroy( )
这三个方法。别说话,看代码
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
public class MyService extends Service {
public MyService() {
}
@Override
public IBinder onBind(Intent intent) {
// TODO: Return the communication channel to the service.
throw new UnsupportedOperationException("Not yet implemented");
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
}
}
其中,onBind方法是抽象方法,必须实现,这里我们暂时用不上它,onStartCommand方法现在站的位置本来是onStart的,后来onStart被抛弃(过期)了。Service框架已经搭好了,
别忘了在清单文件里注册
<service
android:name="com.hyw.servicedemo.MyService"
android:enabled="false"
android:exported="false" >
</service>
接下来我们启动它。我们在布局里添加一个button,点击之后让它执行:
Intent intent = new Intent(this,MyService.class);
startService(intent);
其中this是当前这个Activity,MyService.class就是刚才创建的服务。通过startService方法启动它。
布局:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.hyw.servicedemo.MainActivity">
<Button
android:id="@+id/start"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="启动服务" />
</RelativeLayout>
代码:
import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private Button start;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
}
private void initView() {
start = (Button) findViewById(R.id.start);
start.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.start:
Intent intent = new Intent(this,MyService.class);
startService(intent);
break;
default:
break;
}
}
}
非常不巧编译器打印不出log,然后我用Toast来测试
当我们点击开启服务之后
会弹出onCreate和onStartCommand方法里的Toast(通过startService开启服务是不会调用onBind方法的),再点开启服务,只弹出onStartCommand方法里的Toast,然后无论按home还是按返回键退出应用,进到手机设置里的应用选项,会发现正在运行里有我们的应用(一个进程和一个服务),接下来我们怎么关闭这个Service呢?
当点击关闭服务的时候,我让他执行
Intent intent2 = new Intent(this,MyService.class);
stopService(intent2);
注意我又new了一个Intent哦,这时候弹出onDestroy里的Toast。这时候再进应用里看,正在运行的应用没有我们这个应用了。
还有一种方法可以停止服务,就是在Service里调用
stopSelf();
方法。
如果我代码这样写的话
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Toast.makeText(this, "onStartCommand", Toast.LENGTH_SHORT).show();
stopSelf();
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
Toast.makeText(this, "onDestroy", Toast.LENGTH_SHORT).show();
super.onDestroy();
}
点击开启服务,弹出onStartCommand之后又会弹出onDestroy,而且在应用正在运行里也不会有我们的应用。它可以自己结束自己。
所以通过StartService启动的服务的生命周期是这样的:开启服务的时候会相继调用onCreate和onStartCommand方法,这就算是开启了,你再执行开启命令,只会调用onStartCommand方法了,所以初始化什么的要写在onCreate里比较好。service就像是一个单例模式的类,在手机里一个服务只会有一个,正确来说服务就是服务器,其他启动它的组件就是客户端,这也是google这样设计的,服务器之后一个,然后很多客户端可以跟它打招呼,服务会响应客户端的请求,但服务一般不会主动要求客户端干什么,所以service与activity的通信google设计的是只能activity操控service,而不能反过来,具体后面讲
当服务开启的时候,就算启动它的组件销毁了,服务还是存在,
停止服务的时候,无论是不是启动它的那个Intent,无论那个组件,都可以结束它,只要你有这个想法(intent里是不是这个Service)和这个能力(stopService方法)。所以服务也可以开启服务。
有一个问题?Service是在子线程执行的吗?
答案当然是否定的。
不然我怎么可以弹出Toast。
如果有要在子线程执行的耗时操作,可以在Service里新建一个线程执行,或者让这个类继承IntentService而不是Service,需要说明的是就算服务结束了,子线程如果还有事没做完,子线程还是会在后台继续执行的。