Android DataBinding where to get context? - android

I have TextView for showing time. I want to use Android's DataBinding plugin.
For formatting time I am using DateUtils.formatDateTime(context, int, int) method which takes Context instance. Is it possible to get context include element? Or do I have to use old school way?
Thanks

Also you can do something like this in your view using the current view context as parameter.
...
android:text="#{yourModelHere.yourModelMethodHere(context)}"
...

Thought I should answer instead of putting in a comment. You'll have more options when rc2 is released. In rc1, you can pass the context in a variable to the Binding, then pass it as a parameter to the method. Alternatively, you can create a custom attribute for data binding:
#BindingAdapter({"timeMillis", "dateFlags"})
public static void setDateText(TextView view, int timeMillis, int dateFlags) {
view.setText(DateUtils.formatDateTime(view.getContext(), timeMillis,
dateFlags));
}
And then use it in your TextView:
<TextView ... app:timeMillis="#{timeVar}" app:dateFlags="#{dateFlags}"/>

A special variable named context is generated for use in binding
expressions as needed. The value for context is the Context from the
root View's getContext(). The context variable will be overridden by
an explicit variable declaration with that name.
In other words, every time you need to pass the context just use "context" as in #{Object.method(context)}.

To used string resources use this
this.yourView.getRoot().getResources().getString(R.string.your_string)

Related

Using ContextCompat.getColor in fragment Kotlin?

I have a check box in fragment and trying to set text color on it using ContextCompat.getColor
the code
optionCb.setTextColor(ContextCompat.getColor(activity,android.R.color.white));
It shows error
required : Context
Found : fragmentactivity
Even used
optionCb.setTextColor(ContextCompat.getColor(activity.applicationContext,android.R.color.white));
Still shows error
What should be the context object here?
was able to solve by using requireActivity()
optionCb.setTextColor(ContextCompat.getColor(requireActivity(), android.R.color.black));
Try to use requiredActivity or requiredContext instead of activity
The ContextCompat.getColor() accepts two arguments -- the first of which is a non-null Context object.
If you're writing code in Kotlin, Android Studio is likely complaining about the Context object you're passing to getColor() being nullable. The context and activity parameters available to Fragments are nullable in Android.
As others have already mentioned, you can use the requireContext() function. However, while this will satisfy Android Studio, it should be used with caution since it will throw an IllegalStateException if the Fragment's context is null (the context of a Fragment is not always available).
My recommendation would be to set the text color in your xml layout file if at all possible. If you have to do it programmatically, the safest way is to handle the null case:
context
?.let { ContextCompat.getColor(it, android.R.color.white) }
?.also { optionsCb.setTextColor(it) }
optionCb.setTextColor(ContextCompat.getColor(getContext(),android.R.color.white));

Getting the context in a BrowseSupportFragment

I migrated recently from BrowseFragment to BrowseSupportFragment in Kotlin for an Android TV app.
In the onActivityCreated I set some properties which rely on getting the color. To get the colors I use:
ContextCompat.getColor(context, R.color.fastlane_background);
The issue here is that context is nullable and getColor doesn't accept that.
Every time I need the context, do I need to do something like this:
val ctx = context ?: return
ContextCompat.getColor(ctx, R.color.fastlane_background);
Is this the recommended solution, are there better ways?
Use requireContext() to get a non-null Context associated with your Fragment.

How to cast view elements in kotlin? [duplicate]

I'm trying to build android application using Kotlin for the first time.
I want to declare on some buttons outside the OnCreate method and i can initialize them only Inside this function with findViewById.
Can i declare in simple and clean code like in java?
private Button btnProceed;
Because when converting it to Kotlin it look like:
private var btnProceed: Button? = null
And then when initialize OnClick function need to add ! sign:
btnProceed!!.setOnClickListener
What is the right and cleanest way?
This is a good use case for lateinit. Marking a property lateinit allows you to make it non nullable, but not assign it a value at the time that your Activity's constructor is called. It's there precisely for classes like Activities, when initialization happens in a separate initializer method, later than the constructor being run (in this case, onCreate).
private lateinit var btnProceed: Button
If the property is read before a real value is assigned to it, it will throw an exception at runtime - by using lateinit, you're taking the responsibility for initializing it before you access it for the first time.
Otherwise, if you want the compiler to guarantee safe access for you, you can make the Button nullable as the converter does by default. Instead of the unsafe !! operator though, which the converter often uses, you should use the safe call operator where you access the property:
btnProceed?.setOnClickListener { ... }
This will make a regular call if btnProceed is a non-null value, and do nothing otherwise.
On a final note, you can check out Kotlin Android Extensions, which eliminates the need to create properties for your Views altogether, if it works for your project.
Last edit (for now): you should also look at using lazy as described in the other answers. Being lazy is cool.
Instead of using lateinit, you can also do lazy initialization:
private val button by lazy {
findViewById(R.id.button) as Button
}
The first time you access the button property, it will execute the block once and use the result for future calls. In onCreate for example, you can now directly access it:
fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(bundle)
setContentView(R.layout.my_view)
button.setOnClickListener { ... }
}
You can do it with lateinit as #zsmb13 suggest BUT this has the disadvantage that your views will be variable instead of final. If you want them to be final you can use the lazy property delegation
By using lazy you can declare how the value will be initialized when you first try to access it so by declaring
private val btnProceed: Button by lazy {
findViewById(R.id.yourID)
}
Whenever you access your btnProceed you will have your activity (this example assume you're using an activity) loaded so you can use that method

Getting context from getContext() or from constructor as a field

Let's use custom or extending View as an example.
Is it more effective to save Context parameter from constructor as a field, than calling getContext() everywhere (supposing there are, let's say, 10 or more places where it is needed)?
Instead of using getContext() every where, it is better to pass current context as argument in constructor where you wanna to use.
View#getContext() is
class View {
protected Context mContext;
public final Context getContext() {
return mContext;
}
}
and a locally cached implementation:
class X {
private final Context mLocalContext;
public X(Context ctx) {
mLocalContext = ctx;
}
}
Now there is a very small difference when you use mLocalContext instead of getContext(). The JVM can get to the required reference of the context object without having to execute the method (which takes a tiny bit of extra time). That call can't be optimized away since View#mContext is mutable (can change). In the local example it can assume that mLocalContext can't change and optimize the code a little better. [Note: I am not 100% sure about what optimizations are / can be done]
The difference might be measurable if you use the context a lot but in this case it does not matter much. It's still a good idea to cache Objects locally if you need them often. Especially when their (re)construction takes time (e.g. when getContext() would create a new Context() or so).
It looks like, from the source code, the View's constructor stores the context parameter and that's what getContext() returns:
http://grepcode.com/file/repository.grepcode.com/java/ext/com.google.android/android/2.2_r1.1/android/view/View.java#View.getContext%28%29
So, my instinct would be that storing the parameter yourself would be redundant, since the super class is already doing it for you.

How to use Android's getString() without violating basic OOD principles?

I need to use getString() from most of the modules in my application.
But for some strange reason, it is tied to Application or Context, so that means I need to pass to each and every class in my application, the Application reference as a parameter.
This clearly violates one of the most basic principles of object oriented design.
Is there a way around this?
The 'strange reason' is that since the string resources are tied to your application, there is no way to access them without some sort of handle to it (the Context). If most of your classes that are not activities need to access string resources, you might want to rethink your design a bit. A simple way to not depend on a Context is to load the strings and pass them to your classes in the constructor.
Yes, there is a workaround - if you happen to (or can) pass a View (any View-derived class) to the constructor, and you assign it to a data member, then you can access the string resources from anywhere in your class:
String str_via_res = yourView.getContext().getString(R.string.str_via_res);
Otherwise, you will have to pass a Context to every class that needs access to these string resources.
you can extend android.app.Application class to create a static method to pass on the context across all classes in your application.
Refer : PhoneApp.java

Categories

Resources