Kotlin Back Button on Documentscanner - android

I wanted to create an app with documentscanner. It works overall. But on the last page, i want a "Back" Button, that goes back to the start to makes a new picture.
But when i click my back button, it crashes and gives back that error:
LifecycleOwner com.websitebeaver.documentscanner.demo.MainActivity#43057a2 is attempting to register while current state is RESUMED. LifecycleOwners must call register before they are STARTED.
Any ideas why and what i can change? I didnt find something about that
#RequiresApi(Build.VERSION_CODES.Q)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// cropped image
croppedImageView = findViewById(R.id.cropped_image_view)
//val imageUrl = croppedImageView.getTag(R.id.cropped_image_view)?.toString()
shareBtn = findViewById(R.id.shareBtn)
shareBtn.setOnClickListener {
val intent= Intent(Intent.ACTION_SEND)
val pdfURL = convertImageViewToPdf(croppedImageView)
print(pdfURL)
intent.putExtra(Intent.EXTRA_STREAM, pdfURL)
intent.type = "application/pdf"
startActivity(intent, null)
}
backBtn = findViewById(R.id.backBtn)
backBtn.setOnClickListener {
documentScanner.startScan()
}
// start document scan
documentScanner.startScan()
}
i Only get this error when clicking on the backBtn, the share buttton works

Related

How to listen for activity result and take action for an activity started from third party library when using Jetpack compose? [duplicate]

I am trying to implement sign-in hints in my Android app using Jetpack Compose, but this API requires an Activity to work.
fun showPhoneNumberHint(activity: Activity) {
val hintRequest: HintRequest = HintRequest.Builder()
.setPhoneNumberIdentifierSupported(true)
.build()
val intent = Auth.CredentialsApi.getHintPickerIntent(apiClient, hintRequest)
val requestCode = 12345
try {
startIntentSenderForResult(activity, intent.intentSender, requestCode, null, 0, 0, 0, null)
} catch (exception: SendIntentException) {
// Error handling
}
}
So I guess that I'll have to pass the Activity object all the way down to the Composable where it's needed, which doesn't seem very clean but it should work.
But now the result of the hint will be received in the Activity's onActivityResult() and I'm not sure what the right way is to get it back to the Composable where it's needed.
Is there some clean/standard/alternative way to do this? Preferably I'd just keep all of this logic contained inside the Composable.
I ended up using rememberLauncherForActivityResult in combination with the ActivityResultContracts.StartIntentSenderForResult() contract to listen for the result. This returns a launcher that can be used to start the intent.
Instead of Auth.CredentialsApi, which requires the deprecated GoogleApiClient, I'm now using the Credentials.getClient. For this I still needed an Activity which I got using LocalContext.current.
val phoneNumberHintLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.StartIntentSenderForResult()
) {
if (it.resultCode != RESULT_OK) {
return#rememberLauncherForActivityResult
}
val credential: Credential? = it.data?.getParcelableExtra(Credential.EXTRA_KEY)
val hintResult = credential?.id
if (hintResult !== null) {
phoneNumber = hintResult
}
}
val context = LocalContext.current
LaunchedEffect(Unit) {
val hintRequest: HintRequest = HintRequest.Builder()
.setPhoneNumberIdentifierSupported(true)
.build()
val phoneNumberHintIntent = Credentials.getClient(context)
.getHintPickerIntent(hintRequest)
phoneNumberHintLauncher.launch(
IntentSenderRequest.Builder(phoneNumberHintIntent)
.build()
)
}
Activity.onActivityResult() is deprecated and you shouldn't use it even without compose. You should use the Activity Result APIs introduced in AndroidX Activity and Fragment.
The Activity Result APIs provide a registerForActivityResult() API for registering the result callback. registerForActivityResult() takes an ActivityResultContract and an ActivityResultCallback and returns an ActivityResultLauncher which you’ll use to launch the other activity.
Example without compose:
val getContent = registerForActivityResult(GetContent()) { uri: Uri? ->
// Handle the returned Uri
}
override fun onCreate(savedInstanceState: Bundle?) {
// ...
val selectButton = findViewById<Button>(R.id.select_button)
selectButton.setOnClickListener {
// Pass in the mime type you'd like to allow the user to select
// as the input
getContent.launch("image/*")
}
}
In compose use rememberLauncherForActivityResult() instead of registerForActivityResult:
val result = remember { mutableStateOf<Bitmap?>(null) }
val launcher = rememberLauncherForActivityResult(ActivityResultContracts.TakePicturePreview()) {
result.value = it
}
Button(onClick = { launcher.launch() }) {
Text(text = "Take a picture")
}
result.value?.let { image ->
Image(image.asImageBitmap(), null, modifier = Modifier.fillMaxWidth())
}
The problem with the API you're trying to use is it requires the use of onActivityResult. So, you have no other option but to use it. Try opening an issue on github requesting to update their API.

How to directly pass Image into ArthurHub / Android-Image-Cropper for cropping

I am using Jetpack compose for my UI, Activity Result Contracts and ArthutHub Android Image Cropper Library to crop images in my App. Everything works fine as expected with the following code:
val (result, launcher) = setUpContentPhotoCropImageIntent()//this activity result
//contracts in launched on a button press
result.value?.let {
//code here to save the image and show it in the UI, upload to cloud storage etc.
}
#Composable
fun setUpContentPhotoCropImageIntent(): Pair<MutableState<Uri?>,
ManagedActivityResultLauncher<Any?, Uri?>> {
val cropActivityResultContract = object : ActivityResultContract<Any?, Uri?>() {
override fun createIntent(context: Context, input: Any?): Intent {
CropImage.isExplicitCameraPermissionRequired(context)
CropImage.getPickImageChooserIntent(context)
return CropImage
.activity()
.setActivityTitle("Choose Photo")
.setCropMenuCropButtonTitle("Select")
.setAllowRotation(true)
.setGuidelines(CropImageView.Guidelines.ON_TOUCH)
.setCropShape(CropImageView.CropShape.RECTANGLE)
.setAllowFlipping(true)
.setOutputCompressQuality(100)
.setFixAspectRatio(true)
.setMaxCropResultSize(
2000,
2000
)
.getIntent(context)
}
override fun parseResult(resultCode: Int, intent: Intent?): Uri? {
return CropImage.getActivityResult(intent)?.uri
}
}
val result = remember { mutableStateOf<Uri?>(null) }
val launcher = rememberLauncherForActivityResult(cropActivityResultContract) {
result.value = it
}
return Pair(result, launcher)
}
So with this approach, the library takes care of not only cropping images but also capturing them via camera/gallery. I would like to pass a Bitmap image myself(by getting images using the built-in Android APIs to Take Picture and get Gallery Image) and use this library for just cropping, so that I can have 2 dedicated buttons for the user to either capture photo or choose from Gallery.
I have the image now, I want this library to just crop it for me, How do i Pass an Image into it?
Try to use the latest library https://github.com/CanHub/Android-Image-Cropper
and them you can pass the image like this:
class MainActivity {
private val cropImage = registerForActivityResult(CropImageContract()) { result ->
if (result.isSuccessful) {
// use the returned uri
val uriContent = result.uriContent
val uriFilePath = result.getUriFilePath(context) // optional usage
} else {
// an error occurred
val exception = result.error
}
}
private fun startCrop() {
// start cropping activity for pre-acquired image saved on the device and customize settings
cropImage.launch(
options(uri = imageUri) {
setGuidelines(Guidelines.ON)
setOutputCompressFormat(CompressFormat.PNG)
}
)
}
}

To enable different pages to be opened according to the selection of the radio buttons on the registration page

I have 2 radio buttons on my user registration page. If the user has registered by clicking the first radio button, I want to open the page according to him when he opens the application again, and if he has registered by clicking the second radio button, I want to show the page accordingly. How can I do that ?
class SignUpPage : AppCompatActivity() {
private lateinit var binding: ActivitySignUpPageBinding
private lateinit var auth : FirebaseAuth
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivitySignUpPageBinding.inflate(layoutInflater)
val view = binding.root
setContentView(view)
auth = Firebase.auth
}
fun loginSignUp (view: View){
val name = binding.nameText.text.toString()
val surname = binding.surnameText.text.toString()
val email = binding.emailText.text.toString()
val password = binding.PasswordText.text.toString()
val button = binding.radioButton4.isChecked
val button2 = binding.radioButton5.isChecked
if(name.equals("")|| surname.equals("")|| email.equals("") || password.equals("") || button.equals("") || button2.equals("")) {
Toast.makeText(this,"Lütfen Tüm Alanları Doldurun.",Toast.LENGTH_SHORT).show()
}
else if (radioButton4.isChecked){
auth.createUserWithEmailAndPassword(email,password).addOnSuccessListener {
val intent = Intent(this#SignUpPage,AccetpActivity::class.java)
startActivity(intent)
finish()
}
}
else if(radioButton5.isChecked){
auth.createUserWithEmailAndPassword(email, password).addOnSuccessListener {
val intent = Intent(this#SignUpPage,MainActivity::class.java)
startActivity(intent)
finish()
}.addOnFailureListener {
Toast.makeText(this#SignUpPage,it.localizedMessage,Toast.LENGTH_SHORT).show()
}
}
}
}
You can store value of radio button which selected by user in Android Shared preferences.
When user reopen the app, check the value from preference in splash activity of your app and open activity as per value.
Shared pref ref: https://developer.android.com/training/data-storage/shared-preferences

Input value not updating in another activity which I pass in Intents

Mine Main Activity :-
var sec = second_activity()
var button1: Button? = null
var button2: Button? = null
var button3: Button? = null
var button4: Button? = null
button1 = findViewById<View>(R.id.button1) as Button
button2 = findViewById<View>(R.id.button2) as Button
button3 = findViewById<View>(R.id.button3) as Button
button4 = findViewById<View>(R.id.button4) as Button
button1?.setOnClickListener {
sec.input = "a"
val intent: Intent = Intent(this, second_activity::class.java)
startActivity(intent)
}
button2?.setOnClickListener {
sec.input = "b"
val intent: Intent = Intent(this, second_activity::class.java)
startActivity(intent)
}
Second activity :-
class second_activity : AppCompatActivity(), NavigationView.OnNavigationItemSelectedListener {
private lateinit var toolbar: Toolbar
private lateinit var mDrawerLayout: DrawerLayout
var input : String = " "
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_second)
//getting recyclerview from xml
val recyclerView = findViewById<RecyclerView>(R.id.recyclerView)
//adding a layoutmanager
recyclerView.layoutManager = LinearLayoutManager(this, RecyclerView.VERTICAL, false)
//crating an arraylist to store users using the data class user
val users = ArrayList<User>()
//adding some dummy data to the list
//creating our adapter
val adapter = CustomAdapter(this , users)
//now adding the adapter to recyclerview
recyclerView.adapter = adapter
Toast.makeText(this, input , Toast.LENGTH_SHORT).show()
when(input) {
"a" -> {
users.add(User(R.drawable.bc))
}
"b" -> {
users.add(User(R.drawable.bc))
users.add(User(R.drawable.bc))
users.add(User(R.drawable.bc))
users.add(User(R.drawable.bc))
}
}
}
Input value is not updating which I pass from MainActivity. It is always taking the blank value which are present in second activity. I also tried by changing the position of Input. but not worked. please help
Is there any other way to find which button is clicked in MainActivity from Second Activity
Yes, there is another way. Use intent.putExtra("requestCode", requestCode). Then in the second activity you can get that requestCode with getIntent().getExtra().getInt("requestCode").
Yes, you can pass the values from one activity to another activity using the following code,
val intent: Intent = Intent(this, SecondActivity::class.java)
intent.putExtra(name, value)
startActivity(intent)
I have given sample code below, please try this..
In first activity, I send the "language" value.
val intent: Intent = Intent(this, SecondActivity::class.java)
intent.putExtra("language", "tamil")
startActivity(intent)
In second activity, I retrived the "language" value.
Put this code in your second activity onCreate()
val intent: Intent = getIntent()
var language = ""
if (intent != null) {
language = intent.getStringExtra("language")
}
println("Language : $language")

Getting a Null value while passing data through intent to another activity

When I do a debug, I can see the first activity sending thecorrect number, but the second activity always gets a null value. Thank you for helping.
First Activity:
val intent = Intent(this#InfBateria,ControlActivity::class.java)
intent.putExtra(EXTRA_PERCENTAGE,batteryPercentage.toString())
Second Activity:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.control_layout)
m_address = intent.getStringExtra(Connect.EXTRA_ADDRESS)
val m_percentage: String? = intent.getStringExtra(InfBateria.EXTRA_PERCENTAGE)
textView9.text = m_percentage
[Edit] Code of the Activity (differente from the First one) that acttualy opens da Second Activity:
val intent = Intent(this,ControlActivity::class.java)
intent.putExtra(EXTRA_ADDRESS,address)
startActivity(intent)
If you don't do anything with this result intent, it will not do anything:
val intent = Intent(this#InfBateria,ControlActivity::class.java)
intent.putExtra(EXTRA_PERCENTAGE,batteryPercentage.toString())
You need to update the intent that you are sending to the second activity, like so:
val intent = Intent(this, ControlActivity::class.java)
intent.putExtra(EXTRA_ADDRESS, address)
intent.putExtra(EXTRA_PERCENTAGE, batteryPercentage.toString())
startActivity(intent)
Then your receiving activity will get both the extras. :-)
If you have Three activities and want to get data from 1st to 3rd you do it like this:
First Activity:
val intent = Intent(this, SecondActivity::class.java)
intent.putExtra(ThirdActivity.EXTRA_PERCENTAGE, batteryPercentage.toString())
startActivity(intent)
Second Activity:
val intent = Intent(this, ThirdActivity::class.java)
intent.putExtra(ThirdActivity.EXTRA_ADDRESS, address)
// Get the data you sent to this activity and re-add it to send again
intent.putExtra(ThirdActivity.EXTRA_PERCENTAGE, getIntent().getStringExtra(ThirdActivity.EXTRA_PERCENTAGE)
startActivity(intent)
Third Activity:
m_address = intent.getStringExtra(EXTRA_ADDRESS)
m_battery = intent.getStringExtra(EXTRA_PERCENTAGE)

Categories

Resources