[英]How to update UI elements from a background thread in Android?
I implemented a custom Android camera using the camera2 api and when I click capture button I save the captured image to my phone eternal storage. 我使用camera2 API实现了自定义Android摄像头,当我单击捕获按钮时,将捕获的图像保存到手机的永久存储中。
Now I needed to show a popup to enter the picture name before saving it and this popup has an imageView to show the captured image. 现在,我需要显示一个弹出窗口以输入图片名称,然后再保存它,并且该弹出窗口具有imageView来显示捕获的图像。
Even though I am loading the image from the Main thread I am getting this error 即使我从主线程加载图像,也遇到此错误
"Only the original thread that created a view hierarchy can touch its views"
Here is the code 这是代码
private void initPopup(final Bitmap bitmap) {
popAddName = new Dialog(this);
popAddName.setContentView(R.layout.popup_add_name);
popAddName.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
popAddName.getWindow().setLayout(Toolbar.LayoutParams.MATCH_PARENT, Toolbar.LayoutParams.WRAP_CONTENT);
popAddName.getWindow().getAttributes().gravity = Gravity.TOP;
popup_add = popAddName.findViewById(R.id.popup_add);
popup_img = popAddName.findViewById(R.id.popup_img);
popup_name = popAddName.findViewById(R.id.popup_name);
Thread thread = new Thread() {
@Override
public void run() {
runOnUiThread(new Runnable() {
@Override
public void run() {
Picasso.with(getApplicationContext()).load(getImageUri(getApplicationContext(), bitmap)).placeholder(R.drawable.placeholder).into(popup_img);
}
});
}
};
thread.start();
}
Here is the method to convert Bitmap to Uri for Picasso loading 这是将位图转换为Uri进行Picasso加载的方法
public Uri getImageUri(Context inContext, Bitmap inImage) {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
inImage.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
String path = MediaStore.Images.Media.insertImage(inContext.getContentResolver(), inImage, "Title", null);
return Uri.parse(path);
}
This is the capture method 这是捕获方法
ImageReader.OnImageAvailableListener readerListener = new ImageReader.OnImageAvailableListener() {
@Override
public void onImageAvailable(ImageReader imageReader) {
Image image = null;
try {
image = reader.acquireLatestImage();
ByteBuffer buffer = image.getPlanes()[0].getBuffer();
byte[] bytes = new byte[buffer.capacity()];
buffer.get(bytes);
//CONVERTION BYTES[] TO BITMAP
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
//create a new folder in external storage directory
String lorealFolder = "coffretPics";
File f = new File(Environment.getExternalStorageDirectory(), lorealFolder);
if (!f.exists()) {
f.mkdirs();
}
initPopup(bitmap);
popAddName.show();
file = new File(Environment.getExternalStorageDirectory() + "/" + lorealFolder + "/" + UUID.randomUUID().toString() + ".jpg");
save(bytes);
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
{
if (image != null)
image.close();
}
}
}
private void save(byte[] bytes) throws IOException {
/* OutputStream outputStream = null;
try {
outputStream = new FileOutputStream(file);
outputStream.write(bytes);
} finally {
if (outputStream != null) {
outputStream.close();
}
}*/
}
};
Can someone please tell me what's the problem ? 有人可以告诉我这是什么问题吗?
Updated answer: 更新的答案:
Create a class called AppExecutors 创建一个名为AppExecutors的类
public class AppExecutors {
// For Singleton instantiation
private static final Object LOCK = new Object();
private static AppExecutors sInstance;
private final Executor diskIO;
private final Executor mainThread;
private final Executor networkIO;
private AppExecutors(Executor diskIO, Executor networkIO, Executor mainThread) {
this.diskIO = diskIO;
this.networkIO = networkIO;
this.mainThread = mainThread;
}
public static AppExecutors getInstance() {
if (sInstance == null) {
synchronized (LOCK) {
sInstance = new AppExecutors(Executors.newSingleThreadExecutor(),
Executors.newFixedThreadPool(3),
new MainThreadExecutor());
}
}
return sInstance;
}
public Executor diskIO() {
return diskIO;
}
public Executor mainThread() {
return mainThread;
}
public Executor networkIO() {
return networkIO;
}
private static class MainThreadExecutor implements Executor {
private Handler mainThreadHandler = new Handler(Looper.getMainLooper());
@Override
public void execute(@NonNull Runnable command) {
mainThreadHandler.post(command);
}
}
And get the main thread like: 并获得如下主线程:
AppExecutors.getInstance().mainThread().execute(new Runnable() {
@Override
public void run() {
// Do the work on UI thread here.
}
});
That should fix your problem. 那应该解决您的问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.