gpt4 book ai didi

java - Android 线程阻塞 UI 除非使用同步

转载 作者:行者123 更新时间:2023-11-29 20:42:37 27 4
gpt4 key购买 nike

我试图计算出手机摄像头拍照的最快速度。我用来管理相机(没有相机逻辑)的对象如下所示:

public class PictureTaker {
private boolean mIsTakingPicture;

public void takePicture() {
mIsTakingPicture = true;
}

public boolean isTakingPicture() {
return mIsTakingPicture;
}
}

在我的 Activity 中,我创建了一个新线程并向其发布了一个可运行的线程以在用户点击按钮时开始循环并拍照。我再次点击按钮停止线程。

import android.os.Handler;
import android.os.HandlerThread;
import android.support.v7.app.ActionBarActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.Button;

public class CameraTestActivity extends ActionBarActivity {

private HandlerThread mThread;
private Handler mThreadHandler;
private volatile boolean mTestingCameraSpeed;
private PictureTaker mPictureTaker;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_camera_test);

mThread = new HandlerThread("testThread");
mThread.start();
mThreadHandler = new Handler(mThread.getLooper());
mPictureTaker = new PictureTaker();
}

public void toggleDoingStuff(final View view) {
Button b = (Button)view;
if(mTestingCameraSpeed) {
mTestingCameraSpeed = false;
b.setText("Start camera");
} else {
mTestingCameraSpeed = true;

mThreadHandler.post(new Runnable() {
public void run() {
loopUntilStop();
}
});
b.setText("Stop camera");
}
}

private void loopUntilStop() {
for(;;) {
if(!mTestingCameraSpeed) break;

if(!mPictureTaker.isTakingPicture()) {
Log.d("CameraTestActivity", "Taking picture at time " + System.currentTimeMillis());
mPictureTaker.takePicture();
}
}
}
}

由于 boolean 值是原子的,我不介意错过更新,所以我没有将 loopUntilStop() 中的 mIsTestingCameraSpeed 检查包装在 同步中 block 。 (编辑: 正如 mttdbrd 和 Kevin Krumwiede 所指出的,如果没有同步或使变量可变,线程可能看不到更改)。

无论如何,上面的代码阻塞了 UI 线程。但是,将 takePicture() 更改为

public void takePicture() {
mIsTakingPicture = false;
}

不会阻塞 UI,但 mIsTakingPicture 设置不正确。为了防止阻塞并使用 takePicture() 的第一个版本,我不得不将 isTakingPicture() 更改为使用锁:

public boolean isTakingPicture() {
synchronized (this) {
return mIsTakingPicture;
}
}

mIsTakingPicture 设置为 true 而不是 false 时,为什么不使用锁来阻止 UI?我检查了 Java documentation on intrinsic locks and synchronization并没有找到任何可以解释它的东西。我也看过这些 SO 问题,但没有一个回答了我的问题:

编辑: Here是 ANR 的日志。前两行表示线程挂起等待锁,看第216行,似乎测试线程确实在某个时刻获取了锁。从 thread_list.cc 的第 161 行开始,操作系统尝试获取两个不同的互斥锁,但我不确定它们是否与问题有关。

最佳答案

首先,确保您甚至可以在 UI 线程之外使用相机 API。除非明确记录你可以,否则你应该假设你不能。 Android 的 API 大多设计为在 UI 线程中调用。

其次,Java 中的线程安全性不仅仅是原子性;您还必须担心能见度。工作线程可能看不到对 mTestingCameraSpeed 的写入除非你做到了volatile或同步读取写入。同样,同步读取 mIsTakingPicture除非您还同步写入,否则毫无意义。 (或者再次将其设置为 volatile 。)

第三,您描述的问题没有任何意义,所以它实际上可能是由上述问题之一引起的。

假设您使用的是 Camera#takePicture(...) ,我建议使用其中一个回调开始拍摄下一张照片。这应该会给你最大的实际利率。

编辑:应该对于 mThread.getLooper() 是不可能的返回 null打电话后 mThread.start() ,我不确定如果这样做会发生什么。所以这只是黑暗中的一枪。但是尝试改变这个:

    mThread.start();
mThreadHandler = new Handler(mThread.getLooper());

...为此:

    mThread.start();
Looper looper = mThread.getLooper();
Log.d("DERP", "looper is " + looper);
mThreadHandler = new Handler(looper);

关于java - Android 线程阻塞 UI 除非使用同步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30794696/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com