Service是在一段不定的时间运行在后台,不和用户交互应用组件。每个Service必须在manifest中 通过<service>来声明。可以通过contect.startservice和contect.bindserverice来启动。
Service和其他的应用组件一样,运行在进程的主线程中。这就是说如果service需要很多耗时或者阻塞的操作,需要在其子线程中实现。
service的两种模式(startService()/bindService()不是完全分离的):
下面我们先来看一个有关音乐播放的Service实例:
主界面的Activity:
package com.example.alarmservice;
import android.os.Bundle;
import android.app.Activity;
import android.content.Intent;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class PlayService extends Activity {
//private static alarmService as = null;
Button start, stop;
boolean k = false;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//as = this;
setContentView(R.layout.main);
start = (Button) findViewById(R.id.start);
stop = (Button) findViewById(R.id.stop);
OnClickListener ol = new OnClickListener() {
@Override
public void onClick(View v) {
if(v == start){
//当按动start时,打开Service
startService(new Intent(
"com.example.alarmservice.PlayService.START_AUDIO_SERVICE"));
}if(v == stop){
//当按动stop时,关闭Service
stopService(new Intent(
"com.example.alarmservice.PlayService.START_AUDIO_SERVICE"));
finish();
}
}
};
start.setOnClickListener(ol);
stop.setOnClickListener(ol);
}
}
上面代码中提到了一个服务:"com.example.alarmservice.PlayService.START_AUDIO_SERVICE",这个服务是要在Manifest中注册的,至于名字,可以随意,但要有一定规律,便于使用,通常用:包名+服务名+常量
下载是注册部分的代码:(注册需要在Aplication中进行)
<service android:name=".Music">
<intent-filter>
<action android:name="com.example.alarmservice.PlayService.START_AUDIO_SERVICE"/>
<category android:name="android.intent.category.default"/>
</intent-filter>
</service>
这个代码中,又提到了一个Music,这是我们Service的核心部分:
package com.example.alarmservice;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.IBinder;
public class Music extends Service {
MediaPlayer mp ;
@Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
@Override
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
mp.stop();
}
@Override
public void onStart(Intent intent, int startId) {
// TODO Auto-generated method stub
super.onStart(intent, startId);
mp = MediaPlayer.create(this, R.raw.tank);
mp.start();
}
}
布局文件非常简单,就不列出了,这样做成Service的好处是,我们的音乐是在后台播放的,不会影响主线程
下面是一个复杂一点的例子,是关于定时反应的程序:alamService
先上主界面:
package com.example.alarmservice;
import java.util.Calendar;
import android.os.Bundle;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.Intent;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class alarmService extends Activity {
private static alarmService as = null;
Button call, exit, play;
boolean k = false;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
as = this;
setContentView(R.layout.activity_main);
call = (Button) findViewById(R.id.call);
exit = (Button) findViewById(R.id.exit);
play = (Button) findViewById(R.id.play);
OnClickListener ol = new OnClickListener() {
@Override
public void onClick(View v) {
if(v == call){//点此计时开始,改变标题名,5s后,就会再次改变标题的
setTitle("Waiting...Alarm=5");
Intent intent = new Intent(alarmService.this, AlarmReceiver.class);
PendingIntent p_intent = PendingIntent.getBroadcast(
alarmService.this, 0, intent, 0);
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(System.currentTimeMillis());
calendar.add(Calendar.SECOND, 5);
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), p_intent);
}if(v == exit){
Intent intent = new Intent(alarmService.this, AlarmReceiver.class);
PendingIntent p_intent = PendingIntent.getBroadcast(
alarmService.this, 0, intent, 0);
AlarmManager am = (AlarmManager) getSystemService(ALARM_SERVICE);
am.cancel(p_intent);
finish();
}if(v == play){
Intent i = new Intent(alarmService.this, PlayService.class);
startActivity(i);
}
}
};
call.setOnClickListener(ol);
exit.setOnClickListener(ol);
}
public static alarmService getApp() {
return as;
}
public void btEvent(String data) {
setTitle(data);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
}
注册Service:
这是另外一种注册方式
<receiver android:name=".AlarmReceiver"></receiver>
<service android:name=".NotifyService"></service>
这种方式需要另一个Receiver支持
package com.example.alarmservice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class AlarmReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
context.startService(new Intent(context, NotifyService.class));
}
}
最后是Service:
package com.example.alarmservice;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.widget.Toast;
public class NotifyService extends Service {
@Override
public IBinder onBind(Intent arg0) {
// TODO Auto-generated method stub
return null;
}
public void onCreate(){
alarmService as = alarmService.getApp();
as.btEvent("from NotifyService");
Toast.makeText(this, "hi, myicel", Toast.LENGTH_LONG);
}
}
注:在第二次运行的时候会有一小问题,点击之后标题不会恢复,这是Service没有关闭的原因,关闭就好了