Service,服务,Android的四大组件之一。服务一般用于去执行需要长期运行,很少于用户交互的任务。服务一般都是后台运行的。下面我们就来学习一下Service服务。
创建一个服务很简单。看步骤:
1. 创建一个类MyService,然后继承Service。
我们可以看到,当我们创建一个服务之后,需要重写onBind()方法,这是Service中唯一个抽象的方法。
public class MyService extends Service {
@Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
}
2. 在AndroidManifext.xml注册。
创建服务之后,要想使用它,必须在AndroidManifext.xml文件中注册。
<service android:name=".MyService"></service>
这样一个服务就是创建完成了,我们就可以开启服务并使用了,在使用之前我们首先要了解一下Service的生命周期。
服务的生命周期我们要分两种介绍:启动类型服务周期和绑定类型服务周期。我们可以先看下图:
一个组件调用startService()方法创建服务,然后服务无限期的运行,并且必须通过调用stopSelf()方法来终止自己。其他组件也能够通过调用stopService()方法来终止这个服务。当服务被终止,系统就会把它销毁。如上图左边周期。
这种方式我们通过Activity启动服务,服务在启动后与活动就没有了关系。Activity无法在控制服务中运行的是什么。
一个组件(客户端)调用bindService()方法创建服务,客户端通过IBinder接口与服务通信。客户端能够调用unbindService()方法来关闭与服务连接。多个客户端能够绑定到同一个服务,并且当所有的都解绑以后,系统就会销毁这个服务(服务不需要终止自己)。这一块知识点老师没有给我们提及,我记得我当时问老师问什么不讲,老师说现在很少有用绑定服务的,一般都是通过发送广播来实现服务与活动的联系。所以在这里我也就不再讲绑定服务了,因为我也不会……
我们通过例子来学习一下服务的简单使用……
1. 创建一个服务并注册。
MyService类:
public class MyService extends Service {
public MyService() {
}
@Override
public void onCreate() {
super.onCreate();
Log.d("data", "onCreate ");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("data", "onStartCommand ");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d("data", "onDestroy ");
}
@Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
}
在AndroidMainfest.xml中注册:
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.lishuang.administrator.servicedemo">
<application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme">
<activity android:name=".MainActivity" android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service android:name=".MyService"></service>
</application>
</manifest>
2. 在Activity的布局文件,定义两个按钮,启动和关闭服务。
<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=".MainActivity">
<Button android:id="@+id/button_start_service" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="启动服务" />
<Button android:id="@+id/button_stop_service" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="关闭服务" />
</LinearLayout>
3. 在Activity中通过使用Intent启动和关闭服务。
public class MainActivity extends Activity implements View.OnClickListener {
private Button mButtonStartService;
private Button mButtonStopService;
private MyDownLoadReceiver myDownLoadReceiver;
public static final String DOWNLOAD_RECEIVER="com.example.receiver";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mButtonStartService = (Button) findViewById(R.id.button_start_service);
mButtonStopService = (Button) findViewById(R.id.button_stop_service);
mButtonStartService.setOnClickListener(this);
mButtonStopService.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.button_start_service:
Intent intent = new Intent(getApplicationContext(), MyService.class);
startService(intent);//启动服务
break;
case R.id.button_stop_service:
Intent intent1 = new Intent(getApplicationContext(), MyService.class);
stopService(intent1);//关闭服务
break;
default:
break;
}
}
定义一个下载任务,通过进度条显示其下载进度。
通常我们的下载是在程序退出之后也可以进行的,所以下载不能定义在活动中,我们可以将其定义在服务中。
1. 在Activity中开启一个Service
2. 在Service中发送一个广播,将下载的进度发送给Activity。但是我们需要知道Service中不能进行耗时操作,所以我们在一个线程中完成。
3. 在Activity中接收广播,并设置进度条。
<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=".MainActivity">
<Button
android:id="@+id/button_stop_service"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="关闭下载" />
<Button
android:id="@+id/button_start_download"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="开始下载" />
<ProgressBar
android:id="@+id/progressBar"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:max="100"
/>
</LinearLayout>
2. 在Activity中启动下载服务。
public class MainActivity extends Activity implements View.OnClickListener {
public static final String DOWNLOAD_RECEIVER="com.example.receiver";
private Button mButtonStopService;
private Button mButtonStartDownload;
private ProgressBar mProgressBar;
private MyDownLoadReceiver myDownLoadReceiver;//定义服务
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mButtonStopService = (Button) findViewById(R.id.button_stop_service);
mButtonStartDownload = (Button) findViewById(R.id.button_start_download);
mProgressBar = (ProgressBar) findViewById(R.id.progressBar);
mButtonStopService.setOnClickListener(this);
mButtonStartDownload.setOnClickListener(this);
//注册一个广播
myDownLoadReceiver = new MyDownLoadReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(DOWNLOAD_RECEIVER);
registerReceiver(myDownLoadReceiver, filter);
}
//取消注册
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(myDownLoadReceiver);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.button_stop_service:
Intent intent1 = new Intent(getApplicationContext(), MyIntentService.class);
stopService(intent1);
break;
case R.id.button_start_download:
Intent intent2 = new Intent(getApplicationContext(), MyIntentService.class);
startService(intent2);
break;
default:
break;
}
}
class MyDownLoadReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
int count = intent.getIntExtra("count",0);
mProgressBar.setProgress(count);
}
}
}
3. 定义一个服务,在服务中发送广播,将下载的进度发送给Activity。
public class MyService extends Service {
private int count = 0;
public MyService() {
}
@Override
public void onCreate() {
super.onCreate();
Log.d("data", "onCreate ");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("data", "onStartCommand ");
//发送一个广播
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
if (count > 100) {
count = 0;
}
count++;
Intent intent = new Intent();
intent.setAction(MainActivity.DOWNLOAD_RECEIVER);
intent.putExtra("count", count);
sendBroadcast(intent);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
Log.d("data", "onDestroy ");
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) {
throw new UnsupportedOperationException("Not yet implemented");
}
}
4. 在AndroidManifest.xml中注册。
在之前我们就说过,主线程中是不允许有耗时操作的,Service服务中的内容是默认运行在主线程中的。因此,在服务中定义下载我们必须开启一个子线程来完成这项工作。
我们通过比较Service和IntentService来学习一下IntentService:Service中使用子线程必须自己重新定义,而IntentService服务中自己包含一个子线程,不需要我们在去重新定义;Service服务开启后必须调用stopService()方法或者stopSelf()方法才可以将服务停止,而IntentService服务只要服务内容运行结束就会自己停止。
IntentService中包含一个任务的堆栈,每次我们在开启服务时, 如果当前服务没有运行结束,就会就会将启动的服务添加到任务堆栈中,直到当前服务运行结束,才会将后启动的服务从堆栈中取出来,然后运行。
了解完了IntentService,我们可以使用IntentService来优化一下刚才讲的Service的下载应用。
1. 定义布局文件。跟刚才的是相同的,我们这里不在贴出。
2. 在Activity中启动下载服务。
public class MainActivity extends Activity implements View.OnClickListener {
private Button mButtonStopService;
private Button mButtonStartDownload;
private ProgressBar mProgressBar;
private MyDownLoadReceiver myDownLoadReceiver;//定义一个广播
public static final String DOWNLOAD_RECEIVER="com.example.receiver";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mButtonStopService = (Button) findViewById(R.id.button_stop_service);
mButtonStartDownload = (Button) findViewById(R.id.button_start_download);
mProgressBar = (ProgressBar) findViewById(R.id.progressBar);
mButtonStartService.setOnClickListener(this);
mButtonStopService.setOnClickListener(this);
mButtonStartDownload.setOnClickListener(this);
//注册一个广播
myDownLoadReceiver = new MyDownLoadReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction(DOWNLOAD_RECEIVER);
registerReceiver(myDownLoadReceiver, filter);
}
//取消注册
@Override
protected void onDestroy() {
super.onDestroy();
unregisterReceiver(myDownLoadReceiver);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.button_stop_service:
Intent intent1 = new Intent(getApplicationContext(), MyIntentService.class);
stopService(intent1);//关闭服务
break;
case R.id.button_start_download:
Intent intent2 = new Intent(getApplicationContext(), MyIntentService.class);
startService(intent2);//开启定义的IntentService服务
break;
default:
break;
}
}
class MyDownLoadReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
int count = intent.getIntExtra("count",0);
mProgressBar.setProgress(count);
}
}
}
这里将启动的服务修改为自定义的IntentService服务。
3. 定义一个IntentService服务,在服务中发送广播,将下载的进度发送给Activity。
public class MyIntentService extends IntentService {
private static final String TAG = "data";
private int count = 0;
private boolean running = true;
/* 必须定义一个无参的构造器,调用父类的有参构造器 */
public MyIntentService() {
super("MyIntentService");
}
@Override
public void onCreate() {
Log.d(TAG, "运行了……onCreate ");
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "运行了……onStartCommand ");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
Log.d(TAG, "运行了……onDestroy ");
running = false;
super.onDestroy();
}
//将服务执行的内容写在该方法中。
@Override
protected void onHandleIntent(Intent intent) {
Log.d(TAG, "运行了……onHandleIntent ");
while (running) {
if (count > 100) {
count = 0;
Toast.makeText(getApplicationContext(), "开始下载", Toast.LENGTH_SHORT).show();
}
Toast.makeText(getApplicationContext(), "开始下载", Toast.LENGTH_SHORT).show();
count++;
Intent intent1 = new Intent();
intent1.setAction(MainActivity.DOWNLOAD_RECEIVER);
intent1.putExtra("count", count);
sendBroadcast(intent1);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}