if i have this button:
<Button
android:id="#+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/button" />
which is more advisable in kotlin when it comes to calling views?
this:
val buttonVar: Button = findById(R.id.buuton)
buttonVar.setOnClickListener{
//my code
}
or:
button.setOnClickListener{
//my code
}
When it comes to performance in Kotlin , this is more advisable
button.setOnClickListener{
//my code
}
Because calling views by their ID directly will generate a local view cache.
So the when the view is called the first time kotlin plugin will execute findViewById just a single time, and the next time the view gets called, it will get recovered from the cache . So accesing that view will be faster.
You can refer to this link for more informations enter link description here
I hope this will help you, don't forget to accept the answer if it helps you.
First one is recommended now. The reason is because if you do it the second way, you would be using kotlinx synthetic which is no longer a recommended practice. Source
Related
I know this is probably a quite simple question to answer but I want to import my button from activity_main.xml with the id "button1":
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
In the MainActivity.kt so I can add a setOnClickListener to it.
I saw something like this:
MainActivity.kt:
val button1 = findViewById(R.id.button1) as Button
That gives me 2 errors:
unresolved reference: findViewById;
unresolved reference: Button;
This is the action I want to add:
button1.setOnClickListener {
Toast.makeText(applicationContext, "Hello World", Toast.LENGTH_LONG).show()
}
So I could use the setOnClickListener on "button1" but it wont work.
Whats the standard way of importing a button with kotlin so I can use it properly?
So apparently, I needed to add
apply plugin: 'kotlin-android-extensions'
to the build.gradle (Module:app).
After that I was able to import all views via
import kotlinx.android.synthetic.main.activity_main.*
on the MainActivity.kt so I could use the setOnClickListener to the Id I gave the button in the activity_main.xml
I think the findViewById() is just another way to do this, still good. Thanks
You Could Do This:
val button1 = findViewById<Button>(R.id.button1)
In your code, make sure that the Button and findViewById both were referenced from Activity class.
There are different ways for view binding. The recommended one is to use either data binding or view binding feature.
Kotlin synthetics, part of Android Kotlin Extensions Gradle plugin, is Kotlin only method of view binding which doesn't expose nullabilty. That means all the views are declared as platform types. Now beginning from Kotlin 1.4.20, they will not be supported. Check migration to view binding here: https://developer.android.com/topic/libraries/view-binding/migration
findVewbyId is another way for the same purpose, but this comes with some expenses like traversing the view hierarchy to get the view, runtime exceptions, boilerplate code.
Other way is to use library like ButterKnife
I have a single button in my app. (simplified) it looks like this:
<ImageButton
android:id="#+id/SendButton"
android:onClick="getCommand"
app:srcCompat="#drawable/circle_send" />
My java looks like this:
public void getCommand(View view)
{
//my code here
}
My question is, is there an xml tag similar to android:onClick="abc", but that works for press+holds, separately from a tap? I want to have something like this:
<ImageButton
android:id="#+id/SendButton"
android:onClick="abc"
android:onPressAndHold="xyz"
app:srcCompat="#drawable/circle_send" />
thanks for your help :)
No, sorry. In general, we do not use XML attributes for event handlers. android:onClick is the only one built into Android, and it has been obsolete for years.
If you really want to do it, you could use data binding and create a BindingAdapter to give you support for an app:onLongClick attribute. However, the syntax of the binding expression that you would use with app:onLongClick would be more complicated than what you have for android:onClick.
Here is the tutorial
https://www.youtube.com/watch?time_continue=289&v=OGfZpfn-dGI
In my android studio it doesn't recognize the button iv'e name them
android:id="#+id/top_button"
android:text="top button"
android:text="button 2"
android: android:id="#+id/button_2"
top_button.setOnClicklistner {
println(top button was clicked)
Button_2.setOnClicklistner {
println(Button)
We're missing a lot of context here that would probably help us help you.
A few things first though:
- The android:id property in your XML layout is how you name the View in question. This is most often how you will reference the View in code.
- The android:text property is the user visible text on views like TextView.
- In order for top_button to refer to your desired View in your XML layout file, it needs to be bound in code. There's a couple of normal ways of doing it findViewById() and data-binding.
I'm going to assume, for now, that the last step is what you are missing (it seems the most likely culprit at this point)... Here's a few ways to bind it:
Method 1: when using an Activity class
If you're binding top_button to your View from an Activity class, this should work:
private lateinit var top_button // replace View here with your widget's type
fun onCreate(...) {
super.onCreate(...)
setContentView(R.layout.<i>your_layout_file_name_here</i>)
top_button = findViewById(R.id.top_button)
...
}
Method 2: when using a Fragment class
If you're binding top_button to your View from a Fragment class, it's more like this:
private lateinit var top_button: View // replace View here with your widget's type
fun onCreateView(...): View {
val rootView = layoutInflater.inflate(R.layout.<i>your_layout_file_name_here</i>)
top_button = rootView.findViewById(R.id.top_button)
...
return rootView
}
Method 3: when using data-binding
I prefer this method myself, but you should Google how to setup data-binding in Android as you'll need changes in your build.gradle and all.
First, change your XML layout to be:
<layout>
<!-- your existing layout XML here -->
</layout>
Then in your Activity/Fragment, let's say your XML layout file is named activity_my_cool_screen.xml, you can do:
val binding = ActivityMyCoolScreenBinding.inflate(getLayoutInflater())
binding.topButton.setOnClickListener(...)
Notice here that the ActivityMyCoolScreenBinding class is auto-generated for you. If it turns red at first, then first verify you've accurately setup data-binding in your project, then if that's good to go, make sure to import the ActivityMyCoolScreenBinding class. If you change your XML layout's filename, then the ActivityMyCoolScreenBinding class name will change to match automatically. But, I'd recommend if you do change the name, that you use Android Studio's refactoring/renaming tools as it'll search your codebase and update it everywhere. Otherwise, you have to do it by hand (doable, but potentially tedious and error prone).
Good luck!
So I recently started messing around with Espresso in one of my existing Android projects.
Everything went pretty decently, until I came to find AutoCompleteTextView in my program. I don't seem to understand how to properly click the first thing in the autocomplete list. I'm actually not even sure which to use, onView() or onData() in this instance.
By some reasons which I don't know, AStupidNoob's solution doesn't work. So I found another one:
onView(withText("Spinner Item"))
.inRoot(RootMatchers.isPlatformPopup())
.perform(click());
The AutoCompleteTextView itself
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/textInputLayout2"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="12dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
app:layout_constraintEnd_toStartOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<AutoCompleteTextView
android:id="#+id/product"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:completionThreshold="1"
android:hint="#string/product"
android:singleLine="true"
android:textSize="16sp" />
</com.google.android.material.textfield.TextInputLayout>
I think I found a bit of a cleaner method than the accepted answer!
onData(equalTo("ITEM")).inRoot(RootMatchers.isPlatformPopup()).perform(click());
The breakdown:
onData(x) This will find the view rendering the data object matching x in the drop down. The data is provided by the Adaptor given to the AutoCompleteTextView, so it can be an object of any type that Adaptor provides, it probably won't be a View. You'll want to use the standard hamcrest core matchers for this (equalTo, instanceOf, etc...) rather than (withText, withId, etc...). It might be a pain to try and find what object this is and how to match it, but there isn't a neater way: with a lot of items in your adapter some of the views won't even be in the hierarchy yet, so onView can't work! onData will make sure to load the views that match your data. Checkout here (this what onData returns) and here (this loads the matching data)
inRoot(RootMatchers.isPlatformPopup()) So it turns out the dropdown menu is on another window than the default window your activity runs in. So we have to specify that we want to search that window. The accepted answer uses RootMatchers.withDecorView(not(is(mActivityRule.getActivity().getWindow().getDecorView()))) which seems to match any window that is not the default one.
Anyways HTH someone else.
For anyone still running into this issue, despite trying out the accepted solution above, I managed to get it working with help from a github issue I uncovered. For reference, I am using Robolectric 4.6, which I believe may be the reason why I am requiring a different solution from non-instrumented tests.
The solution I came up with (to verify an item is appearing in an AutoCompleteTextView popup is:
fun testAutoCompleteTextViewEntry() {
onView(withId(R.id.editText_search))
.perform(typeTextIntoFocusedView("x"), showDropDown())
onView(withText("xyz"))
.inRoot(RootMatchers.isPlatformPopup())
.check(matches(isDisplayed()))
}
// Somewhere else in your code
fun showDropDown(): ViewAction =
object : ViewAction {
override fun getDescription(): String = "Shows the dropdown menu of an AutoCompleteTextView"
override fun getConstraints(): Matcher<View> = allOf(
isEnabled(), isAssignableFrom(AutoCompleteTextView::class.java)
)
override fun perform(uiController: UiController, view: View) {
val autoCompleteTextView = view as AutoCompleteTextView
autoCompleteTextView.showDropDown()
uiController.loopMainThreadUntilIdle()
}
}
So i finally figured it out, thanks to this previous question:
Testing autocomplete textview using espresso tool
Ill just post my version of it for people who might use it in future.
onData(instanceOf("Whatever your arrayadapter contains".class)).inRoot(RootMatchers.withDecorView(not(is(mActivityRule.getActivity().getWindow().getDecorView())))).perform(ViewActions.click());
Following on from the answer from AStupidNoob on 28 July 2017...
To click on a specific row number of the drop-down list, you can use this:
onData(anything())
.atPosition(2)
.inRoot(RootMatchers.isPlatformPopup())
.perform(click());
To click on a specific item in a specific row number of the drop-down list, you can use this:
onData(anything())
.atPosition(2)
.inRoot(RootMatchers.isPlatformPopup())
.onChildView(withId(R.id.button_on_layout))
.perform(click());
Since the place predictions are inside a recyclerview, after typing the name of the placement, if you want to click on the first option in the predicted list, you can go with one of the RecyclerViewActions methods (actionOnItemAtPosition).
The key is to find out the id of the autocompleted places. It is set up by Google Place SDK but not yourself so might not be that straightforward to find out.
This works for my project, see if it can help:
onView(ViewMatchers.withId(com.google.android.libraries.places.R.id.places_autocomplete_list)).perform(RecyclerViewActions.actionOnItemAtPosition(0,click()));
I need to exchange data between activity and it's layout xml in Android. But I do not find a way to do this in Android. For example, views and controller in mvc pattern always has a way to exchange data between. So I am wondering is there any way to exchange data between them to should I refresh my mind and realize there is no such way?
use below code to get value from layout in your activity
String value;
EditText editText= (EditText) findViewById(R.id.editText);
value=editText.getText();
code in xml example:
<ImageView
android:id="#+id/image_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
in java class (like onCreate()):
ImageView image = (ImageView) findViewById(R.id.image_view);
Then you can do what you want with image
I believe you're unsure exactly what you're asking. If you want to exchange information, such as ID or text entered into a textfield then any good android tutorial should be-able to demonstrate this. Considering your last comment I think you're talking about GET and POST based technologies which can be done usingREST andSOAP, or both if you want.
This questions answer has a good implementation and definition of what both of these webservices are.
P.S. If this is what you're looking for then upvote that answer.
As some additional info, the "view" (XML Layout file) gets set by your activity initially on your activity's onCreate method. Right after you call it's parent method (super.onCreate()).
To maintain scope throughout the activity I tend to declare all the layout widgets that I need to the activity to interact with outside of any methods and within the class.
TextView textWelcomeMessage;
public void MyActivity(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// before calling setContentView() we have the option to change
// window features ex requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_my_activity);
// Now to set the textview
textWelcomeMessage = (TextView) findViewById(R.id.textWelcomeMessage);
// Set some data
textWelcomeMessage.setText("Hello, welcome to my activity");
}
It's not exactly like traditional php style mvc since static typing changes thing up a bit and we have to worry about scope. But the core principles can still apply as far as data abstraction and separation go. Hope this helps =)