本文共 13797 字,大约阅读时间需要 45 分钟。
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.对代理对象调用某个方法 代理对象在该方法内访问服务的方法采用接口暴露服务里面的方法
- 绑定服务 调用服务方法 的例子
- 我们发现 代理对象的方法我们都可以调用 那为了屏蔽代理对象其他方法 我们必须将其他方法设置为了私有 但是这样还不够彻底 因为我们可以用反射去调用其方法。 - 所以我们可以去创建一个公共接口 这样我们只需要知道接口的方法 到底是那个类在做代理 可以在运行时去指定
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 的生命周期
混合生命周期:(为了让服务能够一直运行 也为了让服务能够与界面UI交互数据 一般需要混合使用两种启动服务的方式)
startService()->bindService()->unBindService()-(服务还存在)-stopService();
onCreate()->onStartCommand()->onBind()->onUnBind()->onDestory();
本地服务和远程服务
1. 从启动方式来说:
开启服务 绑定服务
2. 服务的执行类型:
远程服务(AIDL服务 android interface definition language) 本地服务
绑定服务的应用场景
* 提供一个服务 后台运行里面有一些公共的逻辑供调用
* 1.微信支付/支付宝支付 微信有一个支付的服务,绑定,调用支付的方法(微信App提供了一个服务 大众点评支付的时候调用微信支付)
* 2.sony手机 人脸识别服务 绑定到这个服务传递一个照片 就会把人脸标记出来
* 3.音乐播放器 后台服务里面播放音乐 绑定服务暂停 下一曲 上一曲 (服务与APP的代码都在同一个包里面)
本地服务就是服务器在自己手机了开启的服务 自己调用他
远程服务就是服务器是另外一个软件的一个服务
支付宝远程服务的创建
AIDL:android interfacedefinition language 安卓接口定义语言
远程服务的调用开发步骤:
1. 在支付宝APP里面 创建一个服务 提供一个支付方法(主功能有了 其他应用能拿到服务)
2. 创建代理 为了规范 要先创建一个接口,服务里面有的支付方法 接口也应该用。
3. 为了让其他应用共享数据、服务,需要定义一个共同的规范.aidl (修改文件后缀)
支付宝的服务:
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; }}
支付宝绑定服务
支付宝里面的AIDL技术
淘宝里面的调用:
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); }}
音乐播放器的界面
开发步骤:
1. 将音乐放置到sd卡中
2. 创建音乐列表
3. 创建音乐服务 创建播放音乐的方法
4. 创建音乐服务的接口
5. 在音乐点击事件中调用音乐服务的调用
6. 设置播放模式 因为这里涉及到列表循环所以需要列表的信息和当前播放的索引 需要将服务的方法进行修改
7. 在播放的过程中需要在界面左上角添加提示框 因为每次播放都会在服务里面执行 所以可以在播放音乐的代码中弹出提示
8. 退出音乐应用 需要关闭提示框释放音乐资源解绑和停止服务关闭界面
附加知识点:
如何获取菜单的点击事件
如何创建提示栏
代码提示:
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 ArrayListmData;// 存放音乐的路径 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 (); // 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); } }
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 ArrayListmData; public void setData(ArrayList 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; } }
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(ArrayListlist,int position) { playMusic(list,position); } @Override public void callStopMusicService() { stopMusicService(); } } /** * 音乐播放器 * @param filePath 传过来的元路径 */ public void playMusic(final ArrayList 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;//重新设为空 } }}
package com.li.musicPlay;import java.util.ArrayList;public interface IMusicService { //调用音乐路径 void callPlayMusic(ArrayListlist,int position); //退出服务 void callStopMusicService();}
转载地址:https://liwangjiang.blog.csdn.net/article/details/79735802 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!