在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