Beginner here.
I'm trying to implement a spinner with images using this guide;
https://dzone.com/articles/custom-spinner-for-android-application
I have it working correctly if implemented in my MainActivity.
The issues arise when I try to implement this within my fragment "Fragment1".
The code to initialize the spinner is as follows :
moodSpinner.adapter = MoodArrayAdapter(this, listOf(
Mood(R.drawable.angry, "Angry"),
Mood(R.drawable.happy, "Happy"),
Mood(R.drawable.playful, "Playful"),
Mood(R.drawable.wondering, "Wondering")
)
)
If that code is in my mainactivity.kt, and the spinner object with id moodSpinner in activity_main.xml, everything works fine. If I move the code to my fragment.kt, and the spinner into the fragment.xml, it fails.
I suspect the issue is related to 'this' being used as the context.
"java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.Spinner.setAdapter(android.widget.SpinnerAdapter)' on a null object reference"
I tried changing 'this' to 'this.requireActivity()' but no change.
Thanks.
Fixed. To those suffering the same problem of context within a fragment, I solved it by doing two things.
First, I placed the above code into the 'onViewCreated' method, and not in the 'onCreate' method.
Secondly, I replaced 'this' with 'requireActivity().baseContext' to pass the correct context to the ArrayAdapter.
Revised code looks like ;
moodSpinner.adapter = MoodArrayAdapter(requireActivity().baseContext, listOf(
Mood(R.drawable.angry, "Angry"),
Mood(R.drawable.happy, "Happy"),
Mood(R.drawable.playful, "Playful"),
Mood(R.drawable.wondering, "Wondering")
)
Related
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
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.
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));
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
New to Kotlin.
I am trying to create a activity with a member variable holding button object, but compiler gives me error when I try to do findViewById
I tried two ways for doing this but none works.
Note: I am not using Android extension
When you declare your property like this:
var btn = null
... its type gets inferred to Nothing?, which makes it so that nothing other than null can ever be assigned to it. What you should do instead is the following:
var btn: Button? = null
You might also want to look into declaring your Views in different ways.