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
- Android 服务Service----重新认识Android(14)
- Android组件---重新认识Android(2)
- Android异步----重新认识Android(6)
- 重新认识android(一)
- Android Service(服务)
- Android服务(Service)
- Android 服务(Service)
- AndroidListView、GridView----重新认识Android(7)
- Android新手对Service服务的认识(1)
- 认识 Android Service
- 认识 Android Service
- 【Android】Android Service 服务
- Android程序的结构---重新认识Android(1)
- Android常用布局组件----重新认识Android(3)
- Android四大组件之Activity----重新认识Android(4)
- Android的Menu_Dialog----重新认识Android(8)
- Android的存储----重新认识Android(9)
- Android的SQLite----重新认识Android(10)
- 游戏开发框架之架构
- sizeof和strlen的区别
- 创建maven项目
- String源码阅读
- k-means+python︱scikit-learn中的KMeans聚类实现( + MiniBatchKMeans)
- Android 服务Service----重新认识Android(14)
- UP9612台湾力智新出2.4A自动识别+DCDC车充方案
- 11.Unity3D商业游戏源码研究-变身吧主公-SceneChat
- php 最简单 子进程创建及分开处理机制
- C#图片处理示例(裁剪,缩放,清晰度,水印)
- Java入门需要从哪里入手学习
- 【寒江雪】测试优先级策略
- linux上导入txt文件数据到mysql自己写的例子
- single number问题