App crashes when I pass an object that extends parcelable interface - android

I am trying to build a simple app that passes objects between activities so I could use the Class properties in the recyclerview later on. I have created the "Member data class" and extended it so that it uses the parelable interface.
data class Member(val name : String, val image : ByteArray) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString(),
parcel.createByteArray()
) {
}
override fun writeToParcel(parcel: Parcel, flags: Int) {
parcel.writeString(name)
parcel.writeByteArray(image)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<Member> {
override fun createFromParcel(parcel: Parcel): Member {
return Member(parcel)
}
override fun newArray(size: Int): Array<Member?> {
return arrayOfNulls(size)
}
}
}
After that i have created a memberCreation activity to input some data in the class and pass the class back to the main activity using intent.
class MemberCreation : AppCompatActivity() {
private lateinit var profilePic : ImageView
private lateinit var nameEditText: EditText
private lateinit var saveButton: Button
private lateinit var profilePictureByteArray: ByteArray
private lateinit var member: Member
companion object{
const val REQUES_CODE_GALLERY = 999
const val EXTRA_REPLY = "robybp.coolkids.reply.extra"
}
#RequiresApi(Build.VERSION_CODES.JELLY_BEAN)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_member_creation)
profilePic = findViewById(R.id.profile_picture)
nameEditText = findViewById(R.id.name_edit_text)
saveButton = findViewById(R.id.button_save)
profilePic.setOnClickListener {
ActivityCompat.requestPermissions(this,
arrayOf(android.Manifest.permission.READ_EXTERNAL_STORAGE),
REQUES_CODE_GALLERY)
}
saveButton.setOnClickListener {
if (nameEditText.text.isNotEmpty()){
val activityIntet = Intent()
val name : String = nameEditText.text.toString()
member = Member(name, profilePictureByteArray)
activityIntet.putExtra(EXTRA_REPLY, member)
setResult(Activity.RESULT_OK, activityIntet)
finish()
}
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
if (requestCode == REQUES_CODE_GALLERY){
if (grantResults.size > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
val intent = Intent(Intent.ACTION_PICK)
intent.type = "image/*"
startActivityForResult(intent, REQUES_CODE_GALLERY)
}else{
Toast.makeText(this, "You don't have the permission to access gallery", Toast.LENGTH_LONG).show()
}
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == REQUES_CODE_GALLERY && resultCode == Activity.RESULT_OK && data!= null) run {
val uri: Uri = data.data
try {
val inputStream: InputStream = contentResolver.openInputStream(uri)
val bitmap : Bitmap = BitmapFactory.decodeStream(inputStream)
profilePic.setImageBitmap(bitmap)
profilePictureByteArray = imageToArray(profilePic)
}catch (e : FileNotFoundException){
e.printStackTrace()
}
}
super.onActivityResult(requestCode, resultCode, data)
}
private fun imageToArray(image : ImageView) : ByteArray{
val bitmap = (image.drawable as BitmapDrawable).bitmap
val stream = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.PNG, 90, stream)
val image = stream.toByteArray()
return image
}
}
But when i go back to retrieve the data in my main activity the app simply crashes without any logcat warnings. Also I am aware that I need to choose the profile picture from the gallery or the app will crash. I plan on adding a default value to the profilePictureByteArray later.
Here is a snippet of the code from my Main activity where i retrieve the object.
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == MEMBER_CREATION_REQUEST_CODE && resultCode == Activity.RESULT_OK){
val member : Member = data!!.getParcelableExtra(MemberCreation.EXTRA_REPLY)
}
}
I would like to point out that I sort of a beginner so I apologize if the question is really simple.

Related

The size of byte buffer and the shape do not match TFLite Android Kotlin

I'm new to ML, but thanks to the documentation and the community, I'm developing in this direction. Now I have stumbled upon an error and for several days I could not solve it, what is the problem and how to solve it?
I looked at the tutorials, I didn't seem to forget anything. On the XMl layout there is a picture, a text where the data comes from, their ids match
I want to open an object, take a picture of it and say what it is based on my trained model
Problem: the application crashes on line 194:
inputFeature0.loadBuffer(byteBuffer)
class SortingFragment : Fragment(), View.OnClickListener {
//ML
lateinit var bitmap: Bitmap
lateinit var appCtx: Application
lateinit var btnMLrn : Button
#SuppressLint("WrongConstant")
public fun checkandGetpermissions() {
if (PermissionChecker.checkSelfPermission(
requireActivity(),
Manifest.permission.CAMERA
) == PackageManager.PERMISSION_DENIED
) {
requestPermissions(arrayOf(Manifest.permission.CAMERA), 100)
} else {
requireActivity().showToast("Camera permission granted")
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == 100) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
requireActivity().showToast("Camera permission granted")
} else {
requireActivity().showToast("Permission Denied")
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.v(LOG_SORTING_FRAGMENT, "onCreate called")
// handling permissions
checkandGetpermissions()
appCtx = requireActivity().application
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
Log.v(LOG_SORTING_FRAGMENT, "onCreateView called")
// Inflate the layout for this fragment
val rootView = inflater.inflate(R.layout.fragment_sorting, container, false)
btnMLrn = rootView.findViewById(R.id.btnMLrn)
fltNtf = rootView.findViewById(R.id.fltNtf)
fltNtf.setOnClickListener(this)
btnMLrn.setOnClickListener(View.OnClickListener {
var camera : Intent = Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE)
startActivityForResult(camera, 200)
})
return rootView
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if(requestCode == 250){
img_view.setImageURI(data?.data)
var uri : Uri?= data?.data
bitmap = MediaStore.Images.Media.getBitmap(requireActivity().contentResolver, uri)
}
else if(requestCode == 200 && resultCode == Activity.RESULT_OK){
bitmap = data?.extras?.get("data") as Bitmap
img_view.setImageBitmap(bitmap)
var resized = Bitmap.createScaledBitmap(bitmap, 224, 224, true)
val model = ModelUnquant.newInstance(requireActivity())
var tbuffer = TensorImage.fromBitmap(resized)
var byteBuffer = tbuffer.buffer
// Creates inputs for reference.
val inputFeature0 = TensorBuffer.createFixedSize(intArrayOf(1, 224, 224, 3), DataType.FLOAT32)
inputFeature0.loadBuffer(byteBuffer)
// Runs model inference and gets result.
val outputs = model?.process(inputFeature0)
val outputFeature0 = outputs?.outputFeature0AsTensorBuffer
var max = outputFeature0?.let { it1 -> getMax(it1.floatArray) }
val labels = appCtx.assets.open("labels.txt").bufferedReader().use { it.readText() }.split("\n")
sorttext.setText(labels[max!!])
// Releases model resources if no longer used.
if (model != null) {
model.close()
}
}}
fun getMax(arr: FloatArray): Int {
var ind = 0;
var min = 0.0f;
for (i in 0..10) {
if (arr[i] > min) {
min = arr[i]
ind = i;
}
}
return ind
}
} ```

Pick file with registerForActivityResult on Androidx

I need to implement the select file option in my webviewActivity and all the tutorials I found have only the example with the startActivityResult, but it is currently deprecated and so I would like some help on how to transform this code to the new templates of a register as in the documentation: https://developer.android.com/training/basics/intents/result.
WebviewActivity.kt
class WebviewActivity: AppCompatActivity() {
val REQUEST_SELECT_FILE = 1
val FILE_CHOOSER_RESULT = 2
var uploadMessage: ValueCallback<Array<Uri>>? = null
var uploaded: ValueCallback<Uri>? = null
private fun launchWebview(url: String): WebView =
webview_id.apply{
loadUrl(url)
webViewClient : object = WebViewClient(){
//...//
}
webChromeClient : object = WebChromeClient(){
override fun onShowFileChooser(
webView: WebView?,
filePathCallback: ValueCallback<Array<Uri>>?,
fileChooserParams: WebChromeClient.FileChooserParams
): Boolean{
if (uploadMessage != null){
uploadMessage!!.onReceiveValue(null)
uploadMessage = null
}
uploadMessage = filePathCallback
val intent = fileChooserParams.createIntent()
startActivityForResult(intent, REQUEST_SELECT_FILE)
return true
}
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == REQUEST_SELECT_FILE){
uploadMessage!!.onReceiveValue(
WebChromeClient.FileChooserParams.parseResult(
resultCode, data
)
)
uploadMessage = null
} else if (requestCode == FILE_CHOOSER_RESULT){
val result = if (data == null || resultCode != RESULT_OK) null else data.data
uploaded!!.onReceiveValue(result)
uploaded = null
}
super.onActivityResult(requestCode, resultCode, data)
}
}
I used this link to make the code above: Android File Chooser not calling from Android Webview
You have to do sth. like that:
private fun createFile() {
getResult.launch("chartName.pdf")
}
private val getResult = registerForActivityResult(
CreateSpecificTypeDocument("application/pdf")
) { uri ->
if(uri != null){
contentResolver.openFileDescriptor(uri, "w")?.use {
FileOutputStream(it.fileDescriptor).use { fileOutputStream ->
//DO sth. with file
}
}
}
}
with:
class CreateSpecificTypeDocument(private val type: String) :
ActivityResultContracts.CreateDocument() {
override fun createIntent(context: Context, input: String): Intent {
return super.createIntent(context, input).setType(type)
}
}

ImageView doesn't display Image from gallery

I want to pick image from gallery, I added the READ_EXTERNAL_STORAGE permission to Manifest, but it doesn't work fine. It take path uri of image but doesn't show it. Only rectangle with good proportions (screen and code below)
class NewRestaurantFragment : Fragment(R.layout.fragment_new_restaurant) {
companion object {
private const val TAG = "NewRestaurantFragment"
private const val GET_IMAGE_REQUEST_CODE = 2137
}
private lateinit var ivPhoto: ImageView
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
ivPhoto = view.findViewById(R.id.iv_photo)
ivPhoto.setOnClickListener {
selectPhoto()
}
}
private fun selectPhoto() {
val intent = Intent()
intent.apply {
type = "image/"
action = Intent.ACTION_PICK
}
startActivityForResult(intent, GET_IMAGE_REQUEST_CODE)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == GET_IMAGE_REQUEST_CODE && resultCode == RESULT_OK) {
val uri = data!!.data
ivPhoto.setImageURI(uri)
}
}
}

Object does not exist at location android studio Kotlin

I wanna store an image in firebase storage but i got an warning message when running "Object does not exist at location", I don't know where is my mistake, already trying search old answer but all of them in java not kotlin.
class Activity2 : AppCompatActivity() {
private var curFile: Uri? = null
private val imageRef = Firebase.storage.reference
private val REQUEST_CODE_IMAGE_PICK = 0
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity2)
//an image view to select and image inside phone storage
ivfoto.setOnClickListener {
Intent(Intent.ACTION_GET_CONTENT).also {
it.type = "image/*"
startActivityForResult(it, REQUEST_CODE_IMAGE_PICK)
}
}
//btn for upload image to storage
btnupload.setOnClickListener {
uploadImageToStorage("Myimages")
}
}
//function to upload an image to firebase
private fun uploadImageToStorage(filename: String) = CoroutineScope(Dispatchers.IO).launch {
try {
curFile?.let {
imageRef.child("images/$filename").putFile(it).await()
withContext(Dispatchers.Main) {
Toast.makeText(
this#Activity2, "Foto anda telah dipilih",Toast.LENGTH_LONG).show()
}
}
} catch (e: Exception) {
withContext(Dispatchers.Main) {
Toast.makeText(this#Activity2, e.message, Toast.LENGTH_LONG).show()
}
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK && requestCode == REQUEST_CODE_IMAGE_PICK) {
data?.data?.let {
curFile = it
ivfoto.setImageURI(it)
}
}
}
}
Here is the error message,its on the device,already run in physical device and emulator but the error is the same

Multiple results from activity to fragment

I've got a question about results/callback from activities to fragments.
Until now I have a fragment which calls a camera activity to scan QR Codes. So I start the activity from the fragment with startActivityForResult. If a QR Code is successfully scanned I get a callback Intent which is handled in onActivityResult.
This works perfectly.
Now I want to handle multiple scanns. In detail that means, that every successfully scan should call the onActivityResult function without closing the activity. The problem which I got at this point is, that onActivityResult is only called if I call finish() in the camera activity.
So my question is, how can I call onActivityResult multiple times with or without calling finish() but without closing the activity? Or is there another way to handle callbacks from activities to fragments?
This is my fragment code:
class ScanFragment : Fragment() {
private val CHECKIN_CODE = 0
private val CHECKOUT_CODE = 1
companion object {
fun newInstance(): LeadScanFragment = LeadScanFragment()
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.fragment_lead_scan, container, false)
view.checkin.setOnClickListener {view ->
val intent = Intent(activity, CodeScannerActivity::class.java)
startActivityForResult(intent, CHECKIN_CODE)
}
view.checkout.setOnClickListener {view ->
val intent = Intent(activity, CodeScannerActivity::class.java)
startActivityForResult(intent, CHECKOUT_CODE)
}
return view
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == CHECKIN_CODE) {
if (resultCode == Activity.RESULT_OK) {
val returnString = data!!.getStringExtra("hash")
Log.d("scaned in", returnString)
}
}
if (requestCode == CHECKOUT_CODE) {
if (resultCode == Activity.RESULT_OK) {
val returnString = data!!.getStringExtra("hash")
Log.d("scaned out", returnString)
}
}
}
}
And this is the camera activity code:
class CodeScannerActivity : AppCompatActivity() {
private val requestCodeCameraPermission = 1001
private lateinit var cameraSource: CameraSource
private lateinit var detector: BarcodeDetector
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_code_scanner)
if (ContextCompat.checkSelfPermission(this#CodeScannerActivity, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
askForCameraPermission()
} else {
setup()
}
}
private fun setup() {
detector = BarcodeDetector.Builder(this#CodeScannerActivity).build()
cameraSource = CameraSource.Builder(this#CodeScannerActivity, detector).setAutoFocusEnabled(true).build()
cameraSurfaceView.holder.addCallback(surfaceCallback)
detector.setProcessor(processor)
}
private fun askForCameraPermission() {
ActivityCompat.requestPermissions(this#CodeScannerActivity, arrayOf(Manifest.permission.CAMERA), requestCodeCameraPermission)
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if(requestCode == requestCodeCameraPermission && grantResults.isNotEmpty()) {
if(grantResults[0] == PackageManager.PERMISSION_GRANTED) {
setup()
} else {
Toast.makeText(applicationContext, "Permission denied!", Toast.LENGTH_SHORT).show()
}
}
}
private val surfaceCallback = object : SurfaceHolder.Callback {
override fun surfaceCreated(surfaceHolder: SurfaceHolder?) {
try {
cameraSource.start(surfaceHolder)
} catch (exception: Exception) {
Toast.makeText(applicationContext, "Something went wrong", Toast.LENGTH_SHORT).show()
}
}
override fun surfaceChanged(p0: SurfaceHolder?, p1: Int, p2: Int, p3: Int) {
}
override fun surfaceDestroyed(p0: SurfaceHolder?) {
cameraSource.stop()
}
}
private val processor = object : Detector.Processor<Barcode> {
override fun release() {
}
override fun receiveDetections(detections: Detector.Detections<Barcode>?) {
val intent = Intent()
if(detections != null && detections.detectedItems.isNotEmpty()) {
val qrCodes: SparseArray<Barcode> = detections.detectedItems
val code = qrCodes.valueAt(0)
intent.putExtra("hash", code.displayValue)
setResult(Activity.RESULT_OK, intent)
finish()
} else {
setResult(Activity.RESULT_CANCELED, intent)
finish()
}
}
}
}
receiveDetections inside the processor in the lower area of the camera activity code is where the callback Intent is send back to onActivityResult.
You could have the scanner Activity send a local broadcast Intent to forward "results" to the calling Fragment. The Fragment (or its hosting Activity) should set a listener to listen for the broadcast "results". In this way you could perform multiple scans and send each result back to the underlying Activity.

Categories

Resources