0
点赞
收藏
分享

微信扫一扫

Android服务器的使用(Service)


start方式开启服务的生命周期

服务的生命周期:

- 如果采用start的方式开启服务
  onCreate()-->onStartCommand()-->onStart()-->onDestory();
- 服务已经被开启,不会重复的创建,多次调用startService方法,服务的onCreate()始终只会执行一次
  onCreate()-->
  onStartCommand()-->
  onStart()-->
  onStartCommand()-->
  onStart()-->
  onStartCommand()-- >
  onStart()-->
  onDestory();

- 服务只会停止一次 多次调用stopService方法是无效的。

代码如下:

package com.li.lifeWeek;
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() {
Log.v("wang", "onCreate 服务器创建的时候调用");
}
@Override
public void onStart(Intent intent, int startId) {
Log.v("wang", "onStart 服务器启动的时候被调用 ");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.v("wang", "onStartCommand 服务器启动的时候被调用 ");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
Log.v("wang", "onDestroy 服务器销毁的时候掉用");
}
@Override
public IBinder onBind(Intent intent) {
return null;
}


}

绑定服务调用服务方法的过程

 

采用startService无法调用
- 通过绑定服务无法返回服务本身
- 通过new无法获取服务的上下文 也就是不是当前服务本身 而只是拿到普通的对象


采用bindService方式
对比:
屁民:想找官员办事(直接找无法找到,找到他的秘书)
官员:为人民服务
秘书:告诉官员办某件事
 

项目:绑定服务调用服务的方法
步骤:
1.采用bindService的方式开启服务
2.如果服务绑定成功 会调用一个onBind方法,返回一个代理对象
3.在连接监听器中获取代理对象
4.对代理对象调用某个方法 代理对象在该方法内访问服务的方法

Android服务器的使用(Service)_ide

采用接口暴露服务里面的方法

- 绑定服务 调用服务方法 的例子
- 我们发现 代理对象的方法我们都可以调用 那为了屏蔽代理对象其他方法 我们必须将其他方法设置为了私有
但是这样还不够彻底 因为我们可以用反射去调用其方法。
- 所以我们可以去创建一个公共接口 这样我们只需要知道接口的方法 到底是那个类在做代理 可以在运行时去指定

 

Android服务器的使用(Service)_生命周期_02

 

bind方式服务的生命周期&混合调用的生命周期

项目准备:服务的生命周期-v2

    - 采用bind方式开启服务的生命周期
       onCreate()-->onBind()-->onUnbind()-->onDestory()
    - bind的方式 只能绑定一次 多次绑定会导致解绑失败
    - bind的方式,只能解绑一次 多次解绑 程序会异常退出
    - 不求同生 但求同死(Activity挂了 服务就挂了)
    - 可以调用服务的方法


混合调用服务的生命周期处理
为了保证服务长期的运行,又想调用服务的方法。
    startService() 保证服务长期后台运行
    bindService() 绑定服务,调用服务的方法
    unbundService() 解绑服务,不需要再去调用方法了

    stopService() 停止服务

 

1.服务有2个特性:

1.后台一直运行    
2.没有界面 能够与界面进行交互


两种启动方式
1.startService: 后台一直运行  不能交互数据

2.bindService :当启动的组件被摧毁的时候 Service也跟着销毁  能够交互数据
   在应用中一般多是 startService调用 bindService 
   使用混合调用

 

Service 的生命周期

Android服务器的使用(Service)_生命周期_03

 

混合生命周期:(为了让服务能够一直运行  也为了让服务能够与界面UI交互数据 一般需要混合使用两种启动服务的方式)

startService()->bindService()->unBindService()-(服务还存在)-stopService();

onCreate()->onStartCommand()->onBind()->onUnBind()->onDestory();

 

本地服务和远程服务

 

 

 

1. 从启动方式来说:

        开启服务
        绑定服务

2. 服务的执行类型:

        远程服务(AIDL服务 android interface definition language)
        本地服务

绑定服务的应用场景

    * 提供一个服务 后台运行里面有一些公共的逻辑供调用

    * 1.微信支付/支付宝支付  微信有一个支付的服务,绑定,调用支付的方法(微信App提供了一个服务  大众点评支付的时候调用微信支付)

    * 2.sony手机 人脸识别服务 绑定到这个服务传递一个照片 就会把人脸标记出来

    * 3.音乐播放器 后台服务里面播放音乐 绑定服务暂停 下一曲 上一曲 (服务与APP的代码都在同一个包里面)

 

Android服务器的使用(Service)_ide_04

 

Android服务器的使用(Service)_ide_05

 

 

 

本地服务就是服务器在自己手机了开启的服务  自己调用他

远程服务就是服务器是另外一个软件的一个服务

 

支付宝远程服务的创建

 

AIDL:android interfacedefinition language  安卓接口定义语言

Android服务器的使用(Service)_ide_06

 

远程服务的调用开发步骤:

    1. 在支付宝APP里面 创建一个服务 提供一个支付方法(主功能有了 其他应用能拿到服务)

    2. 创建代理 为了规范 要先创建一个接口,服务里面有的支付方法 接口也应该用。

    3. 为了让其他应用共享数据、服务,需要定义一个共同的规范.aidl  (修改文件后缀)

Android服务器的使用(Service)_生命周期_07

Android服务器的使用(Service)_android_08

支付宝的服务:

package com.li.zhifubao;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;

public class AlipayService extends Service{
private class MyAlipayService extends IAlipayService.Stub{

@Override
public int callSafePay(String account, String pwd, String payPwd, double money, long currTimeMiles) {
return safePay(account, pwd, payPwd, money, currTimeMiles);//通关接口的实现方法
}


}
@Override
public IBinder onBind(Intent intent) {
return new MyAlipayService();
}
/**
*
* @param account 账号
* @param pwd 密码
* @param payPwd 支付密码
* @param money 支付金额
* @param currTimeMiles 当前的时间撮
* @return int
* 代码错误 ----- -1
* 账号密码错误 ---0
* 支付密码错误 ---1
* 余额不足 ------2
* 支付成功 ------3
*/
private int safePay(String account,String pwd,String payPwd,
double money,long currTimeMiles){
if(!account.equals("zhangsa")||!pwd.equals("123456")){
return 0;
}if(!payPwd.equals("123456")){
return 1;
}
//如果支付的金额大于一千块就显示余额不足
if(money>1000){
return 2;
}
//如果上面的多不满足 说明支付成功
return 3;
}
}

支付宝绑定服务

<service android:name="com.li.zhifubao.AlipayService">
<intent-filter >
<action android:name="com.li.zhifubao.AlipayService.SAFEPAY"/><!--对外提供隐士启动com.li.zhifubao.AlipayService类-->
</intent-filter>
</service>

支付宝里面的AIDL技术

Android服务器的使用(Service)_ide_09

 

 

淘宝里面的调用:

package com.li.taobao;

import com.li.zhifubao.IAlipayService;

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.os.RemoteException;
import android.view.View;
import android.widget.Toast;

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void clickPay(View v){
Intent intent = new Intent();
intent.setAction("com.li.zhifubao.AlipayService.SAFEPAY");//使用隐试启动
bindService(intent, new ServiceConnection() {

@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub

}

@Override
public void onServiceConnected(ComponentName name, IBinder service) {
IAlipayService sefePay=IAlipayService.Stub.asInterface(service);

try {
/**
* @return int
* 代码错误 ----- -1
* 账号密码错误 ---0
* 支付密码错误 ---1
* 余额不足 ------2
* 支付成功 ------3
*/
int i=sefePay.callSafePay("zhangsa", "123456", "123456", 5000,System.currentTimeMillis());
switch (i) {
case 0:
Toast.makeText(MainActivity.this, "账号或密码错误", Toast.LENGTH_SHORT).show();
break;
case 1:
Toast.makeText(MainActivity.this, "支付密码错误", Toast.LENGTH_SHORT).show();
break;
case 2:
Toast.makeText(MainActivity.this, "余额不足", Toast.LENGTH_SHORT).show();
break;
case 3:
Toast.makeText(MainActivity.this, "支付成功", Toast.LENGTH_SHORT).show();
break;

default:
break;
}
} catch (RemoteException e) { //该异常叫远程调用的异常
// TODO Auto-generated catch block
e.printStackTrace();
}

}
}, BIND_AUTO_CREATE);
}
}

Android服务器的使用(Service)_android_10

 

音乐播放器的界面

 

开发步骤:

1. 将音乐放置到sd卡中

2. 创建音乐列表

3. 创建音乐服务 创建播放音乐的方法

4. 创建音乐服务的接口

5. 在音乐点击事件中调用音乐服务的调用

6. 设置播放模式 因为这里涉及到列表循环所以需要列表的信息和当前播放的索引 需要将服务的方法进行修改

7. 在播放的过程中需要在界面左上角添加提示框 因为每次播放都会在服务里面执行 所以可以在播放音乐的代码中弹出提示

8. 退出音乐应用 需要关闭提示框释放音乐资源解绑和停止服务关闭界面

附加知识点:

如何获取菜单的点击事件

如何创建提示栏

 

 

代码提示:

Android服务器的使用(Service)_ide_11

Android服务器的使用(Service)_ide_12


MainActivity.java


 

package com.li.musicPlay;

import java.io.File;
import java.util.ArrayList;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Bundle;
import android.os.Environment;
import android.os.IBinder;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;
import android.widget.Toast;

public class MainActivity extends Activity implements OnItemClickListener{
private ListView mListView;
private ArrayList<String> mData;// 存放音乐的路径
private MusicAdapter adapter;
private ServiceConnection mConn;
private IMusicService mIMusic;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// 加载UI控件
initUI();
// 初始化数据
initData();
//传入列表
adapter.setData(mData);
adapter.notifyDataSetChanged();//重新调用Adapter对象
mListView.setOnItemClickListener(this);

//启动服务绑定
Intent intent = new Intent(this,MusicService.class);
mConn=new ServiceConnection() {

@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub

}

@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mIMusic = (IMusicService)service;
}
};
bindService(intent, mConn , BIND_AUTO_CREATE);

//设置播放的模式 1.播放停止 2.单曲循环 3.全部循环


}

private void initData() {
mData = new ArrayList<String>();
// 1.应该找到SD卡的路径
File file = Environment.getExternalStorageDirectory();
// 2.循环遍历子文件
File[] files=file.listFiles();//全部的子文件
for(File filsFile : files){
// 3.判断文件是否以MP3结尾
String fileName=filsFile.getAbsolutePath();
if(fileName.endsWith("mp3")){
// 4.如果是的话需要将路径添加到mData里面
mData.add(fileName);
}
}
}

private void initUI() {
mListView = (ListView) findViewById(R.id.listViewId);
adapter = new MusicAdapter();
mListView.setAdapter(adapter);
}

@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
//拿到代理对象
Toast.makeText(this, ""+(String)adapter.getItem(position), Toast.LENGTH_SHORT).show();
mIMusic.callPlayMusic(mData, position);
}
//创建菜单栏 返回true 代表告诉系统我们自己处理 不需要系统插手
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
//菜单栏被点击的时候回调的方法
@Override
public boolean onOptionsItemSelected(MenuItem item) {
SharedPreferences shared = getSharedPreferences("music", MODE_PRIVATE);
Editor edit=shared.edit();//状态 0 停止音乐 1 单取循环 2 循环播放
switch (item.getItemId()) {
case R.id.stop_when_over:
edit.putInt("mode", 0);
break;
case R.id.single_loop:
edit.putInt("mode", 1);
break;
case R.id.all_loop:
edit.putInt("mode", 2);
break;
case R.id.logout_app://退出应用
//退出应用
//1.通知栏去掉
mIMusic.callStopMusicService();
//2.关闭服务
unbindService(mConn);
Intent intent = new Intent(this,MusicService.class);
stopService(intent);
//3.界面退出
finish();
break;
}
edit.commit();//写入文件中回写s
return super.onOptionsItemSelected(item);
}

}

 

 


MusicAdapter.java


package com.li.musicPlay;

import java.util.ArrayList;

import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;

public class MusicAdapter extends BaseAdapter{

private ArrayList<String> mData;
public void setData(ArrayList<String> mData) {
this.mData=mData;
}
@Override
public int getCount() {
return mData!=null?mData.size():0;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
TextView textView=null;
if(convertView==null){
convertView=LayoutInflater.from(parent.getContext()).
inflate(android.R.layout.simple_list_item_1, null);
textView=(TextView)convertView.findViewById(android.R.id.text1);
convertView.setTag(textView);
}else{
textView=(TextView)convertView.getTag();
}
textView.setText(subFileName(mData.get(position))+"");

return convertView;
}
private String subFileName(String subName){
return subName.substring(subName.lastIndexOf("/")+1);
}
@Override
public Object getItem(int position) {
return mData.get(position)!=null?mData.get(position):null;
}

@Override
public long getItemId(int position) {
// TODO Auto-generated method stub
return 0;
}




}

 


MusicService.java


 

package com.li.musicPlay;


import java.util.ArrayList;

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.content.SharedPreferences;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnCompletionListener;
import android.os.Binder;
import android.os.IBinder;

public class MusicService extends Service{
private MediaPlayer mMediaPlayer;
private int mCurrentPosition;
@Override
public IBinder onBind(Intent intent) {

return new MusicAgent();
}
private class MusicAgent extends Binder implements IMusicService{

@Override
public void callPlayMusic(ArrayList<String> list,int position) {
playMusic(list,position);
}

@Override
public void callStopMusicService() {
stopMusicService();
}

}
/**
* 音乐播放器
* @param filePath 传过来的元路径
*/
public void playMusic(final ArrayList<String> list,final int position){
mCurrentPosition=position;
showNotification(list.get(mCurrentPosition).substring(list.get(mCurrentPosition).lastIndexOf("/")+1));
if(mMediaPlayer == null){
mMediaPlayer = new MediaPlayer();//player播放 IDEL空闲状态
//当音乐播放完成的时候调用的 根据当前的播放模式来决定是单曲循环还是其他
mMediaPlayer.setOnCompletionListener(new OnCompletionListener() {//音乐播放接听器

@Override
public void onCompletion(MediaPlayer mp) {
SharedPreferences shared= getSharedPreferences("music", MODE_PRIVATE);
int type=shared.getInt("mode", 0);
switch (type) {
case 1://单曲循环
playMusic(list,mCurrentPosition);//自己调用自己
break;
case 2://全部循环
mCurrentPosition++;
//如果加完了 此时索引大于队列的最后一个索引 就要变成0 0停止播放
if(mCurrentPosition>list.size()-1){
mCurrentPosition=0;
}
playMusic(list,mCurrentPosition);
break;
}
}
});
}
try {
//如果上一次有设置数据源了 再次进来需要重新释放资源
mMediaPlayer.reset();
mMediaPlayer.setDataSource(list.get(mCurrentPosition));//设置数据元
mMediaPlayer.prepare();//装备数据
mMediaPlayer.start();//开始播放
} catch (Exception e) {
e.printStackTrace();
}
}
private void showNotification(String musicName){
NotificationManager manager=(NotificationManager)getSystemService(NOTIFICATION_SERVICE);
Notification notification=new Notification(R.drawable.ic_launcher, musicName+"正在播放...", System.currentTimeMillis());

//PendingIntent.FLAG_ONE_SHOT 只显示一次
Intent intent = new Intent(this,MainActivity.class);
PendingIntent contentIntent =PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_ONE_SHOT);

notification.setLatestEventInfo(this, musicName+"正在播放...", musicName+"播放中....", contentIntent);
manager.notify(0,notification);
}
//取消标题栏上面的选项
private void CloseShow(){
NotificationManager manager=(NotificationManager)getSystemService(NOTIFICATION_SERVICE);
manager.cancelAll();
}
/**
* 停止播放
*/
public void stopMusicService(){
//1.取消通知栏
CloseShow();
//2.释放mMediaPlayer的资源
if(mMediaPlayer!=null){
mMediaPlayer.stop();//停止音乐服务
mMediaPlayer.release();//释放资源
mMediaPlayer=null;//重新设为空
}
}
}

 


IMusicService.java


 

package com.li.musicPlay;

import java.util.ArrayList;

public interface IMusicService {
//调用音乐路径
void callPlayMusic(ArrayList<String> list,int position);
//退出服务
void callStopMusicService();
}

 


activity_main.xml


 

<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">

<ListView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/listViewId"
/>

</LinearLayout>

 


main.xml


 

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="@+id/stop_when_over"
android:title="播放停止"/>
<item
android:id="@+id/single_loop"
android:title="单曲循环"/>
<item
android:id="@+id/all_loop"
android:title="全部循环"/>
<item
android:id="@+id/logout_app"
android:title="退出应用"/>
</menu>

 

举报

相关推荐

0 条评论