Android服务器的使用(Service)
发布日期:2021-06-30 21:21:40 浏览次数:2 分类:技术文章

本文共 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的代码都在同一个包里面)

 

 

 

 

 

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

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

 

支付宝远程服务的创建

 

AIDLandroid 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. 退出音乐应用 需要关闭提示框释放音乐资源解绑停止服务关闭界面

附加知识点:

如何获取菜单的点击事件

如何创建提示栏

 

 

代码提示:

 

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
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
(); // 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
mData; 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; } }

 

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
list,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;//重新设为空 } }}

 

IMusicService.java

 

package com.li.musicPlay;import java.util.ArrayList;public interface IMusicService {	//调用音乐路径	void callPlayMusic(ArrayList
list,int position); //退出服务 void callStopMusicService();}

 

activity_main.xml

 

 

main.xml

 

 

转载地址:https://liwangjiang.blog.csdn.net/article/details/79735802 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:Android的消息通知--Notification
下一篇:Android后台服务Service

发表评论

最新留言

关注你微信了!
[***.104.42.241]2024年04月06日 06时54分07秒