android in practice_Making remote procedure calls(GoodShares project)

You need to pass data to another app so that it can perform some operation on that data and return a result back to your app. You don’t want to give up control flow to this other application; you want to interact with it unseen.

The key technology is to use an Android Service.remote procedure call (RPC).

the ImageMash appmust expose a Service that can be called by the GoodShares app’s Activity.


synchronously. The GoodShares app calls the ImageMash Service and waits for a response.After receiving a response, GoodShares updates the UI. To enable this kind of interaction, the GoodShares Activity must bind to the Service and directly invoke an operation on the Service.

To share data with another app’s Service in a synchronous manner; your app must have the AIDL that describes that Service. Similarly, if you want to allow other apps to integrate with a Service in your app, you must provide an AIDL.

create ShareRpcActivity class:

public class ShareRpcActivity extends Activity {
		Uri photoUri0;
		IMashService mashService;//generated interface representing remote service
		Button mashButton;
		int bindCount=0;
		ServiceConnection conn=new ServiceConnection(){
			@Override
			//callback once service is bound
			public void onServiceConnected(ComponentName name, IBinder service) {
				// TODO Auto-generated method stub
				mashService=IMashService.Stub.asInterface(service);
				mashButton.setEnabled(true);
			}
			@Override
			public void onServiceDisconnected(ComponentName name) {
				// TODO Auto-generated method stub
				mashService=null;
				mashButton.setEnabled(false);
			}
		};
		protected void onCreate(Bundle savedInstanceState){
			super.onCreate(savedInstanceState);
			setContentView(R.layout.share_rpc);
			
			Button button=(Button)findViewById(R.id.btn0);
			button.setOnClickListener(new OnClickListener(){
				@Override
				public void onClick(View v) {
					// TODO Auto-generated method stub
					Intent request=new Intent(Intent.ACTION_GET_CONTENT);
					request.setType("image/*");
					startActivityForResult(request,0);
				}
				
			});
			
			mashButton=(Button)findViewById(R.id.button);
			CheckBox syncBox=(CheckBox)findViewById(R.id.syncBox);
			syncBox.setOnCheckedChangeListener(new OnCheckedChangeListener(){
				@Override
				public void onCheckedChanged(CompoundButton buttonView,
						boolean isChecked) {
					// TODO Auto-generated method stub
					if(isChecked){
						mashButton.setEnabled(false);
						//bind to remote service
						bindService(new Intent("example.mash.ACTION"),conn,Context.BIND_AUTO_CREATE);
						bindCount++;
					}else{
						bindCount--;
						if(bindCount==0){
							unbindService(conn);
						}
						mashButton.setEnabled(true);
					}
				}
			});
			
			mashButton.setOnClickListener(new OnClickListener(){
				@Override
				public void onClick(View v) {
					// TODO Auto-generated method stub
	                EditText input0 = (EditText) findViewById(R.id.input0);
	                float scaleX = Float.parseFloat(input0.getText().toString());
	                EditText input1 = (EditText) findViewById(R.id.input1);
	                float scaleY = Float.parseFloat(input1.getText().toString());
	                EditText input2 = (EditText) findViewById(R.id.input2);
	                float angle = Float.parseFloat(input2.getText().toString());
	                Uri result;
	                if(bindCount>0){
	                	try{
	                		//synchronous
	                		//invoke remote service
	                		result=mashService.mash(photoUri0, scaleX, scaleY, angle);
	                		//use result to update UI
	                		ImageView image=(ImageView)findViewById(R.id.image);
	                		image.setImageURI(result);
	                	}catch(RemoteException e){
	                		 e.printStackTrace();
	                	}
	                }else{
	                	//asynchronous
	                	Intent request=new Intent("example.mash.ACTION");
	                	request.putExtra("example.mash.EXTRA_PHOTO", photoUri0);
	                	request.putExtra("example.mash.EXTRA_SCALE_X", scaleX);
	                	request.putExtra("example.mash.EXTRA_SCALE_Y", scaleY);
	                	request.putExtra("example.mash.EXTRA_ANGLE", angle);
	                	startService(request);
	                	/*
	                	 * The Service will receive it and 
	                	 * respond by broadcasting an Intent with the response data in it.
	                	 */
	                }
				}		
			});
			mashButton.setEnabled(true);
			//implement BroadcastReceiver
			BroadcastReceiver receiver=new BroadcastReceiver(){
				@Override
				public void onReceive(Context context, Intent intent) {
					// TODO Auto-generated method stub
					//pull data from extras
					Uri result=intent.getParcelableExtra("example.mash.EXTRA_RESULT");
					ImageView image=(ImageView)findViewById(R.id.image);
					image.setImageURI(result);
				}
			};
			
			IntentFilter filter=new IntentFilter();
			//the action that will be used by Service
			filter.addAction("example.mash.ACTION_RESPONSE");
			this.registerReceiver(receiver, filter);//register with IntentFilter
			
		}

		protected void onActivityResult(int requestCode, int resultCode, Intent data ){
			if(requestCode==0){
				photoUri0=(Uri)data.getParcelableExtra(Intent.EXTRA_STREAM);
				if(photoUri0==null&&data.getData()!=null){
					photoUri0=data.getData();
				}
				ImageView imgView0=(ImageView)findViewById(R.id.pic0);
				imgView0.setImageURI(photoUri0);
			}
		}
		
		public static void start(Context context){
			Intent i=new Intent(context,ShareRpcActivity.class);
			context.startActivity(i);
		}
}

create IMashService.aidl

package example.mash;
import android.net.Uri;
interface IMashService{
Uri mash(in Uri uri, float scaleX, float scaleY, float angle);
}

create MashService class in ImageMash app:

public class MashService extends Service {
	private IMashService.Stub stub;
	public int onStartCommand(Intent intent,int flags, int startId) {
		    Uri imageUri=intent.getParcelableExtra("example.mash.EXTRA_PHOTO");
		    float scaleX=intent.getFloatExtra("example.mash.EXTRA_SCALE_X",1.0f);
		    float scaleY=intent.getFloatExtra("example.mash.EXTRA_SCALE_Y",1.0f);
		    float angle=intent.getFloatExtra("example.mash.EXTRA_ANGLE", 0.0f);
		    try{
		    	Uri resultUri=stub.mash(imageUri, scaleX, scaleY, angle);
		    	//put the appropriate action on the intent
		    	Intent response=new Intent("example.mash.EXTRA_RESPONSE");
		    	response.putExtra("example.mash.EXTRA_RESULT", resultUri);
		    	sendBroadcast(response);//broadcast the intent
		    }catch(RemoteException e){
		    	Log.e("MashService", "Exception mashing image async", e);
		    }
		    return START_STICKY;
			}
	@Override
	public IBinder onBind(Intent arg0) {
		// TODO Auto-generated method stub
		return null;
	}

}
In this case, only one type of Intent is being sent in, but if there were more than one then you could check what the action is to figure out what kind of request it is. Once you know the request type, you can pull out the appropriate data from the Intent.

In the synchronous mode, the interface is explicit and defined—in the AIDL. You know exactly how to call the Service and the response is immediate (in the sense that your thread will block until the Service gets a response—be careful about doing this on the main UI thread). In the asynchronous case, nothing is as explicit. You still must know the names and types of the data that the Service expects and produces, but this doesn’t come in the form of code (AIDL). This arrangement can be more error prone. Furthermore, you also need to know the name of the action to use to send it to the Service, as well as the name of the action to use to register a BroadcastReceiver to get the response back from the Service.

Synchronous and asynchronous don’t need to be mutually exclusive. For example, let’s say you expose a Service for synchronous usage via AIDL. But suppose that one
of your operations could take a long time. Now the Activity that binds to the Service could do so from an AsyncTask or similar, so that the UI thread isn’t blocked while your Service does all of its work. So it might be okay for this operation to take a long time. But you could alternatively return a message saying that request was received, but that some or all of the response will come later. Then your Service could broadcast an Intent with more data later on as it becomes available.

This is a common technique to use if your Service contains a local cache of data that’s ultimately stored somewhere in the cloud.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值