Reputation: 2434
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.
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.
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
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 ?
Upvotes: 0
Views: 1217
Reputation: 636
Updated answer:
Create a class called 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.
Upvotes: 1