So currently, I'm capturing an image and updating it in a RecyclerView using the Camera Intent:
private void cameraIntent() {
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
if (takePictureIntent.resolveActivity(getActivity().getPackageManager()) != null) {
File photoFile = null;
try {
photoFile = createImageFile();
} catch (IOException ex) {
Log.e(TAG, ex.getLocalizedMessage());
}
if (photoFile != null) {
Uri uri = FileProvider.getUriForFile(getActivity().getApplicationContext(),
"packagename.fileprovider",
photoFile);
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, uri);
startActivityForResult(takePictureIntent, REQUEST_TAKE_PHOTO);
}
}
}
What happens prior to this is it'll trigger the intent from an setOnItemClickListener interface I have created within my RecyclerView.Adapter which is called in onCreate to populate the data from the web-server (or when triggered by setVisibleUserHint as they re-enter the fragment again).
//init camera data
if (isCamera) {
cameraArray = object.getJSONArray(PROFILE_DETAILS_CAMERA_ARRAY_KEY);
sortAdapter(true, object, cameraArray);
} else {
galleryArray = object.getJSONArray(PROFILE_DETAILS_GALLERY_ARRAY_KEY);
sortAdapter(false, object, galleryArray);
}
//settings adapters
cameraAdapter = new RecyclerViewAdapterGallery(getActivity(), array, true);
cameraAdapter.setOnItemClickListener(new RecyclerViewAdapterGallery.onItemClickListener() {
#Override
public void setOnItemClickListener(View view, final int position, String image, final boolean isCamera, boolean isLongClick) {
clickResponse(view, position, image, isCamera, isLongClick, cameraAdapter, array, object);
}
});
recyclerView.setAdapter(cameraAdapter);
cameraAdapter.notifyDataSetChanged();
What happens post is within the onActivityResult:
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case REQUEST_TAKE_PHOTO:
if (resultCode != Activity.RESULT_CANCELED) {
if (resultCode == Activity.RESULT_OK) {
try {
handleBigCameraPhoto(finalPosition);
} catch (IOException e) {
Log.e(TAG, e.getLocalizedMessage());
}
}
}
break;
...
}
}
handleBigCameraPhoto:
private void handleBigCameraPhoto(int position) {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
File f = new File(mCurrentPhotoPath);
Uri contentUri = Uri.fromFile(f);
mediaScanIntent.setData(contentUri);
getActivity().sendBroadcast(mediaScanIntent);
saveFile(f, false, position);
}
This works perfectly, it saves the file fine to the web-server but I want to update the adapter when that is successful, and of course I'm unable to restore the adapter object using outState or inState bundle.
cameraArray.put(position, parseFile.getUrl());
userObject.put(PROFILE_DETAILS_CAMERA_ARRAY_KEY, cameraArray);
userObject.saveInBackground(new SaveCallback() {
#Override
public void done(ParseException e) {
if (e == null) {
if (cameraAdapter != null) {
cameraAdapter.updatePosition(cameraArray, position);
}
} else {
Log.e(TAG, "failed " + e.getLocalizedMessage());
}
}
});
By this point I'm not sure why the cameraAdapter isn't updating as it's not returning null and is calling updatePosition().
public void updatePosition(JSONArray array, int position) {
Log.e(TAG, "updatePositionCalled");
this.imageList = array;
notifyItemChanged(position);
}
If anyone can help me solve this mystery, that would be great! Also, if you need any more code or verification at all, let me know.
Note: I currently have the JSONArray of objects, position in the adapter and web-server object stored in the saveInstanceState bundle and is restored correctly (because when I come out of the ViewPager fragment and come back in, thus calling setUserVisibleHint it restores the adapter from the web-server correctly).
Update: I've created a getImageList() method inside the adapter and calling that after the supposed 'update', it's updating the list values but not the list?! So i really do think the problem is with notifyItemChanged(position)
public JSONArray getImageList() {
return imageList;
}
// new call
if (e == null) {
cameraAdapter.updatePosition(cameraArray, position);
Log.e(TAG, cameraAdapter.getImageList().toString());
} else {
Log.e(TAG, "failed " + e.getLocalizedMessage());
}
It literally prints out the corresponding values in the list, that has been passed to the adapter, but doesn't seem to update the UI.
Update II:
I've had two (now deleted) answers advising me to notifyDataSetChanged(), Which makes no difference at all and is counter-productive as it'll rebind the whole adapter within the fragment, thus making it slow. I'm already rebinding the dedicated position (supposedly) with notifyItemChanged().
Note II: I'm offering a bounty, not for lazy and unresearched answers but for a solution with the very least an explanation, I'd like to know why it's going wrong, so I don't run into the same problem again (not a quick fix). I'm already well aware of the different functionalities and components of a RecyclerView, RecyclerView.Adapter and RecyclerView.ViewHolder, I'm just having trouble in this particular scenario where the Activity is returning a result, but not updating the UI as it should.
Hey i think the issue is with the line this.imageList = array of below method,
public void updatePosition(JSONArray array, int position) {
Log.e(TAG, "updatePositionCalled");
this.imageList = array;
notifyItemChanged(position);
}
Reason :
The this.imageList = array line is creating a new reference. It is not updating the old reference which was passed in the Recyclerview. Hence, notifyItemChanged(position); is refreshing the view but with the old reference of the array which has not been updated.
Solution:
You need to update the method as following:
public void updatePosition(String url, int position) {
Log.e(TAG, "updatePositionCalled");
this.imageList.put(position, url);
notifyItemChanged(position);
}
And
userObject.put(PROFILE_DETAILS_CAMERA_ARRAY_KEY, cameraArray);
userObject.saveInBackground(new SaveCallback() {
#Override
public void done(ParseException e) {
if (e == null) {
if (cameraAdapter != null) {
cameraAdapter.updatePosition(parseFile.getUrl(), position);
}
} else {
Log.e(TAG, "failed " + e.getLocalizedMessage());
}
}
});
Update:
Also, replace notifyItemChanged(position) with notifyItemInserted(position)as new item is being inserted here in the Array.
Related
My requirement is that I have to built a video recording app in which user will save his 30 seconds of video which will be sent to the another server. User will use the video recording only for once.
How can I store that 30 second recorded video in SQLite database as I cannot store it in gallery as it is confidential.
Any help in this topic is highly appreciated.
Below is my demo app in which I'm just saving it into the gallery for now.
public class VideoKycActivity extends AppCompatActivity implements ImageAnalysis.Analyzer, View.OnClickListener {
private ListenableFuture<ProcessCameraProvider> cameraProviderFuture;
PreviewView previewView;
private VideoCapture videoCapture;
private Button bRecord;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
previewView = findViewById(R.id.previewView);
bRecord = findViewById(R.id.bRecord);
bRecord.setText("start recording"); // Set the initial text of the button
bRecord.setOnClickListener(this);
cameraProviderFuture = ProcessCameraProvider.getInstance(this);
cameraProviderFuture.addListener(() -> {
try {
ProcessCameraProvider cameraProvider = cameraProviderFuture.get();
startCameraX(cameraProvider);
} catch (ExecutionException | InterruptedException e) {
e.printStackTrace();
}
}, getExecutor());
}
Executor getExecutor() {
return ContextCompat.getMainExecutor(this);
}
#SuppressLint("RestrictedApi")
private void startCameraX(ProcessCameraProvider cameraProvider) {
cameraProvider.unbindAll();
CameraSelector cameraSelector = new CameraSelector.Builder()
.requireLensFacing(CameraSelector.LENS_FACING_BACK)
.build();
Preview preview = new Preview.Builder()
.build();
preview.setSurfaceProvider(previewView.getSurfaceProvider());
// Video capture use case
videoCapture = new VideoCapture.Builder()
.setVideoFrameRate(30)
.build();
// Image analysis use case
ImageAnalysis imageAnalysis = new ImageAnalysis.Builder()
.setBackpressureStrategy(ImageAnalysis.STRATEGY_KEEP_ONLY_LATEST)
.build();
imageAnalysis.setAnalyzer(getExecutor(), this);
//bind to lifecycle:
cameraProvider.bindToLifecycle((LifecycleOwner) this, cameraSelector, preview, videoCapture);
}
#Override
public void analyze(#NonNull ImageProxy image) {
// image processing here for the current frame
Log.d("TAG", "analyze: got the frame at: " + image.getImageInfo().getTimestamp());
image.close();
}
#SuppressLint("RestrictedApi")
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.bRecord:
if (bRecord.getText() == "start recording"){
bRecord.setText("stop recording");
recordVideo();
} else {
bRecord.setText("start recording");
videoCapture.stopRecording();
}
break;
}
}
#SuppressLint("RestrictedApi")
private void recordVideo() {
if (videoCapture != null) {
long timestamp = System.currentTimeMillis();
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, timestamp);
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, "video/mp4");
try {
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
videoCapture.startRecording(
new VideoCapture.OutputFileOptions.Builder(
getContentResolver(),
MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
contentValues
).build(),
getExecutor(),
new VideoCapture.OnVideoSavedCallback() {
#Override
public void onVideoSaved(#NonNull VideoCapture.OutputFileResults outputFileResults) {
Toast.makeText(VideoKycActivity.this, "Video has been saved successfully.", Toast.LENGTH_SHORT).show();
}
#Override
public void onError(int videoCaptureError, #NonNull String message, #Nullable Throwable cause) {
Toast.makeText(VideoKycActivity.this, "Error saving video: " + message, Toast.LENGTH_SHORT).show();
}
}
);
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
First of all SQL(Room in our case) database is not the best approach to storing a single element. I suggest you use PharedPreferences. And about your main question. Room so as SharedPreferences working with primary types (to be honest Room store data in SQL types like TEXT, INTEGER, BLOB, REAL and UNDEFINED and that convert in java types) so for your goal, you have to convert your file to something that feet for our storage. I guess you can use a String.
You could convert the file to a Base64 format and save it as a String however depending on your file size you could face problems with memory because the Base64 format consumes more memory than the initial file. Here is an explanation of Base64 format memory consumption.
https://stackoverflow.com/a/27798343/5422725
I want to update my app immediately every time I publish an update. I followed the instructions from the official android documentation on how to test the auto update feature , but nothing happens. I placed some logs in order to check whether these functions initialize, but the logcat shows nothing either. Is this a problem in my syntax, or should I place these functions somewhere else? Currently, all my update code is written inside the main, starting class of the app.
On create method of the class
private static final int REQUEST_APP_UPDATE = 560;
private AppUpdateManager appUpdateManager;
private InstallStateUpdatedListener installStateUpdatedListener;
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
appUpdateManager = AppUpdateManagerFactory.create(this);
installStateUpdatedListener = new
InstallStateUpdatedListener() {
#Override
public void onStateUpdate(InstallState state) {
if (state.installStatus() == InstallStatus.DOWNLOADED){
} else if (state.installStatus() == InstallStatus.INSTALLED){
if (appUpdateManager != null){
appUpdateManager.unregisterListener(installStateUpdatedListener);
}
} else {
Log.i(TAG, "InstallStateUpdatedListener: state: " + state.installStatus());
}
}
};
appUpdateManager
.getAppUpdateInfo()
.addOnSuccessListener(
appUpdateInfo -> {
Log.d("TAG", "here");
// Checks that the platform will allow the specified type of update.
if ((appUpdateInfo.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE)
&& appUpdateInfo.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE))
{
// Request the update.
try {
Log.d("TAG", "here");
appUpdateManager.startUpdateFlowForResult(
appUpdateInfo,
AppUpdateType.IMMEDIATE,
this,
REQUEST_APP_UPDATE);
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
}
});
appUpdateManager.registerListener(installStateUpdatedListener);
...
On resume and on stop handling methods:
#Override
protected void onResume() {
super.onResume();
appUpdateManager
.getAppUpdateInfo()
.addOnSuccessListener(
appUpdateInfo -> {
if (appUpdateInfo.updateAvailability()
== UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS) {
// If an in-app update is already running, resume the update.
try {
appUpdateManager.startUpdateFlowForResult(
appUpdateInfo,
AppUpdateType.IMMEDIATE,
this,
REQUEST_APP_UPDATE);
Log.d("TAG", "tu");
} catch (IntentSender.SendIntentException e) {
e.printStackTrace();
}
}
});
}
#Override
protected void onStop() {
super.onStop();
if (appUpdateManager != null) {
appUpdateManager.unregisterListener(installStateUpdatedListener);
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == REQUEST_APP_UPDATE) {
if (resultCode != RESULT_OK) {
Log.d("TAG", "Update flow failed! Result code: " + resultCode);
// If the update is cancelled or fails,
// you can request to start the update again.
}
}
}
I suggest you to move all your AppUpdateInfo retrieving to onResume() since it is more reliable entry point of an activity (for example, if Activity has came to background and then was opened again by user). OnCreate method will be called only if activity was destroyed, since that, you may not see update dialog after reopening application if it was minimized.
#Override
public void onResume() {
super.onResume();
appUpdateManager.getAppUpdateInfo().addOnSuccessListener( info -> {
boolean isStalledUpdate = info.updateAvailability() == UpdateAvailability.DEVELOPER_TRIGGERED_UPDATE_IN_PROGRESS;
boolean isReadyForUpdate =
info.updateAvailability() == UpdateAvailability.UPDATE_AVAILABLE
&& info.isUpdateTypeAllowed(AppUpdateType.IMMEDIATE;
if (isReadyForUpdate || isStalledUpdate) {
appUpdateManager.startUpdateFlowForResult(
info,
AppUpdateType.IMMEDIATE,
this,
REQ_CODE
);
}
}
Sometimes app is not automatically synchronized with Play Store updates, so you need to do the following:
Make sure you have an update available manually - go to Play Store, check for updates and make sure that you have an update available for your application.
After that open your app (your activity, that calls update manager in onResume) and you will see immediate update dialog.
Also, one tip for you - make your Activity implement InstallStateUpdateListener and override method onStateUpdate like this to handle different events.
#Override
public void onResume() {
// All previous logic
// If update is available or was stalled call this
appUpdateManager.registerListener(this);
}
#Override
public void onStateUpdate(InstallState state) {
if (state == null) return;
switch (state.installStatus()) {
case InstallStatus.INSTALLED:
appUpdateManager.unregisterListener(this)
return;
case InstallStatus.FAILED:
appUpdateManager.unregisterListener(this)
return;
case InstallStatus.CANCELED:
appUpdateManager.unregisterListener(this)
return;
default:
// provide your own logic
return;
}
}
This will help you to avoid calling separate instance of listener in activity lifecycle methods.
The code that I provided was working, the problem of not updating was a matter of the device itself not knowing whether an update is available. After refreshing the update list on the Play Store, the app update manager initialized the auto update window when starting the app.
I'm trying to pass a Bitmap from an Activity to an other, I tried multiple solutions but they are not fast enough.
Currently I'm facing this problem: When I click the next button it freezes for 2 seconds then move to the next Activity with the right Bitmap shown in the ImageView.
I found this solution in StackoverFlow. Here is the code:
Uri imageUri = intent.getParcelableExtra("URI");
if (imageUri != null) {
imageView.setImageURI(imageUri);
try {
bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), imageUri);
} catch (IOException e) {
e.printStackTrace();
}
} else {
Toast.makeText(this, "No image is set to show", Toast.LENGTH_LONG).show();
}
btn_next_process.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (bitmap == null) {
Toast.makeText(CropResultActivity.this, "Emptyyy", Toast.LENGTH_SHORT).show();
}
else {
try {
//Write file
String filename = "bitmap.png";
FileOutputStream stream = CropResultActivity.this.openFileOutput(filename, Context.MODE_PRIVATE);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
//Cleanup
stream.close();
// bitmap.recycle();
//Pop intent
Intent in1 = new Intent(CropResultActivity.this, InputProcessingActivity.class);
in1.putExtra("image_data", filename);
startActivity(in1);
} catch (Exception e) {
e.printStackTrace();
}
}
}
});
Then I tried to save the file in a worker Thread first, and when I click the next button I retrieve it, now it's working fast but I am getting a wrong Bitmap.
Here is the code :
Uri imageUri = intent.getParcelableExtra("URI");
if (imageUri != null) {
imageView.setImageURI(imageUri);
try {
bitmap = MediaStore.Images.Media.getBitmap(this.getContentResolver(), imageUri);
new Thread() {
#Override
public void run() {
try {
//Write file
FileOutputStream stream = CropResultActivity.this.openFileOutput(filename, Context.MODE_PRIVATE);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, stream);
//Cleanup
stream.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}.run();
} catch (IOException e) {
e.printStackTrace();
}
} else {
Toast.makeText(this, "No image is set to show", Toast.LENGTH_LONG).show();
}
btn_next_process.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (bitmap == null) {
Toast.makeText(CropResultActivity.this, "Empty", Toast.LENGTH_SHORT).show();
}
else {
//Pop intent
Intent in1 = new Intent(CropResultActivity.this, InputProcessingActivity.class);
in1.putExtra("image_data", filename);
startActivity(in1);
}
}
});
In the second Activity I retrieve the Bitmap this way :
private void getIncomingIntent(){
if(getIntent().hasExtra("image_data")){
try {
String filename = getIntent().getStringExtra("image_data");
FileInputStream is = this.openFileInput(filename);
imageToProcess = BitmapFactory.decodeStream(is);
process_detect_edges(imageToProcess);
is.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
What am I doing wrong?
Just pass the image uri to next activity. Load from the uri in other activity.
Create a trivial Service. Give that Service a public Bitmap mBitmap member.
Keep each Activity bound to the Service while they are between onStart() and onStop().
If your Activities have a reference to the Service, they can communicate directly via the mBitmap member. One Activity can set mBitmap, then start the other Activity. The second Activity can simply grab the reference (after binding, of course), and begin manipulating the Bitmap. Since everything happens on the UI thread, there are no synchronization concerns. And everything is quite fast.
This solution does not address problems of persistence: If the user leaves the app for a period of time (puts it the background, locks the screen, etc.), then the entire app may be destroyed, and mBitmap would be lost. However, if you're just trying to share data between two successive Activities, this is a straightforward way of doing it.
You could even share the Bitmap via a public static reference, placed in any convenient class. There are rumors that the garbage collector goes around setting static references to null at a whim, but this is a misinterpretation of the actual behavior: That an entire app may get cleaned up at an unexpected time. When you return to your Activity, the system may actually have to restart the app and recreate the Activity from scratch. In this case, the reference would be reset to null.
Instead, using a Service indicates to the OS that you have a component of your app that should be a little bit longer-lived. Certainly, it will continue to exist across the gap between two successive Activities.
Note that, on Oreo and later, the system can be quite aggressive about cleaning up apps as soon as they leave the foreground.
I am working on an android app whose main purpose is to update the working location of the employees by admin. Now when I want to change/update the location of an employee from my recycler view(list of employees connected with my UserManagerAdapter), I have to pass the user name of that employee to the place picker intent so that when the admin pick the desired location, the database of that user will be changed accordingly.
My Steps(2 Steps)
I have passed the username to the place picker intent as bundle.
My UserManagerAdapter
holder.locationTv.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
launchPicker(data.get(position).getUserName());
}
});
private void launchPicker(String userName) {
PlacePicker.IntentBuilder builder = new PlacePicker.IntentBuilder();
Bundle bundle = new Bundle();
bundle.putString(USERNAME,userName);
try {
fragment.startActivityForResult(builder.build(fragment.getActivity()),PLACE_PICKER_REQUEST,bundle);
} catch (GooglePlayServicesRepairableException e) {
e.printStackTrace();
} catch (GooglePlayServicesNotAvailableException e) {
e.printStackTrace();
}
}
I received the location request inside of a fragment and update the location of that particular user
My ManageUserFragment
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode == PLACE_PICKER_REQUEST){
if(resultCode == RESULT_OK){
Place place = PlacePicker.getPlace(getContext(),data);
address = place.getAddress().toString();
String latLng = place.getLatLng().toString();
latLang = latLng;
//update user's decided location
Bundle bundle = data.getExtras();
String userName = bundle.getString(USERNAME);// it returns null, Why?
updateLocation(latLang,userName);
Toast.makeText(getContext(), latLng, Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(getContext(), getContext().getText(R.string.locationError), Toast.LENGTH_SHORT).show();
}
}
}
My constant is
public static final String USERNAME="Username";
Now,
My problem is
Why bundle.getString(USERNAME) always return null?
How to pass data to place picker intent so that we can receive it in
onActivityResult ?
After replicating your case and researching for a little bit, I found out that the third parameter in startActivityForResult() is not used to pass a bundle of values to the onActivityResult, it's used to pass options to Android itself, you can find those here. So if you want to pass any data you have to use an intent with putExtra("USERNAME", username), and you can retrieve it with getStringExtra("USERNAME"). It's explained in this answer as well.
I am attempting to render a photo I have taken with the following class, which returns the used file:
public File takePhoto(){
Intent pictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
File destination= null;
try {
destination = createFile();
} catch (IOException error) {
Log.v(TAG, "IO error, reading exception");
String errorMessage = error.getMessage();
Log.v(TAG, errorMessage);
String errorCauseMessage = error.getCause().getMessage();
Log.v(TAG, errorCauseMessage);
}
if (destination != null){
Log.v(TAG, "destination was written");
pictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(destination));
parentActivity.startActivityForResult(pictureIntent, REQUEST_TAKE_PHOTO);
Log.v(TAG, "destination was: " + destination.getAbsolutePath());
}
else {
Log.v(TAG, "destination was not written");
}``
return destination;
The result is then used in the following code:
Log.v(TAG, "adding picture");
PhotoHandler photoHandler = new PhotoHandler(getPackageManager(), PolishCreateActivity.this);
File imgFile = photoHandler.takePhoto();
if (imgFile == null) {
Toast.makeText(this, ERROR_TOAST_TEXT, Toast.LENGTH_SHORT).show();
} else {
Log.v(TAG, "Picture added");
Log.v(TAG, "storing directory");
img = imgFile.getAbsolutePath();
Log.v(TAG, "Directory stored");
Log.v(TAG, "Displaying picture");
LinearLayout layout = (LinearLayout) findViewById(R.id.rootLayout);
if (imageViewExists == Boolean.TRUE) {
ImageView oldView = (ImageView) findViewById(R.id.imageViewID);
layout.removeView(oldView);
}
UIHelper uiHelper = new UIHelper(this.getApplicationContext());
ImageView imageView = uiHelper.getImageViewFromPath(imgFile);
imageView.setId(R.id.imageViewID);
layout.addView(imageView);
imageViewExists = Boolean.TRUE;
Log.v(TAG, "picture displayed");
And passed to this method, as imgFile:
public ImageView getImageViewFromPath(File imgFile) {
ImageView imageView = new ImageView(context);
Bitmap imgBM = null;
if (imgFile.exists()) {
Log.v(TAG, "image file exists");
imgBM = BitmapFactory.decodeFile(imgFile.getAbsolutePath());
if (imgBM == null){
Log.v(TAG, "Bitmap returned was null");
}
}
imageView.setImageBitmap(imgBM);
imageView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
Log.v(TAG, "ImageView was created");
return imageView;
}
The problem is that BitmapFactory.decodeFile(imgFile.getAbsolutePath) returns every time I run it, even though the file exists (I can tell because I'm getting the log messages in the "if (imgFile.exists())" body). I have searched for a solution for a long time, but I have not found a solution. I have tested that it is not causing an outOfMemory exception, which it is not. Any help would be appreciated.
Check for the sdk version you are using for sdk version 23 or above you have to take permission for reading and writing on device..check for the below code may be it will resolve your issue
#Override
public void onClick(View v) {
if((ContextCompat.checkSelfPermission(MainActivity.this,
Manifest.permission.READ_EXTERNAL_STORAGE)!=PackageManager.PERMISSION_GRANTED)
|| (ContextCompat.checkSelfPermission(MainActivity.this,
Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED))
{
ActivityCompat.requestPermissions
(MainActivity.this, new String[]{
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE
},MY_PERMISSIONS_REQUEST_READ_AND_WRITE_EXTERNAL_STORAGE);
}
}
takePhoto starts an activity for a result:
parentActivity.startActivityForResult(pictureIntent, REQUEST_TAKE_PHOTO);
But your code carries on like this was done instantly, which it is not.
The file will of course be there, but it will always be 0 bytes large.
You will need to override onActivityResult() and handle the file contents from there.
Check the value of imgFile.getAbsolutePath().
Probably this value is null or illegal.
Use debug mode or log this value to log cat.
Okay, I solved it by switching to getting the bitmap from the intent via onActivityResult.
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_IMAGE_CAPTURE && resultCode == RESULT_OK){
Bundle extras = data.getExtras();
photo = (Bitmap) extras.get("data");
LinearLayout layout = (LinearLayout) findViewById(R.id.rootLayout);
layout.addView(UIHelper.getImageViewFromPath(photo, getApplicationContext()));
}
}
I still need to save the bitmap, though.