Я пытался выяснить самую быструю скорость, с которой камера моего телефона могла делать снимки. Объект я использую для управления камерой (без логики камеры) выглядит следующим образом:Пользовательский интерфейс блокировки андроида Android, если только не используется Синхронизированный
public class PictureTaker {
private boolean mIsTakingPicture;
public void takePicture() {
mIsTakingPicture = true;
}
public boolean isTakingPicture() {
return mIsTakingPicture;
}
}
В моей деятельности, я создаю новую нить и оставить работоспособный к нему, чтобы начать цикл и фотографировать, когда краны пользователя кнопка. Я останавливаю нить, снова нажимая кнопку.
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();
}
}
}
}
С булевы атомарные, и я не возражаю хватает обновления, я не обернуть чек на mIsTestingCameraSpeed
в loopUntilStop()
в synchronized
блоке. (EDIT: как mttdbrd и Kevin Krumwiede указали, без синхронизации или изменения переменной volatile, нить не увидит изменений).
В любом случае, приведенный выше код блокирует поток пользовательского интерфейса. Однако изменение takePicture()
к
public void takePicture() {
mIsTakingPicture = false;
}
не блокирует пользовательский интерфейс, но тогда mIsTakingPicture
правильно не установлен. Для предотвращения блокировки и использовать первую версию takePicture()
, я должен был изменить isTakingPicture()
использовать блокировку:
public boolean isTakingPicture() {
synchronized (this) {
return mIsTakingPicture;
}
}
Почему бы не используя блок стопорного пользовательского интерфейса, когда mIsTakingPicture
установлен в true
но не false
? Я проверил Java documentation on intrinsic locks and synchronization и не нашел ничего, что могло бы объяснить это. Я также имел взглянуть на эти SO вопросы, и ни один из них не ответил на мой вопрос:
- Android :UI Thread Blocked
- Thread blocks my Android UI
- Thread blocking UI in android
- Android asynchronous post blocks UI thread
- Android UI Thread Block when calling AsynchTask.get()
- load textures into a thread blocks the mainUI in android
EDIT:Here - это журналы для ANR. Первые две строки показывают, что поток приостановлен, ожидая блокировки, и, смотря на строку 216, кажется, что тестовый поток действительно получает блокировку в какой-то момент. Начиная с строки 161 потока_list.cc, ОС пытается получить два разных мьютекса, но я не уверен, связаны ли они с проблемой.
Благодарим за хедз-ап большинства API, предназначенных для резьбы интерфейса; Я делал снимки вне основного потока, но я думаю, я не должен полагаться на это. Все это также относится к параллелизму, но я не понимаю, почему поток пользовательского интерфейса может блокировать или заходить в ту или иную ситуацию; где он ждет? –
@Shane_S Вы упомянули, что упростили свой код для этого сообщения. Может быть, рабочий поток зацикливается внутри синхронизированного блока и, следовательно, держится за замок? –
Код, как написано выше, все еще блокирует (без 'synchronized' в' isTakingPicture() ', то есть). –