Binder初尝

首先看的书是《Android内核剖析》,先讲下书上的Binder架构:


分3部分,客户端,服务端和Binder驱动

首先来看服务端。一个Binder 服务端实际上就是一个Binder 类的对象,该对象一旦创建,内部就启动一个隐藏线程。该线程接下来会接收Binder 驱动发送的消息,收到消息后,会执行到Binder 对象中的onTransact()函数,并按照该函数的参数执行不同的服务代码。

面再看Binder 驱动。任意一个服务端Binder 对象被创建时,同时会在Binder 驱动中创建一个mRemote 对象,该对象的类型也是Binder 类。客户端要访问远程服务时,都是通过mRemote 对象。

最后来看应用程序客户端。客户端要想访问远程服务,必须获取远程服务在Binder 对象中对应的mRemote 引用,获得该mRemote 对象后,就可以调用其transact()方法。


先来看服务端,上面也说了Binder服务端实际上就是一个Binder类对象,因此设计一个MusicPlayerServer类:

public class MusicPlayerServer extends Binder
{
	
	@Override
	protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
			throws RemoteException
	{
		// TODO Auto-generated method stub
		if(code==1000)
		{
			data.enforceInterface("MusicPlayerServer");//检验包裹名,用于安全操作,对应于包包裹是所加的包裹名
			String filepath=data.readString();
			start(filepath);
		}
		return super.onTransact(code, data, reply, flags);
	}
	
	public void start(String filepath)
	{
		Log.e("TEST", "MusicPlayerServer--start--"+filepath);
	}
	public void stop()
	{
		
	}

}
服务端有start()和stop()函数,重载了onTransact()函数。服务端接收到信息的时候执行的函数不是start,stop而是onTransact,根据它的参数code的值你可以约定code==1000的时候执行哪些代码,例如运行start(),再如code==2000的时候执行stop()之类。如果start()这些函数有参数怎么办?Parcel包裹类data中就包含了很多参数,按约定的顺序从data包裹中取出数据。


客户端的设计:

首先要获取mRemote对象,这个先不说怎获取,获取之后要怎做?

String filepath="cnraw.mp3";
Parcel data=Parcel.obtain();
Parcel reply=Parcel.obtain();
data.writeInterfaceToken("MusicPlayerServer");
data.writeString(filepath);
try
{
	binder.transact(1000, data, reply, 0);
} catch (RemoteException e)
{
	// TODO Auto-generated catch block
	e.printStackTrace();
}
申请包裹,写包裹名,写参数到包裹中,利用获得的mRemote对象,代码中的binder来调用transact()。

然后重点来了,怎样获得mRemote对象,利用bindservice(),一个Service通过bindservice创建的生命周期:onCreate()--->onBind()--->onUnbind()--->onDestroy()

public boolean bindService(Intent service, ServiceConnection conn, int flags);

其中ServiceConnection有2个回调函数:

public void onServiceConnected(ComponentName name, IBinder service);//绑定服务成功时回调,应该是onBind()之后调用
public void onServiceDisconnected(ComponentName name);//解除绑定是回调,应该是onUnbind()之前调用


下面是完整的代码:

服务端:

package com.example.bindertest;

import android.media.MediaPlayer;
import android.os.Binder;
import android.os.Parcel;
import android.os.RemoteException;
import android.util.Log;

public class MusicPlayerServer extends Binder
{
	
	@Override
	protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
			throws RemoteException
	{
		// TODO Auto-generated method stub
		if(code==1000)
		{
			data.enforceInterface("MusicPlayerServer");
			String filepath=data.readString();
			start(filepath);
		}
		return super.onTransact(code, data, reply, flags);
	}
	
	public void start(String filepath)
	{
		Log.e("TEST", "MusicPlayerServer--start--"+filepath);
	}
	public void stop()
	{
		
	}

}
客户端:


package com.example.bindertest;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Binder;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcel;
import android.os.RemoteException;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;

public class MainActivity extends Activity
{

	Button bindButton,unbindButton,workButton;
	MusicPlayerServer binder;
	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		final Intent intent=new Intent(MainActivity.this, MyService.class);
		bindButton=(Button) findViewById(R.id.start_btn);
		unbindButton=(Button) findViewById(R.id.stop_btn);
		workButton=(Button) findViewById(R.id.work_btn);
		
		final ServiceConnection conn=new ServiceConnection()
		{
			
			@Override
			public void onServiceDisconnected(ComponentName arg0)
			{
				// TODO Auto-generated method stub
				
			}
			
			@Override
			public void onServiceConnected(ComponentName arg0, IBinder arg1)
			{
				// TODO Auto-generated method stub
				binder=(MusicPlayerServer) arg1;
			}
		};
		
		bindButton.setOnClickListener(new View.OnClickListener()
		{
			
			@Override
			public void onClick(View arg0)
			{
				// TODO Auto-generated method stub
				bindService(intent, conn, BIND_AUTO_CREATE);
			}
		});
		
		unbindButton.setOnClickListener(new View.OnClickListener()
		{
			
			@Override
			public void onClick(View arg0)
			{
				// TODO Auto-generated method stub
				unbindService(conn);
				if(binder!=null)
				{
					Log.e("TEST", "binder is not null");
				}
			}
		});
		
		workButton.setOnClickListener(new View.OnClickListener()
		{
			
			@Override
			public void onClick(View arg0)
			{
				// TODO Auto-generated method stub
				String filepath="cnraw.mp3";
				Parcel data=Parcel.obtain();
				Parcel reply=Parcel.obtain();
				data.writeInterfaceToken("MusicPlayerServer");
				data.writeString(filepath);
				try
				{
					binder.transact(1000, data, reply, 0);
				} catch (RemoteException e)
				{
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		});
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu)
	{
		// Inflate the menu; this adds items to the action bar if it is present.
		getMenuInflater().inflate(R.menu.main, menu);
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item)
	{
		// Handle action bar item clicks here. The action bar will
		// automatically handle clicks on the Home/Up button, so long
		// as you specify a parent activity in AndroidManifest.xml.
		int id = item.getItemId();
		if (id == R.id.action_settings)
		{
			return true;
		}
		return super.onOptionsItemSelected(item);
	}
}

Service:

package com.example.bindertest;

import android.app.Service;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.Binder;
import android.os.IBinder;
import android.util.Log;

public class MyService extends Service
{

	private MediaPlayer mediaPlayer;
	MusicPlayerServer musicPlayerServer = new MusicPlayerServer();
	
	@Override
	public IBinder onBind(Intent arg0)
	{
		// TODO Auto-generated method stub
		Log.e("TEST", "----onBind----");
		return musicPlayerServer;
	}

	@Override
	public void onCreate()
	{
		// TODO Auto-generated method stub
		Log.e("TEST", "----onCreate----");
		mediaPlayer=MediaPlayer.create(MyService.this, R.raw.cnwav);
		super.onCreate();
	}

	@Override
	public void onDestroy()
	{
		// TODO Auto-generated method stub
		Log.e("TEST", "----onDestroy----");
		mediaPlayer.stop();
		super.onDestroy();
	}

	@Override
	@Deprecated
	public void onStart(Intent intent, int startId)
	{
		// TODO Auto-generated method stub
		Log.e("TEST", "----onStart----");
		mediaPlayer.start();
		super.onStart(intent, startId);
	}

	@Override
	public boolean onUnbind(Intent intent)
	{
		// TODO Auto-generated method stub
		Log.e("TEST", "----onUnbind----");
		return super.onUnbind(intent);
	}

}
下面按申请服务到得到服务的顺序浏览依次代码:

(1)按bindService按钮

(2)对应的Listener代码bindService(intent, conn, BIND_AUTO_CREATE);

(3)MyService的onCreate,mediaPlayer=MediaPlayer.create(MyService.this, R.raw.cnwav);注意这里没mediaPlayer.start()所以不会播放

(4)MyService的onBind,不执行onStart,因为不是用startservice启动的service,所以因为不会播放,return musicPlayerServer;

(5)conn的onServiceConnected(ComponentName arg0, IBinder arg1),binder=(MusicPlayerServer) arg1; 保存得到的服务端

(6)按workButton

(7)对应的Listener代码binder.transact(1000, data, reply, 0);给binder发信息

(8)MusicPlayerServer的onTransact,根据code==1000执行start()的Log.e("TEST", "MusicPlayerServer--start--"+filepath);

(9)按unbindservice按钮

(10)执行对应的Listener代码,unbindService(conn);

(11)conn的onServiceDisconnected(ComponentName arg0)

(12)MyService的onunbind,onDestroy,注意此时客户端的binder仍然保留着,依旧可以按workButton来向MusicePlayerServer申请服务


总的来说就是Service担当了客户端获取服务器Binder的角色,目前所有程序都是同一进程内运行,还没真正发挥出binder跨进程交流的作用,在下一章中再展示吧,2个APP之间调用MusicePlayerServer的transact函数。





期末大作业基于python的足球运动员数据分析源码+数据集(高分项目),个人经导师指导并认可通过的高分设计项目,评审分98分,项目中的源码都是经过本地编译过可运行的,都经过严格调试,确保可以运行!主要针对计算机相关专业的正在做大作业、毕业设计的学生和需要项目实战练习的学习者,资源项目的难度比较适中,内容都是经过助教老师审定过的能够满足学习、使用需求,如果有需要的话可以放心下载使用。 期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于python的足球运动员数据分析源码+数据集(高分项目)期末大作业基于pyth
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值