Kotlin : getResources() on a null object reference - android

I have create array of color like this in kotlin
private var colorArray = arrayOf(
ContextCompat.getColor(this, R.color.text_yellow),
ContextCompat.getColor(this, R.color.text_green),
ContextCompat.getColor(this, R.color.text_red)
)
and when i want to get color from colorArray through index
var color = colorArray[0]
I am getting crash on index 0,
Attempt to invoke virtual method 'android.content.res.Resources
android.content.Context.getResources()' on a null object reference
I don't know where i am wrong
If i write ContextCompat.getColor(this, R.color.text_yellow) this is fine no crash but through array index it give me error

You're declaring this as a field:
private var colorArray = arrayOf(
ContextCompat.getColor(this, R.color.text_yellow),
ContextCompat.getColor(this, R.color.text_green),
ContextCompat.getColor(this, R.color.text_red)
)
The issue is that your context (the this parameter) is null before your onCreate() method is called. And when you declare something as a field, it tries to initialise it immediately, before any method calls. (So before the onCreate is called)
What you can do is initialise this field with a lazy call.
This means that it is actually only initialised when it is first used. So if you're calling the index AFTER your onCreate, the context won't be null and it should work fine.
Change it to:
private var colorArray by lazy { arrayOf(
ContextCompat.getColor(this, R.color.text_yellow),
ContextCompat.getColor(this, R.color.text_green),
ContextCompat.getColor(this, R.color.text_red)
) }

You are using this as Context globally which is not initialized yet .
This is why you are getting this error cause Context is null.
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.Resources android.content.Context.getResources()
The Right way to do this access the context inside onCreate(). You can try something like below:-
class Dx :AppCompatActivity(){
private lateinit var colorArray:Array<Int>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_dx)
colorArray = arrayOf(
ContextCompat.getColor(this, R.color.colorAccent),
ContextCompat.getColor(this, R.color.colorPrimary),
ContextCompat.getColor(this, R.color.colorPrimaryDark)
)
val btn=findViewById<Button>(R.id.b1)
btn.setBackgroundColor(colorArray[0])
}
}

Related

Macrobenchmark is failing due to null result in Google sample

I am trying to learn Jetpack benchmark. By reviewing this google sample : https://github.com/android/performance-samples/tree/main/MacrobenchmarkSample
One of classes includes following method :
private fun MacrobenchmarkScope.clickOnId(resourceId: String) {
val selector = By.res(packageName, resourceId)
if (!device.wait(Until.hasObject(selector), 2_500)) {
fail("Did not find object with id $resourceId")
}
device
.findObject(selector)
.click()
// Chill to ensure we capture the end of the click span in the trace.
Thread.sleep(100)
}
And it has been called like : clickOnId("launchRecyclerActivity")
The string is a resource :
<string name="launchRecyclerActivity">RecyclerView</string>
And RecyclerView is an item in MainActivity :
BenchmarkActivityButton(name = "RecyclerView") {
launchActivityWithTrace<NonExportedRecyclerActivity>()
}
#Composable
fun BenchmarkActivityButton(name: String, onClick: () -> Unit) {
TextButton(
modifier = Modifier.padding(8.dp),
onClick = onClick,
border = BorderStroke(1.dp, MaterialTheme.colors.primary)
) {
Text(name)
}
}
The problem is this line returns null : val selector = By.res(packageName, resourceId)
And therefore I receive following exception :
java.lang.NullPointerException: Attempt to invoke virtual method 'void androidx.test.uiautomator.UiObject2.click()' on a null object reference
at com.example.macrobenchmark.clickslatency.ClickLatencyBenchmark.clickOnId(ClickLatencyBenchmark.kt:189)
at com.example.macrobenchmark.clickslatency.ClickLatencyBenchmark.access$clickOnId(ClickLatencyBenchmark.kt:40)
at com.example.macrobenchmark.clickslatency.ClickLatencyBenchmark$simpleViewClick$2.invoke(ClickLatencyBenchmark.kt:64)
at com.example.macrobenchmark.clickslatency.ClickLatencyBenchmark$simpleViewClick$2.invoke(ClickLatencyBenchmark.kt:51)
at androidx.benchmark.macro.MacrobenchmarkKt$macrobenchmark$measurements$1$tracePath$1.invoke(Macrobenchmark.kt:193)
at androidx.benchmark.macro.MacrobenchmarkKt$macrobenchmark$measurements$1$tracePath$1.invoke(Macrobenchmark.kt:167)
at androidx.benchmark.perfetto.PerfettoCaptureWrapper.record(PerfettoCaptureWrapper.kt:90)
at androidx.benchmark.macro.MacrobenchmarkKt.macrobenchmark(Macrobenchmark.kt:167)
at androidx.benchmark.macro.MacrobenchmarkKt.macrobenchmarkWithStartupMode(Macrobenchmark.kt:301)
at androidx.benchmark.macro.junit4.MacrobenchmarkRule.measureRepeated(MacrobenchmarkRule.kt:106)
at com.example.macrobenchmark.clickslatency.ClickLatencyBenchmark.simpleViewClick(ClickLatencyBenchmark.kt:51)
How it can be resolved?

java.lang.NullPointerException: Gson().fromJson(placeJson, Place::class.java) must not be null

I used the following function in my code:
private fun sharedPreferences() = context.getSharedPreferences(
"sunny_weather",
Context.MODE_PRIVATE
)
fun getSavedPlace(): Place {
val placeJson = sharedPreferences().getString("place","")
return Gson().fromJson(placeJson, Place::class.java)
}
but the following error appear
java.lang.NullPointerException: Gson().fromJson(placeJson, Place::class.java) must not be null
i had found a similar question and according to asker's meaning, although his code isn`t similar to mine, he also write the getString function but set the second parameter to null. so his program went wrong, and after changing, his program ran well. but i had set the parameter to "", not null, but it's wrong.
Use "{}" for the default value:
fun getSavedPlace(): Place {
val placeJson = sharedPreferences().getString("place","{}")
return Gson().fromJson(placeJson, Place::class.java)
}

How to reach resources inside a method within RecyclerView's class

I have a "insert_data()" function in same class with RecyleView's adapter class. With this method, I'll populate an array.
That method works after clicking an "setOnClickListener".
So onBindViewHolder method's codes are below,
override fun onBindViewHolder(holder: adsViewHolder, position: Int) {
holder.itemView.txt_ads.text = category[position]
holder.itemView.setOnClickListener(){
if (holder.itemView.txt_ads.text.contains("Estate")){
var arrayID = holder.itemView.resources.getIdentifier("EstateCategory","array", holder.itemView.context.packageName )
var category_arraylist = ArrayList<String>(9)
i**nsert_data(category_arraylist,arrayID)**
var mylinearlayout = LinearLayoutManager(holder.itemView.context,LinearLayoutManager.VERTICAL, false)
holder.itemView.myAdsRecycleView.layoutManager = mylinearlayout
var myadapter = adsRecyleAdapter(category_arraylist)
holder.itemView.myAdsRecycleView.adapter = myadapter
}
}
}
and "insert_data()" method's codes are below,
fun insert_data(categoryArraylist: ArrayList<String>,arrayID:Int) {
var obje = AppCompatActivity()
var Category = obje.resources.getStringArray(R.array.EstateCategory)
for (i in 0..obje.resources.getStringArray(R.array.realEstateCategory).size -1 ){
categoryArraylist.add(Category[i])
}
}
Wtihin this method, I cant reach "resources". To solve this, I created and object from AppCombatActivity class. But it gives error like below at "var obje = AppCompatActivity()" line.
java.lang.NullPointerException: Attempt to invoke virtual method 'android.content.res.Resources android.content.Context.getResources()' on a null object reference
How can I reach resources with this method? "this", or "context" doesn't works.
Pass in the itemView into the insertData method and call the resources the same way you're calling them in other places
insertData(itemView: View) {// along with your other parameters
itemView.resources.getStringArray(..)
}

property getter or setter expected

I want to use a bitmap var in a class. It makes 'property getter or setter expected' error. What is the problem?
The error shows around 'bmp? : Bitmap = null'.
How can I solve the problem?
And I don't understand why I must use getter or setter for private properties in a class.
class MyView(context: Context?) : View(context) {
private var bmp? : Bitmap = null
init {
bmp = BitmapFactory.decodeResource(resources, R.mipmap.ic_launcher)
}
override fun onDraw(canvas: Canvas?) {
super.onDraw(canvas)
canvas?.drawColor(Color.BLUE)
canvas?.drawBitmap(bmp,10f,10f, null)
}
}
Issue is that you're going to create Nullable object using safe call operator, but your syntax is wrong. Inspite of placing ? at variable, you'll need to put it at Reference type.
Check correct syntax :
private var bmp : Bitmap? = null
And then you can access this variable with safe call operator like below :
bmp?.someMethodCall() // This line will never throw you null pointer exception because of ? (Safe call operator)
Check out more here.
Please try below line
lateinit var bmp : Bitmap

How do I initialize a collection value for a MutableLiveData object?

class Foo : ViewModel() {
val bars: MutableLiveData<ArrayList<Bar>> = MutableLiveData()
get() {
if(field.value == null) {
field.setValue(ArrayList()) // NullPointerException
}
}
}
class FooTest(){
#Test fun itShouldNotBlowUp() {
Foo() //nullPointerException
}
}
I don't understand how to initialize the value of a MutableLiveData object. I've tried to lazily initialize it via the getter and with an init block. Both approaches throw a null pointer when setting the value. bars is not null however.
Here is the stacktrace:
java.lang.NullPointerException
at android.arch.core.executor.DefaultTaskExecutor.isMainThread(DefaultTaskExecutor.java:58)
at android.arch.core.executor.ArchTaskExecutor.isMainThread(ArchTaskExecutor.java:116)
at android.arch.lifecycle.LiveData.assertMainThread(LiveData.java:434)
at android.arch.lifecycle.LiveData.setValue(LiveData.java:279)
at android.arch.lifecycle.MutableLiveData.setValue(MutableLiveData.java:33)
at org.Foo.<init>(Foo.kt:10)
at org.FooTest.ShouldNotBlowUp(FooTest.kt:3)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
How do I initialize the ArrayList and set it as the value of bars?
Maybe the reason is that you are trying to run this in the test. Your sample fails in DefaultTaskExecutor.isMainThread(), that looks like this:
public boolean isMainThread() {
return Looper.getMainLooper().getThread() == Thread.currentThread();
}
So Looper.getMainLooper() returns null in the test environment.
And also, have you tried to initialize property via 'lazy' delegate?
val bars: MutableLiveData<List<Bar>> by lazy {
MutableLiveData<List<Bar>>().apply {
value = emptyList()
}
}
That works fine in my case and feels more idiomatic
The answer to the question is: if you want to give it an empty value clearly, but the variable is not null and you can at least use it without breaking the program.
to create a variable:
val myVariable = MutableLiveData<ArrayList<String>>()
Well, now you only have to pass the constructor of the empty list within the type parentheses so that your variable does not remain with a Null value.
val myVariable = MutableLiveData<ArrayList<String>>(arrayListOf())
I know it's an old question but in case it can help someone, it helped me discover this ;)

Categories

Resources