Android 为什么我的HandlerThread会更新UI
我目前正在用一个简单的摄像头示例在Android中练习Android 为什么我的HandlerThread会更新UI,android,multithreading,Android,Multithreading,我目前正在用一个简单的摄像头示例在Android中练习HandlerThread,问题是如果我在onCreate中创建我的CameraController对象,并向处理线程发送一条消息,以便处理我的openCamera()方法(其中包含直接的UI更新代码) 它允许我更新用户界面,尽管我不应该被允许这样做,因为从技术上讲,我应该在一个不同的线程中 public class MainActivity extends AppCompatActivity implements Handler.Callb
HandlerThread
,问题是如果我在onCreate
中创建我的CameraController
对象,并向处理线程发送一条消息,以便处理我的openCamera()
方法(其中包含直接的UI更新代码)
它允许我更新用户界面,尽管我不应该被允许这样做,因为从技术上讲,我应该在一个不同的线程中
public class MainActivity extends AppCompatActivity implements Handler.Callback {
private ToggleButton toggleButton;
private TextView textView;
private CameraController mTestCam;
//generate messages
private static final int MSG_OPEN_CAM = 0;
private static final int MSG_CLOSE_CAM = 1;
private static final int MSG_OPEN_FLASH= 2;
private static final int MSG_CLOSE_FLASH = 3;
//verify
private static final int MSG_OPEN_CAM_DONE = 4; // nu trebuie
private static final int MSG_CLOSE_CAM_DONE = 5;
private static final int MSG_OPEN_FLASH_DONE= 6;
private static final int MSG_CLOSE_FLASH_DONE= 7;
//used for MainActivity HandleMessage
protected Handler mHandler;
//camera controler thread
private CameraControllerThread mCameraControlThread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//android marshmallow - in order for service to run you need runtime permissions
//testCam.openCamera(); //moved to method
toggleButton = (ToggleButton) findViewById(R.id.toggleButton);
textView = (TextView) findViewById(R.id.textView_text);
mHandler = new Handler(this);
mCameraControlThread = new CameraControllerThread("Camera Control Thread");
mCameraControlThread.start();
//moved to onStart
mTestCam = new CameraController();
Message openCameraMsg = mCameraControlThread.mWorkerHandler.obtainMessage(this.MSG_OPEN_CAM);
openCameraMsg.sendToTarget();
toggleButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) {
if(isChecked){
mTestCam = new CameraController();
Message openCameraMsg = mCameraControlThread.mWorkerHandler
.obtainMessage(MSG_OPEN_CAM);
openCameraMsg.sendToTarget();
//mTestCam.openFlash();
} else {
//close flash
//mTestCam.stopFlash();
}
}
});
}
private void openCamera(){
synchronized (mTestCam){
mTestCam.openCamera();
}
Toast.makeText(this, "This is my text", Toast.LENGTH_LONG).show();
textView.setVisibility(View.VISIBLE);
textView.setText("Camera Open");
}
@Override
public boolean handleMessage(Message message) {
return false;
}
private class CameraControllerThread extends HandlerThread implements Handler.Callback{
protected Handler mWorkerHandler;
public CameraControllerThread(String name){
super(name);
}
@Override
protected void onLooperPrepared() {
mWorkerHandler = new Handler(getLooper(), this);
}
@Override
public boolean handleMessage(Message message) {
switch(message.what){
case MSG_OPEN_CAM:
openCamera();
break;
}
return true;
}
}
}
如果我移动codeonCheckedChanged
方法(它在下面的代码片段中有注释),应用程序将崩溃,说明我正在尝试从其他线程更新UI线程
public class MainActivity extends AppCompatActivity implements Handler.Callback {
private ToggleButton toggleButton;
private TextView textView;
private CameraController mTestCam;
//generate messages
private static final int MSG_OPEN_CAM = 0;
private static final int MSG_CLOSE_CAM = 1;
private static final int MSG_OPEN_FLASH= 2;
private static final int MSG_CLOSE_FLASH = 3;
//verify
private static final int MSG_OPEN_CAM_DONE = 4; // nu trebuie
private static final int MSG_CLOSE_CAM_DONE = 5;
private static final int MSG_OPEN_FLASH_DONE= 6;
private static final int MSG_CLOSE_FLASH_DONE= 7;
//used for MainActivity HandleMessage
protected Handler mHandler;
//camera controler thread
private CameraControllerThread mCameraControlThread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//android marshmallow - in order for service to run you need runtime permissions
//testCam.openCamera(); //moved to method
toggleButton = (ToggleButton) findViewById(R.id.toggleButton);
textView = (TextView) findViewById(R.id.textView_text);
mHandler = new Handler(this);
mCameraControlThread = new CameraControllerThread("Camera Control Thread");
mCameraControlThread.start();
//moved to onStart
mTestCam = new CameraController();
Message openCameraMsg = mCameraControlThread.mWorkerHandler.obtainMessage(this.MSG_OPEN_CAM);
openCameraMsg.sendToTarget();
toggleButton.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(CompoundButton compoundButton, boolean isChecked) {
if(isChecked){
mTestCam = new CameraController();
Message openCameraMsg = mCameraControlThread.mWorkerHandler
.obtainMessage(MSG_OPEN_CAM);
openCameraMsg.sendToTarget();
//mTestCam.openFlash();
} else {
//close flash
//mTestCam.stopFlash();
}
}
});
}
private void openCamera(){
synchronized (mTestCam){
mTestCam.openCamera();
}
Toast.makeText(this, "This is my text", Toast.LENGTH_LONG).show();
textView.setVisibility(View.VISIBLE);
textView.setText("Camera Open");
}
@Override
public boolean handleMessage(Message message) {
return false;
}
private class CameraControllerThread extends HandlerThread implements Handler.Callback{
protected Handler mWorkerHandler;
public CameraControllerThread(String name){
super(name);
}
@Override
protected void onLooperPrepared() {
mWorkerHandler = new Handler(getLooper(), this);
}
@Override
public boolean handleMessage(Message message) {
switch(message.what){
case MSG_OPEN_CAM:
openCamera();
break;
}
return true;
}
}
}
我想我的问题是-为什么我实例化我的CameraController
并从onCreate
发送消息-它允许我更新UI-当我从onCheckedChangeListener
执行同样的操作时,它不允许我?引用:
[从UI线程外部访问Android UI toolkit]可能会导致未定义和意外的行为,这可能很难且耗时地跟踪
任何事情都可能在竞争条件之后发生。扩展
HandlerThread
在大多数情况下都是多余的:只需创建新的HT
,start()
它并创建一个新的处理程序(HT.getLooper())
,这就是我在教程中学习的内容:)-谢谢您的提示,在这种情况下,如何在启动应用程序时启动相机?通常我需要在onCreate或onStart@AlexPRY您可以在任何喜欢的线程中初始化相机,例如在主线程或CameraController线程中的onStart内部。问题是在主线程外显示Toast和更新TextView。例如,您可以在活动中执行。runOnUiThread()
谢谢,我会考虑你的建议——事实上,我注意到了其他一些奇怪的行为,当我从不同的线程扰乱UI时——我想了解的是我的问题发生的原因——但由于文档中指出可能会发生意外行为——我猜这就是他们所说的:)