Add a Intent in a class - java

I need to start a new activity to show an image in Fullscreen and my Intent is in a class but outside my main class.
class PhotoItem(val user: String, val send: String, val timestamp: Long, val country: String): Item<GroupieViewHolder>(){
override fun bind(viewHolder: GroupieViewHolder, position: kotlin.Int) {
viewHolder.itemView.textView10.text = user
viewHolder.itemView.textView13.text = timestamp.toString()
viewHolder.itemView.textView14.text = country
val uri = send
val targetImageView = viewHolder.itemView.selectphoto_imageview
val targetImageViewFullScreen = viewHolder.itemView.fullscreen
Picasso.get().load(uri).into(targetImageView)
viewHolder.itemView.setOnClickListener{v : View ->
v.getContext().startActivity(Intent(v.getContext(), FullscreenPhoto::class.java))
}
}
override fun getLayout(): kotlin.Int {
return R.layout.photo_from_row
}
}
So I found this line : v.getContext().startActivity(Intent(v.getContext(), FullscreenPhoto::class.java)) because I can't create a basic Intent : val intent = Intent(this,Home::class.java)startActivity(intent)
And I need to have the val uri for load the image into my Image view
thank you in advance.

I guess the issue is that startActivity is not available in PhotoItem
So change GroupieViewHolder class and add activity in constructor like this:
class GroupieViewHolder(val activity: Activity, /* other arguments */)
Now use that field in bind of PhotoItem as below:
override fun bind(viewHolder: GroupieViewHolder, position: kotlin.Int) {
// other codes.........
viewHolder.itemView.setOnClickListener{v : View ->
// using activity field for startActivity
viewHolder.activity.startActivity(Intent(v.getContext(), FullscreenPhoto::class.java))
}

Related

java custom view in flutter

I have a custom view, written in Java and want to use it in my flutter project. Is it possible to convert it to dart-native code or use it as a java class in flutter?
Custom view is quite complex and I am not very experienced in dart language, so would be great to have it either converted to dart or use it as it is
Step 1 : You have to write method channel into dart code:
static Future<void> initSupport({
String? url,
String? appId,
String? clientId,
String? id,
}) async {
await _channel.invokeMethod<void>('initSupport', {
'url': url,
'appId': appId,
'clientId': clientId,
'id': id,
});
}
You have to write into your view where you want to open java view to init this method channel
After this, you have to open your project in android studio
Step 2: Check the below code to get method channel from dart
class MainActivity: FlutterFragmentActivity() {
override fun onNewIntent(intent : Intent){
super.onNewIntent(intent)
setIntent(intent)
}
private val CHANNEL = "channelname"
override fun configureFlutterEngine(#NonNull flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler {
call, result ->
if(call.method == "initSupport"){
initSupport(call)
result.success(true)
}
}
}
Step 3: method of init is
fun initSupport(call: MethodCall){
val url = call.argument<String>("url") ?: "" // here is your dart data
val appId = call.argument<String>("appId") ?: ""
val clientId = call.argument<String>("clientId") ?: ""
val id = call.argument<String>("id") ?: "1"
// You can init your view here like below
Toast.makeText(this,"hello from native", Toast.LENGTH_SHORT).show()
}

How to use interfaces as listeners from and Dialoge in Android?

I don't know how I can use a interface in Android as an event listener. I defined an interface ProfilePictureTakenEvent with the method onProfilePictureTaken. In an dialog, which is opened by a button click on a fragment, the user can take an Image with the camera. I used the method startActivityForResult for it. The result (the image) of this action I get in the fragment (the overriden method onActivityResult).
Now my question: How can I show this picture in my dialog when I get the result in my fragment? I thought that I can use an event listener, but I don't know how and didn't find any Explanation.
Here my code:
UserFragment.tk
class UserFragment() : Fragment() {
private var userFragment: UserFragment? = null
private var profilePictureTakenEvent: ProfilePictureTakenEvent? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_user, container, false)
}
override fun onViewCreated(
view: View,
savedInstanceState: Bundle?
) {
super.onViewCreated(view, savedInstanceState)
this.userFragment = this
val database = UserManagerDatabase(view.context)
val repository = UserRepository(database)
val factory = UserViewModelFactory(repository)
val viewModel = ViewModelProviders.of(this, factory).get(UserViewModel::class.java)
val adapter = UserAdapter(listOf(), viewModel)
rvUsers.layoutManager = LinearLayoutManager(view.context)
rvUsers.adapter = adapter
var emailAddresses: List<String> = emptyList()
viewModel.getAll().observe(viewLifecycleOwner, { userList ->
adapter.users = userList
emailAddresses = userList.map { user -> user.email }
adapter.notifyDataSetChanged()
})
viewModel.getEmailAddresses().observe(viewLifecycleOwner, {emailAddresses = it })
fBtnAddUser.setOnClickListener {
AddUserDialog(view.context,
object: UserCreateEvent {
override fun onAddButtonClicked(user: User) {
viewModel.insert(user)
}
}, emailAddresses, userFragment).show()
}
}
fun setProfilePictureTakenEvent(profilePictureTakenEvent: ProfilePictureTakenEvent) {
this.profilePictureTakenEvent = profilePictureTakenEvent
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == AddUserDialog.REQUEST_IMAGE_CAPTURE) {
this.profilePictureTakenEvent?.onProfilePictureTaken(data)
}
}
}
AddUserDialog.kt:
class AddUserDialog(
context: Context,
private var userCreateEvents: UserCreateEvent,
private var emails: List<String>,
private var parentFragment: UserFragment?
) : AppCompatDialog(context), ProfilePictureTakenEvent {
companion object {
const val REQUEST_IMAGE_CAPTURE = 1
}
private var imageData: Bitmap? = null
override fun onProfilePictureTaken(data: Intent?) {
this.ivProfilePicture.setImageBitmap(data?.extras?.get("data") as Bitmap)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.dialog_add_user)
setTitle(context.getString(R.string.title_add_user))
val editTextViews: Map<String, EditText> = mapOf(
"first_name" to dAddUserEdFirstName,
"last_name" to dAddUserEdLastName,
"email" to dAddUserEdEmail,
"password" to dAddUserEdPassword,
"password_confirmation" to dAddUserEdPasswordConfirmation
)
dAddUserBtnSave.setOnClickListener {
val firstName = dAddUserEdFirstName.text.toString()
val lastName = dAddUserEdLastName.text.toString()
val username = "${firstName.toLowerCase(Locale.GERMAN)}-${lastName.toLowerCase(Locale.GERMAN)}"
val email = dAddUserEdEmail.text.toString()
val password = dAddUserEdPassword.text.toString()
val passwordConfirmation = dAddUserEdPasswordConfirmation.text.toString()
var error = false
val emptyFields: StringBuilder = StringBuilder()
// Check if any EditText is empty
editTextViews.forEach {(key, editTextView) ->
val textEmpty: Boolean = editTextView.text.toString().isEmpty()
if (textEmpty) {
error = true
emptyFields.append("${context.getString(AppHelper.stringTranslation(key))}, ")
}
AppHelper.updateBackground(context, editTextView, if (textEmpty) R.drawable.input_field_error else R.drawable.input_field)
}
if (error) {
//AppHelper.showToastLong(context, context.getString(R.string.error_field_not_filled, AppHelper.commaStringToCorrectGrammatical(context, emptyFields.toString())))
return#setOnClickListener
}
// Check if E-Mail address is valid
if (AppHelper.invalidEmail(email)) {
AppHelper.showToastShort(context, R.string.error_invalid_email)
return#setOnClickListener
}
// Check if supplied E-Mail address is unique
if (emails.contains(email)) {
AppHelper.showToastShort(context, R.string.error_email_already_taken)
return#setOnClickListener
}
// Check if password and password confirmation match
if (password != passwordConfirmation) {
AppHelper.showToastShort(context, R.string.error_password_confirmation_not_matching)
return#setOnClickListener
}
//TODO: Password hashing
// Creating the User
val user = User(firstName, lastName, username, email, password)
userCreateEvents.onAddButtonClicked(user)
// Closing the dialog after calling the onClickEvent and data is valid
dismiss()
}
btnTakeProfilePicture.setOnClickListener {
val takePictureIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
try {
parentFragment?.startActivityForResult(takePictureIntent, REQUEST_IMAGE_CAPTURE)
} catch (e: ActivityNotFoundException) {
AppHelper.showToastLong(context, "Fehler")
}
}
// Close dialog when cancel Button is clicked
dAddUserBtnCancel.setOnClickListener { cancel() }
}
}
ProfilePictureTakenEvent.kt:
interface ProfilePictureTakenEvent {
fun onProfilePictureTaken(data: Intent?)
}
As far I understand, your dialog is still shown after capture the image,
As are create the dialog from that fragment, one of the easy solution can be: hold the object in a global variable, can call a function to show that capture images.
Like:
val dialog = AddUserDialog(....)
inside
onActivityResult(..)
...
dialog.updateImage(data)
Thus actually you will not need any listeners to show the image at dialog.

Pass string from onLoadFinished method to another activity

I have created a content retriever which calls data from the content provider in another application, I can read the data successfully, but I want to pass the data from the onLoadFinished Method in my content retriever to an activity which should display the data on button press. But I am unsure of how to do it, I tried using a getter and setter, but it does not print anything.
Here are the rows in my content provider:
String[] columns = new String[]{"_id", "item"};
MatrixCursor matrixCursor = new MatrixCursor(columns);
matrixCursor.addRow(new Object[]{1, "FOUND"});
//Test is a string object that gets serialized to Json
matrixCursor.addRow(new Object[]{2, new Gson().toJson(test)});
matrixCursor.setNotificationUri(getContext().getContentResolver(), uri);
return matrixCursor;
I want to get the data from the 2nd row and this is what I have in my onLoadFinished in my Retriever class:
class Retriever : LoaderManager.LoaderCallbacks<Cursor>{
private var dataFromJson = ""
//getters and setters
fun setData(data: String){
this.dataFromJson = data
}
fun getData():String{
return dataFromJson
}
//other Loader method such as onCreateLoader, etc.
override fun onLoadFinished(loader: Loader<Cursor>, data: Cursor?) {
try
{
val success: Boolean
if (data != null && data.getCount() > 0)
{
data.moveToFirst()
val dataString = data.getString(1)
//this works, I am able to find the "found" text at the first row
success = dataString.equals("FOUND", ignoreCase = true)
//move to 2nd row
data.moveToNext()
//get data from 2nd row does not work
val JSonData = data.getString(1)
setData(JSonData)
}
else
{
Timber.d( "onLoadFinished Unknown error occurred")
success = false
}
//custom interface listener
listener.onClassListener(success)
}
catch (e:Exception) {
Timber.d("Error")
}
}
}
And in my activity when I create a Retriever object and call the getData() method, it displays nothing.
class TestActivity{
private lateinit var dataRetriever: Retriever
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_test_activity)
//I have a textView called dataTxt
//displays nothing
dataTxt.text = dataRetriever.getData()
}
}
Any help or advice will be highly appreciated
This is because of the loading task is an async operation, when you call the getData() function, the value of dataFromJson is probably still an empty string.
To easily deal with this, you can declare an interface like this:
interface OnDataRetrieveListener{
fun onDataLoad(dataString: String)
}
and then create an instance of it inside the Retriever
private lateinit var listener: OnDataRetrieveListener
fun setListener(listener: OnDataRetrieveListener){
this.listener = listener
}
set the listener in your activity (if anonymously, it's like below):
dataRetriever.setListener(object: Retriever.Listener{
override fun onDataLoad(data: String) {
dataTxt.text = dataRetriever.getData()
}
})
callback the listener when the string is loaded in Retriever:
...
val jsonData = data.getString(1)
listener.onDataLoad(jsonData)
...
then the dataTxt will update

Camera2 - "Must be called from main thread of fragment host" when changing fragment

I'm trying to change the fragment after an image is taken with the following code Google Sample - Camera2Basic.
I've implemented a callback to my MainActivity at line 839 of the above sample. However when I am trying to traverse to a different activity from that callback I receive the following exception:
java.lang.IllegalStateException: Must be called from main thread of
fragment host
Does anyone know anyway around this?
I have the working code in Kotlin
You must replace this callback with:
val captureCallback = object : CameraCaptureSession.CaptureCallback() {
override fun onCaptureCompleted(session: CameraCaptureSession,
request: CaptureRequest,
result: TotalCaptureResult) {
sendBackResult(mFile)
}
}
mCaptureSession!!.capture(captureBuilder.build(), captureCallback, mBackgroundHandler)
} catch (e: CameraAccessException) {
e.printStackTrace()
}
sendBackResult method is as follows:
private fun sendBackResult(resultFile: File?) {
val fileUri = Uri.fromFile(resultFile)
val dataIntent = Intent()
dataIntent.data = fileUri
dataIntent.putExtra("isFront", isFrontCamera)
activity!!.setResult(Activity.RESULT_OK, dataIntent)
activity!!.finish()
}

RecyclerView throwing IndexOutOfBoundsException when trying to insert multiple items and notifying the adapter

I am trying to get unique numbers from call logs of a user and show them in a RecyclerView. By unique I mean if I have shown the number, or corresponding contact once in the list, I have to skip the item. And I want to use a Cursor for showing this to make the rendering quick.
To do this, I have implemented a RecyclerView Adapter which looks like this (Only showing the relevant code, kotlin)
class CallAdapter(val activity: Activity, var cursor: Cursor) : RecyclerView.Adapter<CallAdapter.ViewHolder>() {
val handler = Handler()
val contacts = ArrayList<Contact>()
init {
cursor.moveToFirst()
UniqueLogs(this).start()
}
companion object {
const val TAG = "CallAdapter"
}
override fun onCreateViewHolder(parent: ViewGroup?, viewType: Int): ViewHolder {
val inflater = LayoutInflater.from(activity)
val binding = CallLogItemBinding.inflate(inflater, parent, false)
return ViewHolder(binding)
}
override fun getItemCount(): Int {
return contacts.count()
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val contact = contacts[position]
...
cursor.moveToNext()
}
class ViewHolder(val binding: CallLogItemBinding) : RecyclerView.ViewHolder(binding.root)
class UniqueLogs(val adapter: CallLogAdapterShobhit) : Thread() {
private var available = true
private val cursor = adapter.cursor
private val hash: HashMap<String, Int> = HashMap<String, Int>()
private val contacts = adapter.contacts
private var count = 0
override fun run() {
cursor.moveToFirst()
while (available && cursor.moveToNext()) {
var contact = adapter.getCurrentItemContact()
while (available && hash[contact.phoneNumber] == 1) {
if (cursor.moveToNext()) {
contact = adapter.getCurrentItemContact()
} else {
available = false
}
}
if (available) {
contacts.add(contact)
val position = count
count += 1
adapter.handler.post({
Log.d(TAG, "Position: $position Size: ${adapter.itemCount}")
adapter.notifyItemInserted(position)
})
hash[contact.phoneNumber] = 1
}
}
}
}
}
When I run this code, I am getting an exception which looks like this :-
java.lang.IndexOutOfBoundsException: Inconsistency detected. Invalid view holder adapter positionViewHolder{c75176c position=5 id=-1, oldPos=4, pLpos:4 scrap [attachedScrap] tmpDetached not recyclable(1) no parent}
The position, id, oldPos, pLpos, etc. are different every time but the error is essentially the same.
I've tried writing logs as well to make sure that I am not trying to insert an element before the element is added to contacts array list, but the logs say that all's well.
Any idea what might be wrong here?
You are updating the data in a background thread, but notifying on the main thread. By the time the notification happens, you may have further altered the data. I would suggest that you do all your updates on the background and then just do a generic notifyDataSetChanged when everything is done.
Another option would be to calculate the entire new list in a background thread and then update the real data once and notify in the main thread.
Modifying the data and calling notifyItemInserted should synchronously or you will have inconsistent data.
Putting contacts.add(contact) just before notifyItemInserted should solve it.
adapter.handler.post({
Log.d(TAG, "Position: $position Size: ${adapter.itemCount}")
contacts.add(contact)
adapter.notifyItemInserted(position)
})

Categories

Resources