This question already has answers here:
Error "must not be null" in Kotlin
(3 answers)
Closed 4 years ago.
I am working on an Application for making a video from multiple images in kotlin. I got many code of java but can not convert it in propare way to kotlin code. Alwayse got an error cursor.getString(column_index) must not be null. I am just beginner at Kotlin. so can anyone give a brief solution for my problem.
val cursor = contentResolver.query(uri, filePathColumn, null, null, null)
cursor!!.moveToFirst()
val columnIndex = cursor.getColumnIndex(filePathColumn[0])
Hey I m also suffering with same issue nd got the solution. just follow my code.
private var context: Context? = null
var PICK_IMAGE_MULTIPLE = 1
lateinit var imagePath: String
var imagesPathList: MutableList<String> = arrayListOf()
call gallery intent first
if (Build.VERSION.SDK_INT < 19) {
var intent = Intent()
intent.type = "image/*"
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
intent.action = Intent.ACTION_GET_CONTENT
startActivityForResult(
Intent.createChooser(intent, "Select Picture")
, PICK_IMAGE_MULTIPLE
)
} else {
var intent = Intent(Intent.ACTION_OPEN_DOCUMENT)
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
intent.addCategory(Intent.CATEGORY_OPENABLE)
intent.type = "image/*"
startActivityForResult(intent, PICK_IMAGE_MULTIPLE);
}
now check onActivityResult
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
// When an Image is picked
if (requestCode == PICK_IMAGE_MULTIPLE && resultCode == Activity.RESULT_OK
&& null != data
) {
if (data.getClipData() != null) {
var count = data.clipData.itemCount
for (i in 0..count - 1) {
var imageUri: Uri = data.clipData.getItemAt(i).uri
getPathFromURI(imageUri)
}
} else if (data.getData() != null) {
var imagePath: String = data.data.path
Log.e("imagePath", imagePath);
}
displayImageData()
}
}
private fun getPathFromURI(uri: Uri) {
var path: String = uri.path // uri = any content Uri
val databaseUri: Uri
val selection: String?
val selectionArgs: Array<String>?
if (path.contains("/document/image:")) { // files selected from "Documents"
databaseUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI
selection = "_id=?"
selectionArgs = arrayOf(DocumentsContract.getDocumentId(uri).split(":")[1])
} else { // files selected from all other sources, especially on Samsung devices
databaseUri = uri
selection = null
selectionArgs = null
}
try {
val projection = arrayOf(
MediaStore.Images.Media.DATA,
MediaStore.Images.Media._ID,
MediaStore.Images.Media.ORIENTATION,
MediaStore.Images.Media.DATE_TAKEN
) // some example data you can query
val cursor = contentResolver.query(
databaseUri,
projection, selection, selectionArgs, null
)
if (cursor.moveToFirst()) {
val columnIndex = cursor.getColumnIndex(projection[0])
imagePath = cursor.getString(columnIndex)
// Log.e("path", imagePath);
imagesPathList.add(imagePath)
}
cursor.close()
} catch (e: Exception) {
Log.e(TAG, e.message, e)
}
}
This is a solution using Github repo for your requirement.
In your app gradle file add these lines
implementation 'com.github.esafirm.android-image-picker:imagepicker:1.13.1'
// for experimental rx picker
implementation 'com.github.esafirm.android-image-picker:rximagepicker:1.13.1'
// If you have a problem with Glide, please use the same Glide version or simply open an issue
implementation 'com.github.bumptech.glide:glide:4.8.0'
in Java class call this to pick or take image
startActivityForResult(ImagePicker.create(getActivity())
.multi()
.folderMode(true)
.returnMode(ReturnMode.ALL)
.getIntent(getActivity()), IpCons.RC_IMAGE_PICKER);
and in onActivityResult() get the arraylist of selected images
#Override
protected void onActivityResult(int requestCode, final int resultCode, Intent data) {
if (ImagePicker.shouldHandle(requestCode, resultCode, data)) {
// Get a list of picked images
List<Image> images = ImagePicker.getImages(data)
// do your stuff here
// or get a single image only
//Image image = ImagePicker.getFirstImageOrNull(data)
}
super.onActivityResult(requestCode, resultCode, data);
}
This code is less complex and no need to handle image multiple selection , just adding multi() to enable multiple selection.
Note:- Copy this code and paste in your kotlin project , the converter will
automatically convert it to kotlin
Related
I want to get content (images & videos) of user selected folder. Code to select the folder is:
val intent = Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION
or Intent.FLAG_GRANT_PREFIX_URI_PERMISSION
or Intent.FLAG_GRANT_READ_URI_PERMISSION
or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
)
startActivityForResult(intent, 1088)
And onActivityResult, I am persisting the permission(even I tested without restarting the device but it is not working):
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if(resultCode == Activity.RESULT_OK) {
if (requestCode == 1088) {
val selectedDirUri = data!!.data
grantUriPermission(packageName, selectedDirUri, (Intent.FLAG_GRANT_READ_URI_PERMISSION
or Intent.FLAG_GRANT_WRITE_URI_PERMISSION
or Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION))
val takeFlags = (data.flags
and (Intent.FLAG_GRANT_READ_URI_PERMISSION
or Intent.FLAG_GRANT_WRITE_URI_PERMISSION))
contentResolver.takePersistableUriPermission(selectedDirUri!!, takeFlags)
}
}
}
And I am traversing through all files using:
val rootUri: Uri = Uri.parse(selectedDir)
val contentResolver: ContentResolver = context.contentResolver
var childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(rootUri, DocumentsContract.getTreeDocumentId(rootUri))
val dirNodes: MutableList<Uri> = LinkedList()
dirNodes.add(childrenUri)
while (!dirNodes.isEmpty()) {
childrenUri = dirNodes.removeAt(0) // get the item from top
val c = contentResolver.query(childrenUri,
arrayOf(
DocumentsContract.Document.COLUMN_DOCUMENT_ID,
DocumentsContract.Document.COLUMN_DISPLAY_NAME,
DocumentsContract.Document.COLUMN_MIME_TYPE,
DocumentsContract.Document.COLUMN_LAST_MODIFIED),
null, null, null)
try {
while (c!!.moveToNext()) {
val docId = c.getString(0)
val fileName = c.getString(1)
val mimeType = c.getString(2)
val lastModified = c.getLong(3)
if (isDirectory(mimeType)) {
val newNode = DocumentsContract.buildChildDocumentsUriUsingTree(rootUri, docId)
dirNodes.add(newNode)
} else {
val newNode = DocumentsContract.buildDocumentUriUsingTree(rootUri, docId)
Logger.log("TAG", "========1 Images: $newNode")
val ***sourceFileUri*** = newNode.toString()
}
}
} finally {
closeQuietly(c)
}
}
Then I display images and videos using Glide, it is not displaying.
Even if I try to copy the image using below code:
val inputStream: InputStream? = context.contentResolver.openInputStream(***sourceFileUri***)
I am getting below error, the above line gives an error:
java.lang.SecurityException: com.android.externalstorage has no access
to content://media/external _primary/file/1000008384 at
android.os.Parcel.createException or Null(Parcel.java:2438) at 08
android.os.Parcel.createException(P arcel.java:2422) at
android.os.Parcel.readException(Par cel.java:2405) at
android.database.DatabaseUtils.rea dExceptionFromParcel(DatabaseUtil
s.java:190) at android.database.DatabaseUtils.rea dException
WithFileNotFoundExcepti on From Parcel(DatabaseUtils.java:15 3)
This is happening in Vivo, Oppo and specially in new Samsung phones only which has android OS 11 and 12. I am really frustrated, I tried all possible solution but not able to find any solution till now.
Any solution or advice would be really helpful and appreciated, please please help me.
I am trying to upload a video file to firebase.:-
this is the code:-
lateinit var file: Any
private fun selectingVideo() {
val videoPickIntent = Intent(Intent.ACTION_PICK)
videoPickIntent.type = "video/*"
startActivityForResult(Intent.createChooser(videoPickIntent, "Please pick a video"), videoRequest )
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == videoRequest && resultCode == Activity.RESULT_OK && null != data) {
feedImageSelect.visibility = View.GONE
feedVideoSelect.visibility = View.VISIBLE
val pickedVideoUrl = getRealPathFromUri(applicationContext, data.data!!)
file = pickedVideoUrl
feedVideoSelect.setVideoPath(pickedVideoUrl)
// Default Media-Controller
feedVideoSelect.setMediaController(MediaController(this))
// start playing
feedVideoSelect.start()
}
}
// Retrieve Video Path from URI.
private fun getRealPathFromUri(context: Context, contentUri: Uri): String {
var cursor: Cursor? = null
try {
val proj = arrayOf(MediaStore.Images.Media.DATA)
cursor = context.contentResolver.query(contentUri, proj, null, null, null)
val columnIndex = cursor!!.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)
cursor.moveToFirst()
return cursor.getString(columnIndex)
} finally {
cursor?.close()
}
}
I am getting this as the error.:-
java.lang.ClassCastException: java.lang.String cannot be cast to android.net.Uri
I have tried all the possible ways to solve it. But Still I am getting this error. I tried other methods as well still they are not working for my requirements.
Make these changes to the code:-
val pickedVideoUrl = data.data
feedVideoSelect.setVideoPath(pickedVideoUrl.toString())
I have an activity from which I launch the gallery, select an image, and want to display the selected image in another activity. I have referred to the following solution and implemented the same.
How to get Image URI from Gallery?
Though I am able to pass the URI to the next activity, I cannot see anything on the image view. Any help as to where I am going wrong, appreciated.
btn_launch_gallery.setOnClickListener {
val requestCode = 0
val launchGalleryIntent = Intent(Intent.ACTION_PICK,
MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
startActivityForResult(launchGalleryIntent, requestCode)
}
My OnActivityResult looks like this, basically implemented the same as given in the example cited above.
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode === 0 && resultCode === Activity.RESULT_OK ) {
val selectedImage: Uri? = data?.data
val picturePath = getRealPathFromURI(
selectedImage,
this
)
val intent = Intent(this, LogFoodDetail::class.java)
intent.putExtra("image_from_gallery", picturePath)
try {
startActivity(intent)
}
catch (e: Exception)
{
e.printStackTrace()
Log.e("Error",e.printStackTrace().toString())
}
}
}
fun getRealPathFromURI(contentURI: Uri?, context: Activity): String? {
val projection =
arrayOf(MediaStore.Images.Media.DATA)
val cursor = context.managedQuery(
contentURI, projection, null,
null, null
)
?: return null
val column_index = cursor
.getColumnIndexOrThrow(MediaStore.Images.Media.DATA)
return if (cursor.moveToFirst()) {
// cursor.close();
cursor.getString(column_index)
} else null
// cursor.close();
}
In my next activity, I getting the intent like this and passing the URI to ImageView. However, I cannot see the image. I get the following error - W/System.err: java.io.FileNotFoundException: No content provider: /storage/emulated/0/DCIM/Camera/***.jpg
val resId = intent.getStringExtra("image_from_gallery")
val imgThumbnail: ImageView = findViewById(R.id.food_thumbnail)
try{
val imageStream: InputStream? = contentResolver.openInputStream(Uri.parse(resId))
val bitmap = BitmapFactory.decodeStream(imageStream)
imgThumbnail.setImageBitmap(bitmap)
}
catch (e: Exception)
{
e.printStackTrace()
}
I see the following image in the next activity:
UPDATE:
As commented by #blackapps in his answer passing the URI as a string to the next activity on an intent.putExtra() and resolving the URI in the subsequent activity solved it, the updated code in OnActivityResult() is,
...
val selectedImage: Uri? = data?.data
val intent = Intent(this, LogFoodDetail::class.java)
intent.putExtra("image_from_gallery",
selectedImage.toString())
startActivity(intent)
Dont convert a nice uri to a file system path.
Uri uri = data.getData();
Pass the obtained uri directly to the next activity.
And there you can use it for
imageView.setImageUri(uri);
Instead of the uri you can also pass the uri as string with uri.toString().
You can directly load an local image Uri using:
imgThumbnail.setImageUri(yourUri);
Instead of sending the string path to the activity, you should send the raw uri and then set it directly to the imageView.
I am trying to write the code to upload file from Android Oreo and Above. First I am running a intent to get the uri of the file.
intent_upload.action = Intent.ACTION_GET_CONTENT
return Intent.createChooser(intent_upload, pickerTitle)
But when I select file from downloads folder, it returns a null filepath from following code. It works perfectly for devices below Android Oreo but I cannot find any solution for android o and above.
Please help
val id = DocumentsContract.getDocumentId(uri)
val contentUri = ContentUris.withAppendedId(Uri.parse("content://downloads/public_downloads"), java.lang.Long.valueOf(id));
return getDataColumn(context, contentUri, null, null)
Code for getDataColumn is as follow
fun getDataColumn(context: Context, uri: Uri?, selection: String?,
selectionArgs: Array<String>?): String? {
var cursor: Cursor? = null
val column = "_data"
val projection = arrayOf(column)
try {
cursor = context.contentResolver.query(uri!!, projection, selection, selectionArgs, null)
val temp = context
if (cursor != null && cursor.moveToFirst()) {
val index = cursor.getColumnIndexOrThrow(column)
return cursor.getString(index)
}
}catch (e:Exception){
} finally {
cursor?.close()
}
return null
}
It is happening for API 26 and above.
My motive is to upload a pdf file from the downloads folder in Android.
I know this is past due. I also faced this issue and I was able to find a solution from this gist. FileUtils.java. Just use this util class in your project
Just leaving this here for people who face this issue in the future. Wasted a couple of hours working on this.
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Uri uri = data.getData();
File originalFile = new File(FileUtils.getRealPath(this,uri));
}
Launch photo picker using Intent.ACTION_GET_CONTENT
Retrieve URI of selected item
Retrieve PATH of URI so that I can POST it to my webserver
Code to launch browse
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("image/*");
startActivityForResult(intent, BROWSE_IMAGE_REQUEST_CODE);
Code to retrieve selected image
if (RESULT_OK == resultCode &&
BROWSE_IMAGE_REQUEST_CODE == requestCode) {
Uri uri = data.getData();
Code to send to the webserver
File file = new File(uri.getPath());
new FileSystemResourceFile(file);
I am currently able to retrieve the PATH from the URI no prob /external/images/media/24 but for some weird reason file is always null, help please?
I've done this method to convert Uri from Intent.ACTION_GET_CONTENT to real path:
public static String getRealPathFromUri(Activity activity, Uri contentUri) {
String[] proj = { MediaStore.Images.Media.DATA };
Cursor cursor = activity.managedQuery(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
return cursor.getString(column_index);
}
Which in turn converted into File:
Uri filePathFromActivity = (Uri) extras.get(Intent.EXTRA_STREAM);
filePathFromActivity = Uri.parse(FileUtil.getRealPathFromUri( (Activity) IntentActivity.this, filePathFromActivity));
File imageFile = new File(filePathFromActivity.getPath());
I know its been a long time since the answer, but I faced the same wall and this is the solution I ended up with. The main benefit of this code is that avoids having parametrized (and hard-coded) all possible providers types and locations across all different android versions.
val act = getActivity() as Activity
object: AsyncTask<Uri, Void, File?>() {
override fun doInBackground(uris: Array<Uri>): File? {
if(act.isFinishing()) return null
try {
val dir = act.getCacheDir()
val file = File.createTempFile("PREFIX", "SUFFIX", dir)
val inputStream = act.getContentResolver().openInputStream(uris[0])
val fos = FileOutputStream(file)
BitmapFactory.decodeStream(inputStream)
.compress(Bitmap.CompressFormat.JPEG, 90, fos)
return file
} catch(e: Exception) { e.printStackTrace() }
return null
}
override fun onPostExecute(result: File?) {
result?.let { doSomethingWithFile(it) }
}
}.execute(uri)
I put it wrapped inside of an AsyncTask for the purpose of leaving unblocked ui thread during bitmap compress. Please be aware that using Bitmap.CompressFormat.JPEG means lossing alpha channel.
Hope it helps!
Pick any file using System File Picker:
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "*/*"
startActivityForResult(intent, 1)
onActivityResult:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == 1 && resultCode == Activity.RESULT_OK) {
val file = data?.data?.let {
getFileFromUri(requireContext().contentResolver, uri, requireContext().cacheDir)
}
}
}
Get File:
private fun getFileFromUri(contentResolver: ContentResolver, uri: Uri, directory: File): File {
val file =
File.createTempFile("suffix", "prefix", directory)
file.outputStream().use {
contentResolver.openInputStream(uri)?.copyTo(it)
}
return file
}