Using Kotlin in Android Studio, I created a form where user can fill in necessary details AND click an imageButton to launch the camera, take picture and submit the form. I want to add a validation where the user is prevented from submitting the form if they did not take a photo.
I have tried to validate by using imageButton.drawable == null but it did not display the error toast.
Here are the relevant parts of my codes:
class FormActivity : AppCompatActivity() {
var selectedPhotoUri : Uri? = null
companion object {
const val REQUEST_FROM_CAMERA = 1001
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_artactivity)
...
val imageButton = findViewById<ImageButton>(R.id.imageButton)
// launch camera
imageButton.setOnClickListener {
takePhotoUsingCamera()
}
val submitButton = findViewById<Button>(R.id.submitButton)
submitButton.setOnClickListener {
submitForm(userId.toString(), HRWAnswer, ResultAnswer)
}
}
private fun takePhotoUsingCamera(){
ImagePicker.with(this).cameraOnly()
.crop()
.start(REQUEST_FROM_CAMERA)
}
// to access the image captured
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == RESULT_OK) {
when (requestCode){
REQUEST_FROM_CAMERA -> {
selectedPhotoUri = data!!.data
val bitmap = MediaStore.Images.Media.getBitmap(contentResolver, selectedPhotoUri)
val bitmapDrawable = BitmapDrawable(bitmap)
val imageButton = findViewById<ImageButton>(R.id.imageButton)
imageButton.setImageDrawable(bitmapDrawable)
}
}
}
}
fun submitForm(userId : String, TestOption: String, ResultOption: String){
...
val imageButton = findViewById<ImageButton>(R.id.imageButton)
if (imageButton.drawable == null) {
Toast.makeText(this, "Image of your Test result is required!", Toast.LENGTH_LONG).show()
imageButton.requestFocus()
}
...
}
}
Check this may it helps you.
class FormActivity : AppCompatActivity() {
lateinit var imageButton : ImageButton//HERE YOU NEED TO ADD BUTTON.Dont add buttons initialization multiple time in once class.
var selectedPhotoUri : Uri? = null
companion object {
const val REQUEST_FROM_CAMERA = 1001
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_artactivity)
...
imageButton = findViewById<ImageButton>(R.id.imageButton)
// launch camera
imageButton.setOnClickListener {
takePhotoUsingCamera()
}
val submitButton = findViewById<Button>(R.id.submitButton)
submitButton.setOnClickListener {
submitForm(userId.toString(), HRWAnswer, ResultAnswer)
}
}
private fun takePhotoUsingCamera(){
ImagePicker.with(this).cameraOnly()
.crop()
.start(REQUEST_FROM_CAMERA)
}
// to access the image captured
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == RESULT_OK) {
when (requestCode){
REQUEST_FROM_CAMERA -> {
selectedPhotoUri = data!!.data
val bitmap = MediaStore.Images.Media.getBitmap(contentResolver, selectedPhotoUri)
val bitmapDrawable = BitmapDrawable(bitmap)
val imageButton = findViewById<ImageButton>(R.id.imageButton)
imageButton.setImageDrawable(bitmapDrawable)
}
}
}
}
fun submitForm(userId : String, TestOption: String, ResultOption: String){
...
if (imageButton.drawable == null) {
Toast.makeText(this, "Image of your Test result is required!", Toast.LENGTH_LONG).show()
imageButton.requestFocus()
}
...
}
}
as stated by Mike M. in the comment above, it will never be null due to its drawable set layout. i have changed my approach to achieve my target outcome.
Related
Complete beginner, trying this on kotlin. I am trying to capture a photo and save it and then load it on room database. I also need tag the photo and load it according to that. But there is an error like "Caused by: java.lang.NullPointerException: findViewById(R.id.metin) must not be null". How I can solve it? Thanks in advance.
class MainActivity : AppCompatActivity() {
private val cameraRequest = 1888
lateinit var imageView: ImageView
lateinit var textbox : EditText
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
var dao_object = ImageDatabase.getInstance(application).MyDao()
textbox = findViewById(R.id.metin)
setContentView(R.layout.activity_main)
if (ContextCompat.checkSelfPermission(applicationContext, Manifest.permission.CAMERA)
== PackageManager.PERMISSION_DENIED
)
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.CAMERA),
cameraRequest
)
imageView = findViewById(R.id.imageView)
// var textbox: EditText = findViewById(R.id.text)
val photoButton: Button = findViewById(R.id.capture_button)
photoButton.setOnClickListener {
val cameraIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
startActivityForResult(cameraIntent, cameraRequest)
}
val saveButton: Button= findViewById(R.id.save_button)
saveButton.setOnClickListener{
val takenPhoto: ByteArray = DbBitmapUtility.getBytes(imageView.drawingCache)
dao_object.insertImage(MyDatabase(takenPhoto, textbox.text.toString()))
}
val loadButton: Button= findViewById(R.id.load_button)
loadButton.setOnClickListener {
var displayPhoto: ByteArray = dao_object.getImageByTag(textbox.text.toString())
imageView.setImageBitmap(DbBitmapUtility.getImage(displayPhoto))
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == cameraRequest) {
val photo: Bitmap = data?.extras?.get("data") as Bitmap
imageView.setImageBitmap(photo)
}
}
object DbBitmapUtility {
// convert from bitmap to byte array
fun getBytes(bitmap: Bitmap): ByteArray {
val stream = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.PNG, 0, stream)
return stream.toByteArray()
}
// convert from byte array to bitmap
fun getImage(image: ByteArray): Bitmap {
return BitmapFactory.decodeByteArray(image, 0, image.size)
}
}
}
Change the arrangement of the code. Rather than doing the following
textbox = findViewById(R.id.metin)
setContentView(R.layout.activity_main)
do:
setContentView(R.layout.activity_main)
textbox = findViewById(R.id.metin)
setContentView must first be called before you can attempt any manipulation on the activity's view.
You can't use findViewById before you've called setContentView(). There is no View to search in for your view yet at that point.
I can scan a barcode successfully but I somehow cannot get the result. I found out that since I am calling the barcode scanner in a fragment, I need change my code to use this:
class AddIerFragment : Fragment() { ....
val intentIntegrator = IntentIntegrator.forFragment(this)
....
}
The problem is, the "this" keyword is not allowed because it gives me an error of
Type mismatch
Requred: Fragment
Found AddIerFragment
See image below.
I have this code in the fragment
companion object {
#JvmStatic
fun newInstance(param1: String, param2: String) =
AddIerFragment().apply {
arguments = Bundle().apply {
}
}
private const val CAMERA = 1
private const val GALLERY = 2
private const val SCAN = 3
}
R.id.button_atgScan -> {
Dexter.withContext(context!!).withPermissions(
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.CAMERA
)
.withListener(object: MultiplePermissionsListener {
override fun onPermissionsChecked(report: MultiplePermissionsReport?) {
report?.let{
if(report!!.areAllPermissionsGranted()) {
intentIntegrator.setDesiredBarcodeFormats(IntentIntegrator.ONE_D_CODE_TYPES)
intentIntegrator.setPrompt("Scan a barcode")
intentIntegrator.setCameraId(0)
intentIntegrator.setBeepEnabled(false)
intentIntegrator.setBarcodeImageEnabled(true)
intentIntegrator.setOrientationLocked(false)
intentIntegrator.initiateScan()
}
}
}
override fun onPermissionRationaleShouldBeShown(
p0: MutableList<PermissionRequest>?,
p1: PermissionToken?
) {
showRationalDialogForPermission()
}
}).onSameThread().check()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == GALLERY) {
data?.let {
val selectedPhotoUri = data.data
file = File(getPath(selectedPhotoUri))
gView!!.iv_ier_image.setImageURI(selectedPhotoUri)
}
} else if (requestCode == CAMERA) {
data?.extras?.let {
val thumbnail: Bitmap =
data.extras!!.get("data") as Bitmap
file = savebitmap(thumbnail)!!
gView!!.iv_ier_image.setImageBitmap(thumbnail)
}
}
val result = IntentIntegrator.parseActivityResult(requestCode, resultCode, data)
if (result != null) {
if (result.contents == null) {
Log.i("TAG", "NOTHING")
} else {
Log.i("TAG", result.contents)
}
} else {
super.onActivityResult(requestCode, resultCode, data)
}
}
For support or androidx fragments you should use IntentIntegrator.forSupportFragment(this)
AddIerFragment must not be a subclass of the correct Fragment. At the top of its file, make sure you have imported androidx.fragment.app.Fragment instead of android.app.Fragment. And assuming you're using zxing-android-embedded, make sure you call forSupportFragment, not forFragment.
My application checks whether the new selected image is the same as the previous one so that I don't need to update the cloud data, but newBitmap.sameAs(oldBitmap) always return false even though I pick the same photo.
Piece of my code:
private lateinit var oldBitmap: Bitmap
private lateinit var newBitmap: Bitmap
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_my_profile)
myProfilePictureUrl = intent.getStringExtra("myProfilePictureUrl")!!
if (myProfilePictureUrl.isNotEmpty()) {
Picasso.get().load(myProfilePictureUrl).into(my_profile_imageView)
}
oldBitmap = (my_profile_imageView.drawable as BitmapDrawable).bitmap //for later comparison
my_profile_imageView.setOnClickListener {
val intent = Intent(Intent.ACTION_PICK)
intent.type = "image/*"
startActivityForResult(intent, RESULT_CODE_PICK_IMAGE)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == RESULT_CODE_PICK_IMAGE && resultCode == Activity.RESULT_OK) {
val inputStream = contentResolver.openInputStream(data!!.data!!)
val bitmap = BitmapFactory.decodeStream(inputStream)
newBitmap = bitmap //for comparison
my_profile_imageView.setImageBitmap(bitmap)
}
}
And when the user click on the "save" button on the action bar will it first check whether they are the same photo:
private fun updateProfile(nickname: String) {
if (this::newBitmap.isInitialized && !newBitmap.sameAs(oldBitmap)) { //here
//upload task code
}
}
THE PROBLEM IS:
!newBitmap.sameAs(oldBitmap) always return false even they are the same photo, may be the problem of PICASSO? Or the way I used to compare is not right. Any help would be appreciated.
Users can show their photo on the imageView button. Codes are given below.
The problem is, savedInstanceState returns null since photo on the imageView is obtained in the onActivityResult function.
Therefore, if users click on btnRegistration and come back to this app again, they lose photo on the imageView.
Could you please help, how to edit these codes to solve this problem
private var iv_crop: ImageView = null
public var tmpResultUri: Uri?=null
public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
if (requestCode == CropImage.CROP_IMAGE_ACTIVITY_REQUEST_CODE) {
val cimg = CropImage.getActivityResult(data)
iv_crop.setImageURI(cimg.uri)
val resultUri = cimg.uri
tmpResultUri = resultUri
}}
#RequiresApi(Build.VERSION_CODES.O)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (savedInstanceState != null) {
var strResultUri: String?= null
strResultUri = savedInstanceState.getString(strResultUri)
// var drawable: BitmapDrawable = iv_crop.getDrawable() as BitmapDrawable
//var bitmapImgCropped = drawable.getBitmap()
}
else {
iv_crop.setOnClickListener {
CropImage.activity().start(this) // <== Starts a new activity here.
}
}
btnRegistration?.setOnClickListener {
val intent = Intent()
intent.setClassName( "com.mylab.myApp","com.mylab.myApp.MainActivity")
startActivity(intent) // <== Starts a new activity here.
finish()}
}
override fun onSaveInstanceState(outState:Bundle ) {
outState.run{
outState.putString(tmpResultUri.toString(), tmpResultUri.toString())
}
super.onSaveInstanceState(outState)
}
override fun onRestoreInstanceState(savedInstanceState: Bundle?) {
super.onRestoreInstanceState(savedInstanceState!!)
savedInstanceState.run {
val strtmpResultUri = getString(tmpResultUri.toString())
}
}
You need to store your image URI using a static key. Something like this.
companion object {
private const val ARG_IMAGE_URI = "imageuri"
}
Then when you save and retrieve your URI, use this value as your key and not the uri.
override fun onSaveInstanceState(outState:Bundle ) {
outState.putString(ARG_IMAGE_URI, tmpResultUri.toString())
super.onSaveInstanceState(outState)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (savedInstanceState != null) {
val strResultUri: String?= savedInstanceState.getString(ARG_IMAGE_URI)
}
}
I am currently using Kotlin. I am trying to change the colour of a box in main activity by going to another activity that is the colour setting activity. My code returns no errors but not working. I tried reading different result on this page but none answering my question. Thank u for your help.
mainactivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val button_box = findViewById<Button>(R.id.button_box)
button_box.setOnClickListener {
val intent = Intent(this, boxColor::class.java)
startActivity(intent)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == RESULT_OK) {
val returnColor = data!!.getStringExtra("colorName")
val boxColorChoice = when (returnColor) {
"green" -> R.drawable.box_green
"grey" -> R.drawable.box_grey
"lblue" -> R.drawable.box_lblue
"purple" -> R.drawable.box_purple
"red" -> R.drawable.box_red
"white" -> R.drawable.box_white
"yellow" -> R.drawable.box_yellow
else -> R.drawable.box_white
}
button_box.setBackgroundResource(boxColorChoice)
}
}
here is boxcolor.kt
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_box_color)
val green = findViewById<Button>(R.id.green_box)
val red = findViewById<Button>(R.id.red_box)
val white = findViewById<Button>(R.id.white_box)
val yellow = findViewById<Button>(R.id.yellow_box)
val grey = findViewById<Button>(R.id.grey_box)
val lblue = findViewById<Button>(R.id.lblue_box)
green.setOnClickListener {
val intent = Intent()
intent.putExtra("colorName", "green")
setResult(Activity.RESULT_OK, intent)
finish()
}
(and the same onclicklistener for all the other colours)
also I know this is small problem but thank you very much for helping. I am 14 year old boy from rajasthan and I want to be a programmer and learning
you need to use startActivityForResult your code must change to these :
mainactivity.kt
...
val mRequestCode = 101 //ADD THIS LINE
...
button_box.setOnClickListener {
val intent = Intent(this, boxColor::class.java)
startActivityForResult(intent, mRequestCode) //ADD THIS LINE
}
...
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == mRequestCode) { //CHANGE THIS LINE
...
}
}
and in your boxcolor.kt:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_box_color)
val mRequestCode = 101 //ADD THIS LINE
...
green.setOnClickListener {
val intent = Intent()
intent.putExtra("colorName", "green")
setResult(mRequestCode, intent) //CHANGE THIS LINE
finish()
}
(and the same onclicklistener for all the other colours)
Note that don't use Activity.RESULT_OK as requestCode
Please use Request Code and startActivityForResult
Example:
private val RC = 101
val intent = Intent(this, boxColor::class.java)
startActivityForResult(intent, RC)