在android项目中用到AIDL,今天碰到了一个诡异的问题,花费了半天的时间终于解决了。具体原因有待细究
bindService( service, connection, BIND_AUTO_CREATE ) 之后一直不调用
connection中的onServiceConnected方法
复查了很多容易出错的问题(有问题的童鞋可以复查下面几条):
1、服务器端的service声明,要和客户端bindService的第一个参数匹配,不然客户端启动不了这个服务。
<service
android:name="com.eebbk.keywordsearch.ExamCommentService"
android:process=":remote" >
<intent-filter>
<!-- AIDL完整路径名。必须指明,客户端能够通过AIDL类名查找到它的实现类 -->
<action android:name="com.eebbk.keywordsearch.ITestService" />
</intent-filter>
</service>
2、服务器端service必须 return实现AIDL接口ITestService.Stub 的binder
@Override
public IBinder onBind( Intent intent )
{
// TODO Auto-generated method stub
return binder; // 返回AIDL接口实例化对象;
}
3、如果前面两种方法都没有解决,那么很有可能就是我要提到的这个问题了,往下看
我的问题代码如下:
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.util.Log; /** * Class Name: SearchClientActivity.java Function: * * Modifications: * * @author tm DateTime 2013-1-23 下午4:20:20 * @version 1.0 */ public class SearchClientActivity extends Activity { private static final String TAG = "SearchClientActivity"; private ITestService tService = null; // 创建远程调用对象 private ServiceConnection connection = new ServiceConnection( ) { public void onServiceConnected( ComponentName name, IBinder service ) { // TODO Auto-generated method stub // 从远程service中获得AIDL实例化对象 tService = ITestService.Stub.asInterface( service ); System.out.println( "Bind Success:" + tService ); } public void onServiceDisconnected( ComponentName name ) { // TODO Auto-generated method stub tService = null; } }; @Override protected void onCreate( Bundle savedInstanceState ) { // TODO Auto-generated method stub super.onCreate( savedInstanceState ); setContentView( R.layout.main ); Intent service = new Intent( ITestService.class.getName( ) ); // 绑定AIDL bindService( service, connection, BIND_AUTO_CREATE ); //tService为空 死循环等待异步任务结束 while ( tService == null ) { Thread.sleep( 500 ); } try { //在客户端调用服务器端的方法 List< SearchResultItem > resultItems = tService.getSearchResulet( "" ); for ( int i = 0; i < resultItems.size( ); i++ ) { Log.i( TAG, resultItems.get( i ).getIndex( ) + resultItems.get( i ).getDetailContent( ) ); } } catch ( RemoteException e ) { // TODO Auto-generated catch block e.printStackTrace( ); } } @Override protected void onDestroy( ) { // TODO Auto-generated method stub super.onDestroy( ); unbindService( connection ); } }
结果一直陷入死循环,不跑onServiceConnected方法。
解决方法:不要在onCreate中等待得到AIDL的接口服务实例,即上面代码中的tService
import java.util.List; 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.util.Log; import android.widget.ListView; import com.eebbk.searchclientaidl.R; public class SearchClientAIDLActivity extends Activity { private static final String TAG = "SearchClientAIDLActivity"; private ITestService tService; //创建远程调用对象 private ServiceConnection connection = new ServiceConnection(){ public void onServiceConnected(ComponentName name, IBinder service) { // TODO Auto-generated method stub System.out.println(" onServiceConnected "); //从远程service中获得AIDL实例化对象 tService = ITestService.Stub.asInterface(service); System.out.println("Bind Success:"+tService); new Thread( new Runnable( ) { @Override public void run( ) { Log.v( TAG, "开启新线程!" ); getResults( ); } } ).start( ); } public void onServiceDisconnected(ComponentName name) { // TODO Auto-generated method stub tService = null; } }; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Intent service = new Intent( ITestService.class.getName()); //绑定AIDL bindService(service, connection, BIND_AUTO_CREATE); } private void getResults() { try { List< SearchResultItem > resultItems = tService.getSearchResulet( "" ); for ( int i = 0; i < resultItems.size( ); i++ ) { Log.i( TAG, resultItems.get( i ).getIndex( ) + resultItems.get( i ).getDetailContent( ) ); } } catch ( RemoteException e ) { // TODO Auto-generated catch block e.printStackTrace(); } } @Override protected void onDestroy( ) { // TODO Auto-generated method stub super.onDestroy( ); unbindService( connection ); } }
bindService的具体流程可以参考
http://blog.csdn.net/luoshengyang/article/details/6745181
#import <UIKit/UIKit.h> @interface UIView (Positioning) - (void)centerInRect:(CGRect)rect; - (void)centerVerticallyInRect:(CGRect)rect; - (void)centerHorizontallyInRect:(CGRect)rect; - (void)centerInSuperView; - (void)centerVerticallyInSuperView; - (void)centerHorizontallyInSuperView; - (void)centerHorizontallyBelow:(UIView *)view padding:(CGFloat)padding; - (void)centerHorizontallyBelow:(UIView *)view; @end #import "UIView+Positioning.h" #import "UIView+Size.h" @implementation UIView (Positioning) //针对给定的坐标系居中 - (void)centerInRect:(CGRect)rect; { //如果参数是小数,则求最大的整数但不大于本身. //CGRectGetMidX获取中心点的X轴坐标 [self setCenter:CGPointMake(floorf(CGRectGetMidX(rect)) + ((int)floorf([self width]) % 2 ? .5 : 0) , floorf(CGRectGetMidY(rect)) + ((int)floorf([self height]) % 2 ? .5 : 0))]; } //针对给定的坐标系纵向居中 - (void)centerVerticallyInRect:(CGRect)rect; { [self setCenter:CGPointMake([self center].x, floorf(CGRectGetMidY(rect)) + ((int)floorf([self height]) % 2 ? .5 : 0))]; } //针对给定的坐标系横向居中 - (void)centerHorizontallyInRect:(CGRect)rect; { [self setCenter:CGPointMake(floorf(CGRectGetMidX(rect)) + ((int)floorf([self width]) % 2 ? .5 : 0), [self center].y)]; } //相对父视图居中 - (void)centerInSuperView; { [self centerInRect:[[self superview] bounds]]; } - (void)centerVerticallyInSuperView; { [self centerVerticallyInRect:[[self superview] bounds]]; } - (void)centerHorizontallyInSuperView; { [self centerHorizontallyInRect:[[self superview] bounds]]; } //同一父视图的兄弟视图水平居中 - (void)centerHorizontallyBelow:(UIView *)view padding:(CGFloat)padding; { // for now, could use screen relative positions. NSAssert([self superview] == [view superview], @"views must have the same parent"); [self setCenter:CGPointMake([view center].x, floorf(padding + CGRectGetMaxY([view frame]) + ([self height] / 2)))]; } - (void)centerHorizontallyBelow:(UIView *)view; { [self centerHorizontallyBelow:view padding:0]; } @end
#import <UIKit/UIKit.h> @interface UIView (Size) @property (nonatomic, assign) CGSize size; @property (nonatomic, assign) CGFloat left; @property (nonatomic, assign) CGFloat right; @property (nonatomic, assign) CGFloat top; @property (nonatomic, assign) CGFloat bottom; @property (nonatomic, assign) CGFloat centerX; @property (nonatomic, assign) CGFloat centerY; @property (nonatomic, assign) CGFloat width; @property (nonatomic, assign) CGFloat height; @end #import "UIView+Size.h" @implementation UIView (Size) - (void)setSize:(CGSize)size; { CGPoint origin = [self frame].origin; [self setFrame:CGRectMake(origin.x, origin.y, size.width, size.height)]; } - (CGSize)size; { return [self frame].size; } - (CGFloat)left; { return CGRectGetMinX([self frame]); } - (void)setLeft:(CGFloat)x; { CGRect frame = [self frame]; frame.origin.x = x; [self setFrame:frame]; } - (CGFloat)top; { return CGRectGetMinY([self frame]); } - (void)setTop:(CGFloat)y; { CGRect frame = [self frame]; frame.origin.y = y; [self setFrame:frame]; } - (CGFloat)right; { return CGRectGetMaxX([self frame]); } - (void)setRight:(CGFloat)right; { CGRect frame = [self frame]; frame.origin.x = right - frame.size.width; [self setFrame:frame]; } - (CGFloat)bottom; { return CGRectGetMaxY([self frame]); } - (void)setBottom:(CGFloat)bottom; { CGRect frame = [self frame]; frame.origin.y = bottom - frame.size.height; [self setFrame:frame]; } - (CGFloat)centerX; { return [self center].x; } - (void)setCenterX:(CGFloat)centerX; { [self setCenter:CGPointMake(centerX, self.center.y)]; } - (CGFloat)centerY; { return [self center].y; } - (void)setCenterY:(CGFloat)centerY; { [self setCenter:CGPointMake(self.center.x, centerY)]; } - (CGFloat)width; { return CGRectGetWidth([self frame]); } - (void)setWidth:(CGFloat)width; { CGRect frame = [self frame]; frame.size.width = width; [self setFrame:CGRectStandardize(frame)]; } - (CGFloat)height; { return CGRectGetHeight([self frame]); } - (void)setHeight:(CGFloat)height; { CGRect frame = [self frame]; frame.size.height = height; [self setFrame:CGRectStandardize(frame)]; } @end