Using ContextCompat.getColor in fragment Kotlin? - android

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));

Related

What does "activity?." mean in Kotlin?

I am trying to use a code snippet from the official android documentation (https://developer.android.com/training/printing/photos#kotlin) which is the doPhotoPrint() function in the code that I have attached, in order to learn how to use the PrintHelper class in Kotlin and Android Studio. See the attached image of the the code snippet:
The problem is that when I put the code in Main Activity in my test app, it keeps showing "activity?." as red. Why is this the case and how can I get the code to work so that is provides the user with the option to print? Thanks
The code you linked is just a general how to use a library function snippet - it's not put in any context, but we can assume it's probably written with a Fragment in mind. Fragments have a getActivity() method that returns the Activity it's currently attached to (or null if it's not)
Kotlin allows you to access getter and setter functions from Java code as if they were properties - so basically, instead of having to do value = getThing()
and setThing(newValue) you can treat it like a variable: value = thing, thing = newValue etc. So when you access the activity property in this code, it's really calling getActivity(). And because the result can be null, you use the ? to null-check it before trying to do anything with it.
Really what that snippet is saying is, this code needs access to a Context, and it's using an Activity as one in the example. If you have a Fragment, you can just drop this code right in. If you're in an Activity though, then you obviously don't need to get one - this is your Activity! And you don't need to null-check it either of course. (And there's no activity property or getActivity() method to access, which is why it's showing up red and unrecognised)
So you can just replace that stuff and the checking code around it with:
private fun doPhotoPrint() {
// using 'this' to pass the current activity as the context
val printHelper = PrintHelper(this).apply {
scaleMode = PrintHelper.SCALE_MODE_FIT
}
val bitmap = BitmapFactory.decodeResource(resources, R.drawable.droids)
printHelper.printBitmap("droids.jpg - test print", bitmap)
}
It is showing red because you have not declared the nullable object activity anyway before you use it

Android Kotlin: Smart cast to 'TextView' is impossible, because 'x' is a property that has open or custom getter

I use findViewById to get references to views in a custom DialogClass outside the view hierarchy. Since I want these references throughout the dialog class, and since they are not available until the call to setContentView, I use lazy field initialization in the dialog class definition:
private val balanceView : TextView? by lazy { dialog?.findViewById(R.id.balanceTextView)}
Later, in a separate function that runs after the call to setContentView, I have two commands related to balanceView:
private fun setupBalance(){
balanceView!!.visibility = View.VISIBLE
balanceView.text = presentation.balance
}
I expected the second command to compile since we are ensuring balanceView is not null in the first command. However, the compiler underlines the second command with this message:
Smart cast to 'TextView' is impossible, because 'balanceView' is a property that has open or custom getter
I was wondering how to interpret this message - to my knowledge the lazy keyword doesn't make a variable open.
The use of a property delegate like lazy means it has a custom getter. A custom getter prevents the compiler from being able to ensure that the value returned by the property will be the same in your two consecutive calls, so it cannot smart-cast.
Since balanceView is nullable, you shouldn't be using !! either, or your app will crash when balanceView is null. The correct way to write your function (if you don't know if balanceView is currently null) would be like this:
private fun setupBalance(){
balanceView?.apply {
visibility = View.VISIBLE
text = presentation.balance
}
}
If there's no chance of it being null, don't use a nullable property, and then you won't have to worry about null-safe calls and smart-casting. But you seem to also have a nullable dialog that it is dependent on. I don't know what's going on higher-up-stream, so I can't help with that.

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 create variable in Kotlin without initialization?

This is simple question. In Java you can create String variable or couple of variables without adding any value to it. This is used at start of the class before onCreate() is called in Activity. I've used lateinit property in Kotlin to achieve that, but now I have a problem with changing visibility of RecyclerView. It will throw exception "lateinit property recyclerView has not been initialized".
Is there any way how to know if property is initialized? This is called at start of the parent activity in Fragment (hide recyclerView and show ProgressBar till data are binded to recyclerView).
In Java you can create String variable or couple of variables without adding any value to it
Actually in that case it is implicitly declared null. Kotlin does not do that, because of its nullability mechanism. You must explicitly declare a variable nullable to allow null:
var str: String // does not work
var str: String? // does not work
var str: String? = null // works
Also see this answer.
Your other option indeed is to mark it lateinit:
lateinit var str: String // works
If you need to make a check to see if it is initialized before using it, you use
if (::str.isInitialized)
But really you should avoid this check and just make sure it is initialized before using it.
If you need to get your UI element in Kotlin, you do not need to create variable and initialise it by using findViewById anymore (though you can). Use kotlin view binding, which works pretty well.
https://kotlinlang.org/docs/tutorials/android-plugin.html#view-binding

Android DataBinding where to get context?

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)

Categories

Resources