- 服务是Android中实现程序后台运行的解决方案,它非常适合于执行那些不需要和用户交互而且还要求长期运行的任务。
- 服务并不是运行在一个独立的进程中,而是依赖于创建服务是所在的应用程序进程。当某个应用进程被杀死后,所有依赖于该进程的服务也会停止运行。
- 实际上服务不会自己自动开启新的线程,所有的代码都默默的运行在主线程当中。也就是说,我们需要在服务的内部手动创建子线程,并在这里执行具体的任务,否则就可能出现主线程被阻塞的情况。
Service的简单使用
onCreate()方法在服务创建时会调用,而onStartCommand()方法则在每次启动服务的时候会调用,由于我们只点击了一次create按钮,所以两个都打印,但当你在点击时只会打印onStartCommand。
主要代码
package com.test.teacherbroadcaststembereight;
import android.support.v7.app.ActionBarActivity;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity implements OnClickListener {
private Button mButtonStart;
private Button mButtonClose;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mButtonStart = (Button) findViewById(R.id.start_service);
mButtonClose = (Button) findViewById(R.id.close_service);
mButtonStart.setOnClickListener(this);
mButtonClose.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.start_service:
Intent intent = new Intent(MainActivity.this, MyService.class);
startService(intent);
break;
case R.id.close_service:
Intent intent1 = new Intent(MainActivity.this, MyService.class);
stopService(intent1);
break;
}
}
}
Service服务类
package com.test.teacherbroadcaststembereight;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
public class MyService extends Service {
@Override
public void onCreate() {
super.onCreate();
Log.d("lalala", "oncreat");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("lalala", "onstart");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d("lalala", "onDestory");
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
主布局文件
<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" >
<Button
android:id="@+id/start_service"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="启动服务"/>
<Button
android:id="@+id/close_service"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="关闭服务"/>
</LinearLayout>
活动和服务进行通信
主布局文件
<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" >
<Button
android:id="@+id/start_service"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="启动服务"/>
<Button
android:id="@+id/close_service"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="关闭服务"/>
<Button
android:id="@+id/bind_service"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Bind Service"/>
<Button
android:id="@+id/unbind_service"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Unbind Service"/>
</LinearLayout>
主程序
package com.test.teacherbroadcaststembereight;
import com.test.teacherbroadcaststembereight.MyService.DownloadBinder;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity implements OnClickListener {
private Button mButtonStart;
private Button mButtonClose;
//下面的与绑定服务有关
private Button mButtonBindService;
private Button mButtonUnbindService;
private MyService.DownloadBinder mDownloadBinder;
private ServiceConnection connection=new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mDownloadBinder=(MyService.DownloadBinder) service;
mDownloadBinder.startDownload();
mDownloadBinder.getProgress();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mButtonStart = (Button) findViewById(R.id.start_service);
mButtonClose = (Button) findViewById(R.id.close_service);
mButtonBindService=(Button) findViewById(R.id.bind_service);
mButtonUnbindService=(Button) findViewById(R.id.unbind_service);
mButtonBindService.setOnClickListener(this);
mButtonUnbindService.setOnClickListener(this);
mButtonStart.setOnClickListener(this);
mButtonClose.setOnClickListener(this);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.start_service:
Intent intent = new Intent(MainActivity.this, MyService.class);
startService(intent);
break;
case R.id.close_service:
Intent intent1 = new Intent(MainActivity.this, MyService.class);
stopService(intent1);
break;
case R.id.bind_service:
Intent bindIntent = new Intent(this,MyService.class);
bindService(bindIntent, connection, BIND_AUTO_CREATE);
break;
case R.id.unbind_service:
unbindService(connection);
break;
}
}
}
Service程序
package com.test.teacherbroadcaststembereight;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
public class MyService extends Service {
private DownloadBinder mBinder = new DownloadBinder();
//这里只是模拟两个方法,并没有实现其功能,只是打印了两行日志
class DownloadBinder extends Binder{
public void startDownload(){
Log.d("lalala", "startDownload excuted");
}
public int getProgress(){
Log.d("lalala", "getProgress excuted");
return 0;
}
}
@Override
public void onCreate() {
super.onCreate();
Log.d("lalala", "oncreat");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("lalala", "onstart");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d("lalala", "onDestory");
}
@Override
public IBinder onBind(Intent intent) {
//绑定服务时必须返回值
return mBinder;
}
}
当按下绑定按钮后会打印出startDownload excuted和getProgress excuted;
需要注意的是:任何一个服务在整个应用程序范围内是通用的,即MyService不仅可以和MainActivity绑定,还可以和任何一个其他的活动进行绑定,而且在绑定完成后他们都可以得到相同的DownloadBinder实例。
服务的生命周期
一但在项目的任何位置调用了Context的startService()方法,相应的服务就会启动起来,并回调onStartCommand()方法。如果这个服务之前没有被创建过,那么onCreate()方法就会优先执行,服务启动后一直处于运行状态,知道调用stopService()或stopSelf方法。注意虽然每调用以次startService方法,onStartCommand()就会执行依次,但实际上每个服务都只会存在一个实例。
另外,还可以调用Context的bindService()来获取一个服务的持久连接,这时就会回调服务中的onBind()方法,类似的服务还没有创建过,那么onCreate()方法就会优先执行。之后调用方法可以获取到onBind()方法里返回的IBinder对象的实例,这样就能自由的和服务通信了。
当调用了startService()方法后,又去调用stopService()方法,这时服务的onDestory()方法就会执行,表示服务已经销毁了。类似地,当调用了bindService()方法后,又去调用unbindService()方法,onDestory()方法也会执行,这两种情况都很好理解。但是需要注意,我们是完全有可能对一个服务即调用了startService()方法,又调用了bindService()方法的。根据Android系统的机制,一个服务只要被启动或者被绑定了之后,就会一直处于运行状态,必须要以上两种条件同时不满足,服务才能被销毁。这种情况下要同时调用stopService()和unbindService()方法,onDestory()方法才会执行。
使用前台服务(里面包含动态注册广播传送消息)
主程序
package com.test.teacherbroadcaststembereight;
import com.test.teacherbroadcaststembereight.MyService.DownloadBinder;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ProgressBar;
public class MainActivity extends Activity implements OnClickListener {
private Button mButtonStart;
private Button mButtonClose;
//下面的与绑定服务有关
private Button mButtonBindService;
private ProgressBar mProgressBar;
private Button mButtonUnbindService;
private MyDownLoadReceive myDownloadReceive;
private MyService.DownloadBinder mDownloadBinder;
public final static String DOWNLOAD_COUNT="AD";
private ServiceConnection connection=new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name) {
}
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mDownloadBinder=(MyService.DownloadBinder) service;
mDownloadBinder.startDownload();
mDownloadBinder.getProgress();
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent=new Intent();
myDownloadReceive=new MyDownLoadReceive();
IntentFilter intentfilte=new IntentFilter();
intentfilte.addAction(DOWNLOAD_COUNT);
registerReceiver(myDownloadReceive, intentfilte);
mProgressBar=(ProgressBar) findViewById(R.id.progressBar1);
mButtonStart = (Button) findViewById(R.id.start_service);
mButtonClose = (Button) findViewById(R.id.close_service);
mButtonBindService=(Button) findViewById(R.id.bind_service);
mButtonUnbindService=(Button) findViewById(R.id.unbind_service);
mButtonBindService.setOnClickListener(this);
mButtonUnbindService.setOnClickListener(this);
mButtonStart.setOnClickListener(this);
mButtonClose.setOnClickListener(this);
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
unregisterReceiver(myDownloadReceive);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.start_service:
Intent intent = new Intent(MainActivity.this, MyService.class);
startService(intent);
break;
case R.id.close_service:
Intent intent1 = new Intent(MainActivity.this, MyService.class);
stopService(intent1);
break;
case R.id.bind_service:
Intent bindIntent = new Intent(this,MyService.class);
bindService(bindIntent, connection, BIND_AUTO_CREATE);
break;
case R.id.unbind_service:
unbindService(connection);
break;
}
}
class MyDownLoadReceive extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
int count =intent.getIntExtra("count",0);
mProgressBar.setProgress(count);
}
}
}
MyService程序
package com.test.teacherbroadcaststembereight;
import android.app.Notification;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;
public class MyService extends Service {
private int count = 0;
private DownloadBinder mBinder = new DownloadBinder();
// 这里只是模拟两个方法,并没有实现其功能,只是打印了两行日志
class DownloadBinder extends Binder {
public void startDownload() {
Log.d("lalala", "startDownload excuted");
}
public int getProgress() {
Log.d("lalala", "getProgress excuted");
return 0;
}
}
@Override
public void onCreate() {
"****这里为本节的重要内容****"
super.onCreate();
Log.d("lalala", "oncreat");
//这里是发出一个通知,可以参考先前的不同版本发送通知的方法。
Notification notification=new Notification(R.drawable.ic_launcher, "This is title", System.currentTimeMillis());
Intent notificationIntent=new Intent(this,MainActivity.class);
PendingIntent pendingIntent=PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(this, "This is a Title", "This is content", pendingIntent);
//这里没有使用NotificationManager来将通知显示出来,而是调用了startForeground()方法
startForeground(1, notification);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("lalala", "onstart");
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
// 开启一个线程在线程中,来调整进度条的值。
if (count > 100) {
count = 0;
}
count++;
Intent intent = new Intent();
"这里是动态的调用广播,来改变进度条"
intent.setAction(MainActivity.DOWNLOAD_COUNT);
intent.putExtra("count", count);
sendBroadcast(intent);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}).start();
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d("lalala", "onDestory");
}
@Override
public IBinder onBind(Intent intent) {
// 绑定服务时必须返回值
return mBinder;
}
}
布局文件
<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" >
<Button
android:id="@+id/start_service"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="启动服务(2)开启下载"/>
<Button
android:id="@+id/close_service"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="关闭服务"/>
<Button
android:id="@+id/bind_service"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Bind Service"/>
<Button
android:id="@+id/unbind_service"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Unbind Service"/>
<ProgressBar
android:id="@+id/progressBar1"
style="?android:attr/progressBarStyleHorizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
/>
</LinearLayout>
使用IntentService,自身包含一个线程(异步的,会自动停止服务的)
只含有一个线程,里面有消息队列,所以一般使用时不用在开启一个线程
示例
一般后台干一件耗时任务时使用IntentService.
public class MyIntentService extends IntentService {
//必须要有一个空的构造器
public MyIntentService(){
super("MyIntentService");//调用父类的有参构造器
}
@override
protected void onHandleIntent(Intent intent){
//打印当前线程的id
Log.d("MyIntentService","Thread id is "+Thread.currentThread().getId());
}
//服务运行完后会自动调用销毁
@override
public void onDestroy(){
super.onDestroy();
Log.d("MyIntentService","onDestroy executed");
}
}
服务的最佳实践—后台定时服务
Android中的定时任务一般有两种实现方式,一种是使用Java API提供的Timer类,一种是使用Android的Alarm机制。这两种方式都能实现类似的效果,但Timer明显不适用于那些需要长期在后台运行的定时任务。
获取AlarmManager的实例:
AlarmManager manager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
在接下来调用AlarmManager的set()方法就可以设置一个定时任务了,比如说想要设定一个任务在10秒后执行,就可以写成:
long triggerAtTime=