I'm trying to support game controller input in my app, I should be able to receive the input when in focus of any element of the app. By the way it is not a game.
I have tried following this guide from the android developer documentation to no avail.
The problem I am facing is that I cannot override the onKeyDown function.
My only knowledge is that I need to override this function in either a custom view or activity, but this is what I am having trouble with.
Here is the sort of code I am attempting.
class customView(context:Context) : View(context){
override fun onKeyDown(...){
// Code to handle keydown
}
}
I am getting an error saying something about onKeyDown not being a method of the view class (sorry I'm not at my computer at the moment so I don't know the exact error)
Just as another note I have also looked at this about custom views and I don't really understand how I should go about implementing controller input. For example if I was to create a new view, I would prefer to override something like a fragment which would allow me to have controller input across the entire app. Would it work better overriding the activity?
I'm new to android and kotlin development, so I'm sorry if this is really simple.
Thanks
You forgot the return type
class customView(context: Context) : View(context) {
override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
return super.onKeyDown(keyCode, event)
}
}
EDIT
To answer your question in the comments, in order to add this view to an XML layout your would need to do something like this
<package.of.my.costumview.customView
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
Related
It is typical to set the inputType=textPassword for fields where users would type in anything that is at risk, like...a password. And when the user types it, each character they type is briefly flashed to let the user know what was actually entered and then turns into an asterisk so that casual observers (spies) have a lot more difficulty seeing what is typed.
Generally this works fine.
I have a specific case where for security reasons the character must NOT be flashed. Instead I want to simply display the asterisk.
I could handle each tap individually via setOnKeyListener(), but it seems like this should be easy. However I don't see any built-in solution. Please tell me that I'm missing something.
Thanks for all those who commented, prodded, and pointed out excellent tips. Using these valuable assists I was able to do something that was actually pretty easy and seems to work perfectly for this situation.
The trick is to override PasswordTransformationMethod and force your EditText to use this new one. The original charAt() method uses Spannable that waits a second and half before hiding it. By overriding that method your code can do something much simpler.
Here's an example of the custom class (in kotlin)
class ReallyHideMyPassword : PasswordTransformationMethod() {
companion object {
const val HIDE_CHAR = '*'
}
override fun getTransformation(source: CharSequence, view: View): CharSequence {
return PasswordCharSequence(source)
}
inner class PasswordCharSequence (private val source: CharSequence) : CharSequence {
override val length: Int
get() = source.length
override fun get(index: Int): Char = HIDE_CHAR
override fun subSequence(startIndex: Int, endIndex: Int): CharSequence {
return source.subSequence(startIndex, endIndex)
}
}
}
And to use this in your EditText:
val et = findViewById<EditText>(R.id.my_password_edittext)
et.transformationMethod = ReallyHideMyPassword();
Turns out that this is similar to https://stackoverflow.com/a/23110194/624814 (thanks Per.J!), but now you have it in kotlin. It's so similar that this question will probably be closed as too similar. But the wording of the question should help people find the answer more easily than the other post.
You are not missing anything, I've struggled with this in the past and until now I've found no built-in solution, I've used addTextChangedListener to do this and external libraries.
Disabling this setting does exactly what you asked, and it applies to every app but I guess you only can change this by code on a rooted phone.
I know this is no solution but it's a statement that this isn't available for developers and we have to make our own thing.
EDIT:
The comments offers great solutions but as you said, not built-in.
I am developing an Android application using Kotlin programming language. I am starting to use the Model-View-Presenter pattern for my application. To be honest, this is my first time using the MVP pattern even though I have been doing Android Development quite a little while. Now, I am a little bit struggling following the best practices and standards of the pattern.
This is the feature now I am currently developing. A very simple and basic feature.
The application will update a text view. When the text view is updated, a string (message) will be passed to a function as a parameter. Inside the function, if the string is empty, it will hide the text view. Otherwise, it will show the text view again. My struggle is that I am not quite sure how to implement my code that fits the MVP pattern. Especially, the logic to toggle the visibility state of the text view.
This is the current signature of my presenter class called, LoginActivityPresenter
class LoginActivityPresenter(viewArg: View)
{
private var view:View = viewArg
interface View
{
fun updateErrorMessageTextView(message: String)
}
}
What I am thinking is that the activity class will implement the LoginActivityPresenter.View and provide the implementation of the updateErrorMessageTextView method. So in the activity, inside one single function, it will do the following tasks.
It will check if the string is empty. If yes, it will hide the view. Otherwise, it will show the view (back). Then it will set the text view with the message. All in the activity class because of the above presenter class signature.
The other way I am thinking of implementing LoginActivityPresenter class is as follows.
class LoginActivityPresenter(viewArg: View)
{
private var view:View = viewArg
fun updateErrorMessage(message: String) {
if (message.isNullOrEmpty()) {
this.view.hideErrorTextView()
return
}
this.view.showErrorTextView()
this.view.updateErrorMessageTextView(message)
}
interface View
{
fun updateErrorMessageTextView(message: String)
fun showErrorTextView()
fun hideErrorTextView()
}
}
So in the second implementation, the presenter class will handle the logic of showing or hiding the view based on the string value rather than logic is being handled by the activity class.
My question is that which approach is more suitable and standard way for the MVP pattern and why?
In my data binding layouts, I set long click listeners via:
android:onLongClick="#{ ..binding expression.. }"
The code runs as expected, but the android:onLongClick attribute is flagged as 'unknown' in the xml file. Additionally, there is no auto-complete for it.
The binding adapter for this attribute is included with the data binding library in ViewBindingAdapter.java.
As said here you can use: android:onLongClick="#{() -> handler.onLongClicked()}"
but if you want to remove warning you can use below code instead of above:
app:onLongClickListener="#{() -> handler.onLongClicked()}"
if you use app:onLongClickListener data binding will find setOnLongClickListener in the View class and will use that method
There is a difference between onLongClickListener and onLongClick : We have a method in view called setOnLongClickListener but we do not have a method like this: setOnLongClick and when you use an attribute atr in data binding that has a method like setAtr data binding will find and use that method automatically not needing any adapter. Thus onLongClickListener do not need any adapter (if there is an adapter it will be used instead of setOnLongClickListener) but onLongClick always needs adapter.
Thanks to Bahman for the helpful answer. Here's some more details and options.
If one uses the native xml binding app:onLongClickListener then the viewModel must return Boolean or android compilation crashes with cannot generate view binders java.lang.StackOverflowError
So this crashes the compiler: app:onLongClickListener="#{() -> viewModel.onLongClickRowNoReturn()}" assuming the viewModel method does not return Boolean. If it returns a boolean it works. The Boolean is required by View.OnLongClickListener see View.OnLongClickListener
Alternatively we can use our own custom adapter
#BindingAdapter("onLongClick")
fun setOnLongClickListener(view: View, listener: Runnable) {
view.setOnLongClickListener { listener.run(); true }
}
XML: app:onLongClick="#{() -> viewModel.onLongClickRowNoReturn()}"
Here's the docs as Bahman also linked, though they are not very informative regarding this issue.
My viewModel example:
override fun onLongClickRow():Boolean {
Toast.makeText(context, "LongClick", Toast.LENGTH_SHORT).show()
return true
}
override fun onLongClickRowNoReturn() {
Toast.makeText(context, "LongClick without return", Toast.LENGTH_SHORT).show()
}
onLongClick and onLongClickListener do the exact same thing because there is a BindingMethod that connects onLongClick to setOnLongClickListener in ViewBindingAdapter.java.
It seems like the IDE just complains about any android: prefixed attributes that don't exist in the framework. This is why it doesn't complain about the app: versions. However, they are not always freely interchangeable because for example android:text does some performance optimizations under the hood whereas app:text would just call setText directly.
I have a ViewModel in my android app, that has some logic, and the view needs to be adjusted/perform different things depending on the result of that logic. At first I tried to do it exclusively with observers and reacting to the state of the data in the viewmodel, but it was too complicated.
Then I found the concept of commands using the SingleLiveEvent class, and I found it good because it reminds me the same pattern when using Xamarin and the microsoft's mvvvm. One of the (few) good things that working with xamarin has ;)
Well, the problem in my case is that when I have more than one command that needs to be send to the view, the view is receiving only one command. Sometimes the last one, sometimes the first one. For example, a couple of commands that order the view to perform complicated things:
sealed class CustomCommands{
class CustomCommand1 : CustomCommands()
class CustomCommand2() : CustomCommands()
class CustomCommand3() : CustomCommands()
class CustomCommand4() : CustomCommands()
class CustomCommand5() : CustomCommands()
}
Then in my viewModel, I have the commands SingleLiveEvent object:
class CustomViewModel...{
val commands: SingleLiveEvent<CustomCommands> = SingleLiveEvent()
private fun doComplicatedThingsOnTheUI() {
GlobalScope.launch(Dispatchers.IO) {
if (someConditionsInvolvingRestRequestsAndDatabaseOperations()){
commands.postValue(CustomCommands.CustomCommand1())
commands.postValue(CustomCommands.CustomCommand2())
} else {
commands.postValue(CustomCommands.CustomCommand3())
commands.postValue(CustomCommands.CustomCommand4())
}
commands.postValue(CustomCommands.CustomCommand5())
}
}
}
And in the Activity/Fragment, I have the observer for the commands, that should react for each command and does the work:
class MainActivity...{
viewModel.commands.observe(this, Observer { command ->
Rlog.d("SingleLiveEvent", "Observer received event: " + command.javaClass.simpleName)
when (command) {
Command1->doSomething1()
Command2->doSomething2()
}
}
Well, the problem is that the view is normally receiving only the last command (Command5). But the behaviour depends on the api level of the Android SDK. By api 16, the view receives the last command. By Api 28, the view receives normally the first and the last command (for example, Command1 and Command5, but not Command2).
Maybe I'm understanding the capabilities of the SingleLiveEvent class wrong, or the whole Command thing wrong, but I need a way to allow the viewmodel to order the view to do somethings depending on the state of many objects and variables. The code above is only a sample, the reality es more complicated than that.
I don't want to use callbacks between the viewmodel and the view, because I read somewhere that that breaks the whole MVVM pattern.
Maybe someone has an advice for me. Any help would be welcome.
Thank you in advance.
I think I found a workaround, that seems to work (I have tested it only a couple of hours).
The thing is that I'm using "command.postValue(XXX)", because that piece of code is running inside a couroutine, that is, in other thread. Because of that I can not use command.value directly.
But the fact is that using command.value=Command1(), it works. I mean, the view receives all the commands sent, and very important too, with the same order as they were sent. Because of that I wrote a little funcion to send the commands to the UI switching the thread.
I'm not sure if this is correct, I'm a new to Kotlin coroutines and I have to admit that I don't understand them very well yet:
private suspend fun sendCommandToView(vararg icommands: CustomCommands) = withContext(Dispatchers.Main) {
icommands.forEach {
commands.value = it
}
}
And then I send the commands
sendCommandToView(CustomCommand1(),CustomCommand2(),CustomCommand5())
This seems to work. Thougt that the "post" method would work in a similar way, but it does not.
Regards.
I am building an app on MVVM+Kotlin+Databinding, and i have this situation i am stuck at.
I have LoginFragment which has a phone number edittext and a button,
Now i need to check if the phone number is empty or not when user clicks the button.
Normally i would do that by using this code in my fragment.
if(!binding!!.phone.text.isEmpty()) {
//do something
}
But according to experts my view should not know anything about the business logic, Hence i need to have this check inside my viewModel.
so what should be the best way to achieve this?
Here is the bet practice to achieve that (from my point of view):
In your layout add text watcher and text to your EditText
android:text="#{view_model.phone}"
app:addTextChangedListener="#{view_model.phoneWatcher}"
and on click method to your button
android:onClick="#{() -> view_model.save()}"
Inside the ViewModel you will have text observable and a watcher
val phone = ObservableField<String?>()
val phoneWatcher = object : TextWatcherAdapter() {
override fun afterTextChanged(s: Editable?) {
phone.set(s?.toString())
}
}
Now you can make your check inside ViewModel
fun save() {
if (phone.get()?.isNotEmpty == true) {
// TODO: do something
}
}
Also please note that it is a best practice to avoid doing something like that binding!!.phone in Kotlin. If you're using !! to make a possible nullable object look like it is not-nullable (even if you're 100% sure it is) - you're doing something wrong.