Reputation: 545
I'm creating a game that uses the Sphero robot ball. When the game starts up/resumes, it checks for a paired or connected ball. If bluetooth is off, or if there is no ball paired, it hides the connection window. If there is a ball paired, but not connected, it goes to this function.
// 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();
}
It crashes in the following method.
private void removeConnectionView() {
mFrameLayout.removeView(mSpheroConnectionView);
mSpheroConnectionView = null;
}
This function works on each other possible outcome. This is the error.
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
Upvotes: 1
Views: 338
Reputation: 31
You can only do UI related things from the main thread. Try creating a Handler using the main looper and posting runnables to that handler.
Ex.
private Handler mHandler = new Handler(Looper.getMainLooper());
.
.
.
mHandler.post(new Runnable() {
public void run() {
removeConnectionView();
}
});
Upvotes: 2
Reputation: 297
The removeConnectionView method is being called from a thread that isn't the main Looper thread (or, the "UI Thread"). View can only be modified from the main looper thread.
In order to fix this, instantiate a Handler sometime on the main Looper thread (such as when the view or Activity is created), and use the Hander#post(Runnable)
method to call your method, or use the View#post(Runnable)
method on your FrameLayout.
Example of the first kind:
Put this in the onCreate method of the Activity, which always runs in the main Looper thread.
mHandler = new Handler();
Then, when you want to run that method:
handler.post(new Runnable() {
@Override
public void run() {
mFrameLayout.removeView(mSpheroConnectionView);
mSpheroConnectionView = null;
}
});
Example of the second kind:
mFrameLayout.post(new Runnable() {
@Override
public void run() {
mFrameLayout.removeView(mSpheroConnectionView);
mSpheroConnectionView = null;
}
})
Upvotes: 5