四大组件服务:
先介绍下安卓进程,安卓优先级可以分为以下5钟进程:
而Android中的服务 也是在后台运行 可以理解成是在后台运行并且是没有界面的Activity。故服务的周期是没有stop()、Resume()、onPause()方法、onStart()方法的。这些方法与界面相关的,而服务属于后台长期运行的进程,是没有这些方法的。
服务的开启方式:
跟其他四大组件一样,定义一个类去继承Service,然后再清单文件中配置该Service。
与Activity相似点,Service中也定义了生命周期的方法,如下:
abstract IBinder onBind(Intent intent):任何类继承了Service就必须实现该方法。该方法返回了一个IBinder对象。
void onCreante():当该Service第一次被创建的时候会执行。
void onDestory(): 当该Service被关闭时前会调用该方法
onUnbind(Intent intent):当该Service 上绑定的服务被解绑时调用。
startService(Intent intent) :开启服务的方法。
android中服务有两种方式启动:
1,通过Context的startService()方法:通过该方法启动的Service ,访问者与Service之间没有什么关联,既是访问者退出了,Service依旧运行。不能被调用方法。
2,通过Context 的bindService()方法:使用该方法启用Service ,访问者与Service进行绑定在一起,访问这一旦退出,Service也结束了。但是该方法可以调用Service中的方法。
通过第一种启动:电话监听器
主MainActivity:
package com.service.phonelisten;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 把开启服务的逻辑放到这个方法里面
Intent intent1 = new Intent(this, PhoneService.class);
startService(intent1);
}
}服务类:
package com.service.phonelisten;
import android.app.Service;
import android.content.Intent;
import android.media.MediaRecorder;
import android.os.IBinder;
import android.telephony.PhoneStateListener;
import android.telephony.TelephonyManager;
public class PhoneService extends Service {
private MediaRecorder recorder;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
// 第一次开启的时候执行
public void onCreate() {
System.out.println("开启服务了 ");
// 1,获取管理者的实例
TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
// 2,注册一个电话状态的监听
tm.listen(new MyPhoneStateListenrer(), PhoneStateListener.LISTEN_CALL_STATE);
super.onCreate();
}
// 监听电话的状态
private class MyPhoneStateListenrer extends PhoneStateListener {
// 当设备的状态发生改变的时候调用
public void onCallStateChanged(int state, String incomingNumber) {
// 3,判断电话处于什么状态
switch (state) {
case TelephonyManager.CALL_STATE_IDLE: // 空闲状态:
if (recorder != null) {
recorder.stop(); // 停止录
recorder.reset(); // You can reuse the object by going back
// to setAudioSource() step
recorder.release(); // Now the object cannot be reused
}
System.out.println("我已经录完了 ");
break;
case TelephonyManager.CALL_STATE_OFFHOOK:// 接听状态
System.out.println("开始录");
// 7,开启录
recorder.start(); // Recording is now started
break;
case TelephonyManager.CALL_STATE_RINGING: // 响铃状态
System.out.println("我准备一个录音机出来 ");
// 1,获取MediaRecorder 实例
recorder = new MediaRecorder();
// 2,设置音频的来源
recorder.setAudioSource(MediaRecorder.AudioSource.VOICE_DOWNLINK);// 双方录音
// [3]设置音频的输出格式
recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
// [4]设置音频的编码方式
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
// [5]保存的文件路径
recorder.setOutputFile("/mnt/sdcard/luyin.3gp");
// [6]准备录音
try {
recorder.prepare();
} catch (Exception e) {
e.printStackTrace();
}
break;
}
super.onCallStateChanged(state, incomingNumber);
}
}
public void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
}
}服务还需要在清单文件中配置,这里同时调用了开机广播启动服务,也需要配置如下:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.service.phonelisten"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="21" />
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<application
android:allowBackup="true"
android:icon="@drawable/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="com.service.phonelisten.PhoneService"></service>
<!--配置广播接收者 -->
<receiver android:name="com.service.phonelisten.BootReceive">
<intent-filter >
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
</application>
</manifest>该方法最大特点:startservice 方式开启服务 服务就会在后台长期运行 直到用户手工停止 或者调用StopService方法 服务才会被销毁。
第二种方式启动:通过接口调用服务里面的方法,需要设定中间人IBinder 继承与Binder
MainActivity
package com.example.whybindservice;
import com.example.interfacemethod.R;
import android.os.Bundle;
import android.os.IBinder;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.view.View;
public class MainActivity extends Activity {
private Iservice myBinder; //这个是我们定义的中间人对象
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// //开启服务
Intent intent = new Intent(this,TestService.class);
//连接服务 TestService
MyConn conn = new MyConn();
//绑定服务
bindService(intent, conn, BIND_AUTO_CREATE);
}
//点击按钮 调用TestService 服务里面的办证方法
public void click(View v) {
//通过我们定义的中间人对象 间接调用服务里面的方法
myBinder.callBanZheng(1020000);
// myBinder.callXiSangNa();没有暴露出来的
myBinder.callPlayMaJiang();
}
//监视服务的状态
private class MyConn implements ServiceConnection{
//当连接服务成功后
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
//[4]获取我们定义的中间人对象
myBinder = (Iservice) service;
}
//失去连接
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
}
自定义的接口:
package com.example.whybindservice;
public interface Iservice {
//把领导想暴露的方法 都定义在接口里面
public void callBanZheng(int money);
public void callPlayMaJiang();
}服务类:
package com.example.whybindservice;
import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.widget.Toast;
public class TestService extends Service {
//当bindservice
@Override
public IBinder onBind(Intent intent) {
//[3]把我们定义的中间人对象返回
return new MyBinder();
}
@Override
public void onCreate() {
super.onCreate();
}
//测试方法
public void banZheng(int money){
if (money > 1000) {
Toast.makeText(getApplicationContext(), "我是领导 把证给你办了", 1).show();
}else{
Toast.makeText(getApplicationContext(), "这点钱 还想办事", 1).show();
}
}
//打麻将的方法
public void playMaJiang(){
System.out.println("陪客户打麻将");
}
//洗桑拿的方法
public void xiShangNa(){
System.out.println("洗桑拿");
}
//[1定义一个中间人对象 ]
private class MyBinder extends Binder implements Iservice{
//[2]定义一个方法 调用办证的方法
public void callBanZheng(int money){
banZheng(money);
}
//定义一个调用打麻将的方法
public void callPlayMaJiang(){
playMaJiang();
}
//调用洗桑拿的方法
public void callXiSangNa(){
xiShangNa();
}
}
}该方法的最大特点:可以调用服务中的方法,而且接口可以隐藏代码内部的细节 让程序员暴露自己只想暴露的方法。
实际上一般应用经常把二种方法混合使用:如音乐盒,我既想让服务在后台长期运行(常见的后台运行) 又想调用服务里面的方法(暂停,继续播放,开始播放等方法)。
例子:音乐盒:
服务类::写了音乐播放逻辑,而且通过一个中间人对象来call方法
package com.examole.baidumusic;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Message;
//音乐播放服务
public class MusicService extends Service {
private MediaPlayer player;
//[2]把我们定义的中间人对象 返回
@Override
public IBinder onBind(Intent intent) {
return new MyBinder();
}
//服务第一次开启的是调用
@Override
public void onCreate() {
//[1]初始化mediaplayer
player = new MediaPlayer();
super.onCreate();
}
//当服务销毁的时候调用
@Override
public void onDestroy() {
super.onDestroy();
}
//设置播放音乐指定位置的方法
public void seekToPosition(int position){
player.seekTo(position);
}
//专门用来播放音乐的
public void playMusic(){
System.out.println("音乐播放了");
//[2]设置要播放的资源 path 可以是本地也可是网络路径
try {
player.reset();
player.setDataSource("/mnt/sdcard/xpg.mp3");
//[3]准备播放
player.prepare();
//[4]开始播放
player.start();
//[5]更新进度条
updateSeekBar();
} catch (Exception e) {
e.printStackTrace();
}
}
//更新进度条的方法
private void updateSeekBar() {
//[1]获取当前歌曲总时长
final int duration = player.getDuration();
//[2]一秒钟获取一次当前进度
final Timer timer = new Timer();
final TimerTask task = new TimerTask() {
@Override
public void run() {
//[3]获取当前歌曲的进度
int currentPosition = player.getCurrentPosition();
//[4]创建message对象
Message msg = Message.obtain();
//[5]使用msg携带多个数据
Bundle bundle = new Bundle();
bundle.putInt("duration", duration);
bundle.putInt("currentPosition", currentPosition);
msg.setData(bundle);
//发送消息 MainActivity的handlemessage方法会执行
MainActivity.handler.sendMessage(msg);
}
};
//300毫秒后 每隔1秒钟获取一次当前歌曲的进度
timer.schedule(task, 300, 1000);
//[3]当歌曲播放完成的时候 把timer 和task 取消
player.setOnCompletionListener(new OnCompletionListener() {
//当歌曲播放完成的回调
@Override
public void onCompletion(MediaPlayer mp) {
System.out.println("歌曲播放完成了 ");
timer.cancel();
task.cancel();
}
});
}
//音乐暂停了
public void pauseMusic(){
System.out.println("音乐暂停了");
//暂停
player.pause();
}
//音乐继续播放的方法
public void rePlayMusic(){
System.out.println("音乐继续播放了");
player.start();
}
//[1]定义一个中间人对象(IBinder)
private class MyBinder extends Binder implements Iservice{
//调用播放音乐的方法
@Override
public void callPlayMusic() {
playMusic();
}
//调用暂停音乐的方法
@Override
public void callPauseMusic() {
pauseMusic();
}
//调用继续播放的方法
@Override
public void callrePlayMusic() {
rePlayMusic();
}
//调用设置播放指定位置的方法
@Override
public void callSeekToPosition(int position) {
seekToPosition(position);
}
}
}
MainActivity:开启服务和定义中间人对象
package com.examole.baidumusic;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import com.itheima.baidumusic.R;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
public class MainActivity extends Activity {
private Iservice iservice; // 这个就是我们定义的中间人对象
private MyConn conn;
private static SeekBar sbar;
public static Handler handler = new Handler(){
//当 接收到消息该方法执行
public void handleMessage(android.os.Message msg) {
//[1]获取msg 携带的数据
Bundle data = msg.getData();
//[2]获取当前进度和总进度
int duration = data.getInt("duration");
int currentPosition = data.getInt("currentPosition");
//[3]设置seekbar的最大进度和当前进度
sbar.setMax(duration); //设置进度条的最大值
sbar.setProgress(currentPosition);//设置当前进度
};
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sbar = (SeekBar) findViewById(R.id.seekBar1);
//[0]先调用startservice 方法开启服务 保证服务在后台长期运行
Intent intent = new Intent(this, MusicService.class);
startService(intent);
// [1]调用bindservice 目的是为了获取我们定义的中间人对象
conn = new MyConn();
// 连接MusicService 服务 获取我们定义的中间人对象
bindService(intent, conn, BIND_AUTO_CREATE);
//[2]给seekbar 设置监听
sbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
//当停止拖动执行
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
//设置播放的位置
iservice.callSeekToPosition(seekBar.getProgress());
}
//开始拖动
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
}
});
}
// 点击按钮 进行 音乐播放
public void click1(View v) {
// 调用播放音乐的方法
iservice.callPlayMusic();
}
// 暂停音乐
public void click2(View v) {
// 调用暂停音乐的方法
iservice.callPauseMusic();
}
// 继续播放
public void click3(View v) {
// 调用继续播放
iservice.callrePlayMusic();
}
// 当Activity销毁的时候调用
@Override
protected void onDestroy() {
// 在Activity销毁的时候 取消绑定服务
unbindService(conn);
super.onDestroy();
}
private class MyConn implements ServiceConnection {
// 当连接成功时候调用
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// 获取我们定义的中间人对象
iservice = (Iservice) service;
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
}
}接口:定义call方法package com.examole.baidumusic;
public interface Iservice {
//把我们想暴露的方法放到接口中
public void callPlayMusic();
public void callPauseMusic();
public void callrePlayMusic();
public void callSeekToPosition(int position);
}
别忘了配置服务。
音乐盒中的Seekbar控件进度条用法:
1,设置seekbar的监听:
sbar.setOnSeekBarChangeListener(new OnSeekBarChangeListener() {
//当停止拖动执行
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
<span style="white-space:pre"> </span>//设置播放的位置
<span style="white-space:pre"> </span>iservice.callSeekToPosition(seekBar.getProgress());
}
//开始拖动
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onProgressChanged(SeekBar seekBar, int progress,
boolean fromUser) {
}
});2,设置进度条最大进度和当前进度
sbar.setMax(duration); //设置进度条的最大值
sbar.setProgress(currentPosition);//设置当前进度
3,布局属性:
android:max="100" 设定进度值范围0 到100
android:progress="10"设定起始默认值进度
android:progressDrawable="@drawable/bg_bar" 设置进度条背景图片
android:thumb="@drawable/thumb_bar" /> 设置滑块的配件图片
一般样式主要背景图片的样式。
总结:服务一般需要混合使用,掌握二种启动的方式。了解服务的生命周期。

被折叠的 条评论
为什么被折叠?



