Android 服务Service----重新认识Android(14)

来源:互联网 发布:无源光网络的特性 编辑:程序博客网 时间:2024/06/07 04:55
启动服务的第一中方式 ----startService

// 启动服务,可以使用 Context 的 startService方法
// 对于 startService而言,第二个参数应该是 Service类型的
Intent intent = new Intent(this, MusicService.class);
// 给服务传递参数,服务的 onStartCommand来接收
intent.putExtra("operation", "prev");
startService(intent);
// 停止服务
// Context.stopService(Intent)

/**
* 支持音乐播放的 Service子类;
*/
public class MusicService extends Service{

/**
* 服务的成员变量,和服务是一样的生命周期;
* 可以播放音乐与视频
*/
private MediaPlayer player;

// 1. 创建服务子类
// 2. 实现 onBind方法,用于服务的绑定
// 3. 必须在清单文件注册,否则服务无法启动
// 4. 添加 onCreate 方法

// 4
/**
* 服务第一次被调用的时候,需要先创建;
* 会自动回调这个方法,只会执行一次,直到销毁位置;
*/
@Override
public void onCreate() {
super.onCreate();
System.out.println("MS : onCreate");

// onCreate 都是进行数据、资源、线程 的初始化;

// 服务自身就和 Activity一样,可以认为是 Context
// 参数2 可以是资源,通常歌曲都放在 res/raw 下面;
player =
MediaPlayer.create(this, R.raw.nobody);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}

/**
* 当 执行 startService的时候,当中的 Intent参数,
* 就会自动传递给这个方法,用于进行服务的处理;
* 这个方法相当于接收参数的,执行相应的动作;
* @param intent
* @param flags
* @param startId
* @return
*/
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
System.out.println("MS : onStartCommand");

// onStartCommand 接收参数的方式

// 1. 检查 intent 是否为 null

System.out.println("intent = " + intent);

if(intent != null){ // START_STICKY 服务复活的时候,intent 就为 null

String operation = intent.getStringExtra("operation");
// 获取传递的参数,可能为null,需要检查
if (operation != null) {

if (operation.equals("play")) {

// 收到Play的操作指令
player.start(); // 开始播放,或者是继续播放

} else if (operation.equals("pause")) {

player.pause(); // 暂停播放

} else if (operation.equals("prev")) {
// TODO: 需要支持上一首功能

} else if (operation.equals("next")) {
// TODO: 需要支持下一首功能

}


System.out.println("operation = " + operation);
}
}
// onStartCommand 返回值决定了 服务能否复活,
// 能够还原之前的Intent
// 可选值:
// START_STICKY
// START_NOT_STICKY
// START_REDELIVER_INTENT
return super.onStartCommand(intent, flags, startId);
}

/**
* 当服务不在被任何其他组件使用了,并且系统准备删除服务的时候
* 就会回调这个方法,需要在这个方法,进行资源的释放;
*/
@Override
public void onDestroy() {

System.out.println("MS : onDestroy");

// 释放MediaPlayer
// 1. 如果正在播放,那么停止
// 2. 释放资源

if(player.isPlaying()){
player.stop(); // 停止播放
}

player.release(); // 释放播放器资源

player = null;

super.onDestroy();
}
}

//--------------------IntentService
*/
public class DownloadService extends IntentService {

/**
* IntentService 必须要有无参的构造方法;
*/
public DownloadService() {
// 构造的字符串可以随意,调试用的;
super("Download");
}

/**
* 在子线程,调用这个方法,来处理 Intent。
* 相当于 把 onStartCommand 中的功能,挪到子线程;
* 如果同时调用了多次 startService,那么就会依次收到
* Intent 参数,一个一个的处理;
* @param intent
*/
@Override
protected void onHandleIntent(Intent intent) {
try {
Thread.sleep(20000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("handle Intent ok");
}

启动服务的第二种方式 ---- context.bindService


public class PlayActivity
extends AppCompatActivity implements ServiceConnection, SeekBar.OnSeekBarChangeListener {

private PlayBindService.Controller controller;

private SeekBar seekBar;

private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
}
};

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_play);

seekBar = (SeekBar) findViewById(R.id.seek_bar);

if (seekBar != null) {
// 拖拽的时候进行回调
seekBar.setOnSeekBarChangeListener(this);
}

}

@Override
protected void onResume() {
super.onResume();

// 绑定服务

Context context = this;

Intent intent = new Intent(this, PlayBindService.class);

// 参数1, Intent 代表需要连接哪一个Service
// 参数2, ServiceConnection 当和服务连接成功之后,
// 通过这个参数可以进行回调;
// 参数3,当绑定的时候,如果服务没有创建,那么自动创建服务
context.bindService(intent, this, BIND_AUTO_CREATE);

}

/**
* 当服务绑定成功,就会调用服务自身的 onBind方法
* onBind方法的返回值,就会传给当前的这个回调方法中,
* 作为第二个参数;使用IBinder 对象就可以给服务传递参数,设置数据、调用方法
*
* @param name
* @param service
*/
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
controller = (PlayBindService.Controller) service;
controller.setHandler(mHandler);
}

/**
* 服务与当前的组件断开连接,那么IBinder将失效;
*
* @param name
*/
@Override
public void onServiceDisconnected(ComponentName name) {
controller = null;
}
/**
* 使用绑定的服务进行播放
*
* @param view
*/
public void btnPlayOnClick(View view) {

if (controller != null) {
controller.play();
// 播放之后,可以获取总时长,设置给Seekbar
int duration = controller.getDuration();
seekBar.setMax(duration);
}
}
public void btnPauseOnClick(View view) {

if (controller != null) {

controller.pause();

}

}

// --------------------------------------

/**
* 当 SeekBar 发送数值变化的时候,会回调这个方法
* fromUser 如果为 true,代表是用户拖拽的
*
* @param seekBar
* @param progress
* @param fromUser
*/
@Override
public void onProgressChanged(
SeekBar seekBar,
int progress,
boolean fromUser) {

if (fromUser) {
// 修改播放的进度
if(controller!= null){
controller.setProgress(progress);
}
}

}

@Override
public void onStartTrackingTouch(SeekBar seekBar) {

}

@Override
public void onStopTrackingTouch(SeekBar seekBar) {

}
}

/**
* 绑定服务使用的步骤:
*
* 1. 创建服务的子类
* 2. 清单文件注册
* 3. onBind 方法必须要进行相应的实现;
* 4. onCreate 初始化数据和资源
* 5. onDestroy 释放资源
*/
public class PlayBindService extends Service {

private MediaPlayer player;

private Handler mHandler;

public PlayBindService() {
}

@Override
public void onCreate() {
super.onCreate();
player = MediaPlayer.create(this, R.raw.nobody);
}

public class Controller extends Binder{
// 就是一个 IBinder 的类的定义,可以直接在 onBind方法使用

public void setHandler(Handler handler){
mHandler = handler;
}

public void play(){
player.start();
}

public void pause(){
player.pause();
}

/**
* 通过内部类,来获取当前播放的歌曲的时长;
* 只有绑定才可以实现这个功能
* @return
*/
public int getDuration(){
return player.getDuration();
}

public void setProgress(int progress){
player.seekTo(progress);
}

}

/**
* 一个应用程序的组件,要想与当前的服务进行关联、绑定
* 当绑定成功之后,就可以使用 IBinder 进行方法的调用和数据的传递;
* onBind方法,是在其他组件调用 bindService() 方法的时候,
* 自动调用的; 通常可以使用 Binder 的子类就可以实现IBinder了
* @param intent
* @return
*/
@Override
public IBinder onBind(Intent intent) {
return new Controller();
}

@Override
public void onDestroy() {

if(player.isPlaying()){
player.stop();
}

player.release();

player = null;

super.onDestroy();
}
}


//---Service 进行应用程序之间的通信
使用AIDL或Messenger

1、使用Messenger 信使
public class MainActivity extends AppCompatActivity implements ServiceConnection {

/**
* 信使,可以通过绑定服务,获取 IBinder,可以实现
* 发送消息的功能
*/
private Messenger sendMessenger;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}

@Override
protected void onResume() {
super.onResume();

// 绑定远程的服务

Intent intent = new Intent();
//参数1:自定义服务类的包名,参数2:自定义服务类的包名+类名
intent.setClassName("com.messengerserver", "com.messengerserver.MessengerService");

bindService(intent, this, BIND_AUTO_CREATE);
}

@Override
protected void onPause() {
super.onPause();

unbindService(this);
}

@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// 构造方法 Messenger(IBinder) 用于给服务发送消息
sendMessenger = new Messenger(service);
}

@Override
public void onServiceDisconnected(ComponentName name) {
sendMessenger = null;
}

public void btnSend(View view) {

if (sendMessenger != null) {
Message msg = Message.obtain();
msg.what = 998;
// 使用信使发送的对象,必须是 可以序列化的,
// 如果需要发送字符串,需要使用 Bundle
Bundle bundle = new Bundle();
bundle.putString("key", "123456");
msg.obj = bundle;
try {
sendMessenger.send(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
}
//在其他应用程序中创建的Service的子类
package com.messengerserver;

import android.app.Service;
import android.content.Intent;
import android.os.*;
import android.util.Log;

public class MessengerService extends Service {

/**
* 用于接收从其他应用程序传递过来的 Message对象,并且处理
*/
private Handler handler = new Handler(){
@Override
public void handleMessage(Message msg) {
int what = msg.what;

Log.d("MS", "what = " + what);

if(what == 998){
// 服务收到的消息 obj 字段需要是序列化的
Bundle bundle = (Bundle)msg.obj;
String key = bundle.getString("key");

Log.d("MS", "key = " + key);
}

}
};

public MessengerService() {
}

@Override
public IBinder onBind(Intent intent) {
// 信使的创建分成两种形式
// !!! Messenger(Handler target)
// 这个信使用于接收消息的,只能收
// 用于服务的 onBind 方法
return new Messenger(handler).getBinder();
}
}

//2、使用AIDL
import com.alipayserver.IPayController;

public class MainActivity extends AppCompatActivity implements ServiceConnection {

private IPayController controller;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}

@Override
protected void onResume() {
super.onResume();

// TODO: 绑定服务

// 绑定/启动 另一个程序的服务,需要指定
// 另一个程序的包名、类名 (Android 5.0 必须设置)
// 也可以设置 隐式意图 Action (5.0以下)

Intent intent = new Intent();
intent.setPackage("com.alipayserver"); // 另一个程序的 package 名称
// 设置包名和类名
intent.setClassName("com.alipayserver", "com.alipayserver.PayService");

bindService(intent, this, BIND_AUTO_CREATE);
}

@Override
protected void onPause() {
super.onPause();

// TODO: 解除绑定

unbindService(this);

}

@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// IPayController 是通过 aidl 文件生成的,一个接口
// 接口中的方法就是可以调用的;
// asInterface(IBinder) 可以把IBinder对象转换为接口对象;
controller =
IPayController.Stub.asInterface(service);
}

@Override
public void onServiceDisconnected(ComponentName name) {
controller = null;
}

public void btnCallOther(View view) {

if (controller != null) {
try {

int code = controller.pay("110", "939384");

Log.d("Code", "code = " + code);

controller.show();

int max =
controller.max(new int[]{9, 39, 99});

Log.d("Max", "Max = " + max);

} catch (RemoteException e) {
e.printStackTrace();
}
}

}
}
//进行通信的应用程序都必须包含这个aidl文件
// IPayController.aidl
package com.alipayserver;

// Declare any non-default types here with import statements

interface IPayController {

/**
* 定义一个方法,接收两个字符串参数,并且返回执行结果
*/
int pay(String account, String password);

void show();

/**
* 从整形数组中,获取最大值
* 如果数组作为参数,那么必须设置方向
* in, out, inout
*/
int max(in int[] data);
}

//-- 在一个应用程序中的服务子类
public class PayService extends Service {
public PayService() {
}

// 继承 AIDL文件生成的接口中的 Stub类
// 就可以继承Binder类,
// 那么这个类可以直接传递给另一个程序了
private class Controller extends IPayController.Stub{
@Override
public int pay(String account, String password) throws RemoteException {
return 998;
}

@Override
public void show() throws RemoteException {
Log.d("Server", "Show test");
}

@Override
public int max(int[] data) throws RemoteException {
int ret = 0;
if (data != null) {
int len = data.length;
for (int i = 0; i < len; i++) {
int d = data[i];
if(ret < d){
ret = d;
}
}
}
return ret;
}
}

/**
* onBind方法,如果是其他程序来绑定,那么就需要使用
* AIDL 或者 信使 来实现IBinder才可以使用;
* @param intent
* @return
*/
@Override
public IBinder onBind(Intent intent) {
return new Controller();
}
}
0 0
原创粉丝点击