1

我正在创建一个使用 Sphero 机器人球的游戏。当游戏开始/恢复时,它会检查配对或连接的球。如果蓝牙关闭,或者没有配对球,它会隐藏连接窗口。如果有球配对但未连接,则转到此功能。

// If the user clicked a Sphero and it failed to connect, this event will be fired
@Override
public void onRobotConnectionFailed(Robot robot) {
    Log.d("activity", "onRobotConnectionFailed");
    removeConnectionView();
}

它在以下方法中崩溃。

private void removeConnectionView() {
    mFrameLayout.removeView(mSpheroConnectionView);
    mSpheroConnectionView = null;
}

此功能适用于彼此可能的结果。这是错误。

Thread [<14> Thread-2606] (Suspended (exception ViewRootImpl$CalledFromWrongThreadException))   
<VM does not provide monitor information>   
ViewRootImpl.checkThread() line: 5031   
ViewRootImpl.invalidateChildInParent(int[], Rect) line: 998 
FrameLayout(ViewGroup).invalidateChild(View, Rect) line: 4358   
ImageView(View).invalidate(boolean) line: 10565 
ImageView(View).invalidate() line: 10520    
ImageView.invalidateDrawable(Drawable) line: 202    
XDrawable(Drawable).invalidateSelf() line: 382  
XDrawable(Drawable).setVisible(boolean, boolean) line: 578  
ImageView.onDetachedFromWindow() line: 1196 
ImageView(View).dispatchDetachedFromWindow() line: 12136    
FrameLayout(ViewGroup).dispatchDetachedFromWindow() line: 2824  
RelativeLayout(ViewGroup).dispatchDetachedFromWindow() line: 2824   
SpheroConnectionView$SpheroItemView(ViewGroup).dispatchDetachedFromWindow() line: 2824  
SpheroConnectionView$SpheroListView(ViewGroup).dispatchDetachedFromWindow() line: 2824  
SpheroConnectionView(ViewGroup).dispatchDetachedFromWindow() line: 2824 
FrameLayout(ViewGroup).removeViewInternal(int, View) line: 3943 
FrameLayout(ViewGroup).removeViewInternal(View) line: 3918  
FrameLayout(ViewGroup).removeView(View) line: 3850  
discgroove.removeConnectionView() line: 233 
discgroove.access$4(discgroove) line: 232   
discgroove$2.onRobotConnectionFailed(Robot) line: 191   
SpheroConnectionView$4.onRobotConnectionFailed(Robot) line: 157 
RobotProvider.update(Observable, Object) line: 570  
Robot(Observable).notifyObservers(Object) line: 138 
Robot.setConnected(boolean) line: 300   
DeviceConnection$4.run() line: 378  
4

2 回答 2

5

从不是主 Looper 线程(或“UI 线程”)的线程调用 removeConnectionView 方法。只能从主循环线程修改视图。

为了解决这个问题,在 Looper 主线程的某个时间(例如创建视图或 Activity 时)实例化一个 Handler,并使用该Hander#post(Runnable)方法来调用您的方法,或者View#post(Runnable)在您的 FrameLayout 上使用该方法。

第一类示例:

把它放在Activity的onCreate方法中,它总是在Looper主线程中运行。

mHandler = new Handler();

然后,当您要运行该方法时:

    handler.post(new Runnable() {
        @Override
        public void run() {

            mFrameLayout.removeView(mSpheroConnectionView);
            mSpheroConnectionView = null;
        }
    });

第二种例子:

    mFrameLayout.post(new Runnable() {
        @Override
        public void run() {
            mFrameLayout.removeView(mSpheroConnectionView);
            mSpheroConnectionView = null;
        }
    })
于 2013-04-26T22:17:05.203 回答
2

你只能从主线程做 UI 相关的事情。尝试使用主循环器创建一个 Handler 并将 runnables 发布到该处理程序。

前任。

private Handler mHandler = new Handler(Looper.getMainLooper());
.
.
.
mHandler.post(new Runnable() {
        public void run() {
            removeConnectionView();
        }
    });
于 2013-04-26T22:21:15.163 回答