findViewById error - Not enough information to infer type variable T. I copied java code and converted it online - android

Copied java code from diolor/swipecards (GITHUB). Converted it into kotlin with help pf online tools. It had some errors which were corrected but this last one still appears (findViewById) in the OnScroll function.
package com.example.fanatic
import android.content.Context
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.ArrayAdapter
import android.widget.Toast
import com.lorentzos.flingswipe.SwipeFlingAdapterView
class Swipe_card_activity : AppCompatActivity() {
private var al:ArrayList<String> = TODO()
private lateinit var arrayAdapter:ArrayAdapter<String>
private var i:Int = 0
override fun onCreate(savedInstanceState:Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_swipe_card_activity)
al = ArrayList()
al.add("php")
al.add("c")
al.add("python")
al.add("java")
al.add("html")
al.add("c++")
al.add("css")
al.add("javascript")
arrayAdapter = ArrayAdapter(this, R.layout.item, R.id.helloText, al)
val flingContainer : SwipeFlingAdapterView = findViewById<SwipeFlingAdapterView>(R.id.frame)
flingContainer.setAdapter(arrayAdapter)
flingContainer.setFlingListener(object: SwipeFlingAdapterView.onFlingListener {
override fun removeFirstObjectInAdapter() {
// this is the simplest way to delete an object from the Adapter (/AdapterView)
Log.d("LIST", "removed object!")
al.removeAt(0)
arrayAdapter.notifyDataSetChanged()
}
override fun onLeftCardExit(dataObject:Any) {
//Do something on the left!
//You also have access to the original object.
//If you want to use it just cast it (String) dataObject
makeToast(this#Swipe_card_activity, "Left!")
}
override fun onRightCardExit(dataObject:Any) {
makeToast(this#Swipe_card_activity, "Right!")
}
override fun onAdapterAboutToEmpty(itemsInAdapter:Int) {
// Ask for more data here
al.add("XML " + (i).toString())
arrayAdapter.notifyDataSetChanged()
Log.d("LIST", "notified")
i++
}
THE ERROR IS PRESENT HERE ON FINDVIEWBYID
IT SAYS : NOT ENOUGH INFORMATION TO INFER TYPE T.
**override fun onScroll(scrollProgressPercent:Float) {
strong textval viuw = flingContainer.selectedView
viuw.run {
findViewById(R.id.item_swipe_right_indicator).setAlpha(if (scrollProgressPercent < 0) -scrollProgressPercent else 0)
findViewById(R.id.item_swipe_left_indicator).setAlpha(if (scrollProgressPercent > 0) scrollProgressPercent else 0)**
}
}
})
// Optionally add an OnItemClickListener
flingContainer.setOnItemClickListener { itemPosition, dataObject -> makeToast(this#Swipe_card_activity, "Clicked!") }
}
fun makeToast(ctx: Context, s:String) {
Toast.makeText(ctx, s, Toast.LENGTH_SHORT).show()
}
#OnClick(R.id.right)
fun right() {
/**
* Trigger the right event manually.
*/
val flingContainer : SwipeFlingAdapterView = findViewById<SwipeFlingAdapterView>(R.id.frame)
flingContainer.getTopCardListener().selectRight()
}
#OnClick(R.id.left)
fun left() {
val flingContainer : SwipeFlingAdapterView = findViewById<SwipeFlingAdapterView>(R.id.frame)
flingContainer.getTopCardListener().selectLeft()
}
}
annotation class OnClick(val right: Int)

I believe the problem you are facing due to code conversion. Java doesn't require you to cast the view explicitly whereas Kotlin requires you to specify the type of view. You need to set the view within angular brackets like this
findViewById<View>(R.id.item_swipe_right_indicator).setAlpha(...)

The type you are getting with findViewById is potentially unconstrained so the type cannot be inferred and in Kotlin needs to be explicitly stated/casted.
If you are targeting API 26 or higher in your app you can do:
findViewById<THE_VIEW_TYPE>(R.id.item_swipe_right_indicator).setAlpha(...)
Otherwise for API 25 and lower you can do:
(findViewById(R.id.item_swipe_right_indicator) as THE_VIEW_TYPE).setAlpha(...)

Related

Kotlin random() always generates the same "random" numbers

I have created an app which should choose an image randomly from an array of images. On my Emulator Nexus 5X Android 5.1 everything works as expected. As soon as I try the same on my real device Galaxy Note 10 Lite I always get the same "random" numbers in same order. I first need to restart my phone to generate a new list of "random" numbers which is then always the same. Example: My array contains 200 elements, I open the app on my Galaxy and it chooses the following random number for the image ids: 43, 12, 176, 33, 2, 78. Then I close the app and I open the app again, now it has the exact same "random" numbers again: 43, 12, 176, 33, 2, 78. I need to restart my phone to get new random numbers, which will stay the same until I restart my phone again. On my emulator everything works fine and I get new random numbers always when I restart the app as expected.
Here is my full code of my app without array list of images:
MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val imageList = arrayOf(Image(R.drawable.image1, false),
Image(R.drawable.image2, false),
Image(R.drawable.image3, false))
val imageViewMain = findViewById<ImageView>(R.id.imageViewMain)
loadNextImage(imageViewMain, imageList)
imageViewMain.setOnClickListener {
val dialogClickListener =
DialogInterface.OnClickListener { _, which ->
when (which) {
DialogInterface.BUTTON_POSITIVE -> {
loadNextImage(imageViewMain, imageList)
}
DialogInterface.BUTTON_NEGATIVE -> { }
}
}
val builder: AlertDialog.Builder = AlertDialog.Builder(this)
builder.setMessage("Nächstes Bild?").setPositiveButton("Ja", dialogClickListener)
.setNegativeButton("Nein", dialogClickListener).show()
}
}
private fun getNextChoice(): Int {
return (0..1).random()
}
private fun getNextImage(imageList: Array<Image>): Int {
val listSize = imageList.size
var imageId: Int
do {
imageId = (0 until listSize).random()
} while (imageList[imageId].played)
imageList[imageId].played = true
return imageList[imageId].image
}
private fun loadNextImage(imageViewMain: ImageView, imageList: Array<Image>) {
val imageQuestionmark = R.drawable.questionmark
val nextChoice = getNextChoice()
if (nextChoice == 0) {
imageViewMain.load(imageQuestionmark)
} else if (nextChoice == 1) {
imageViewMain.load(getNextImage(imageList))
}
Toast.makeText(this, "Bild hat geladen", Toast.LENGTH_SHORT).show()
}
}
Image:
data class Image(
val image: Int,
var played: Boolean
)
EDIT:
I tried what cactustictacs suggested in the comment and create a simple app, once with the kotlin random function and once with the java random function. here is the code I used:
Kotlin:
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.Toast
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val buttonTest = findViewById<Button>(R.id.buttonTest)
buttonTest.setOnClickListener {
val getRandomNumber = (0..999).random()
Toast.makeText(this, getRandomNumber.toString(), Toast.LENGTH_SHORT).show()
}
}
}
Java:
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.Button;
import android.widget.Toast;
import java.util.Random;
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button buttonTest = (Button) findViewById(R.id.buttonTest);
buttonTest.setOnClickListener(v -> {
int randomNumber = new Random().nextInt(999);
Toast.makeText(this, "" + randomNumber, Toast.LENGTH_SHORT).show();
});
}
}
on Kotlin I get the same behavior as with my inital problem, doesnt matter what I do with the app (I CAN EVEN UNINSTALL AND INSTALL AGAIN) I always get the same set of numbers. On Java its working as exptected, as soon as I close the app I get a new set of numbers. So the error definetly lays in kotlin.
Maybe it helps, my Android version is 12 and my phone Galaxy Note 10 Lite.
I once had this issue too. My solution is to use a seeded random object instead of calling the function Random.nextSomething(). Then I seed currentTimeInMillis as the seed.
var randomGenerator = Random(System.currentTimeMillis())
var result = randomGenerator.nextInt(30, 50)
This is quite a terrible implementation of Kotlin defaul Random class. Java Random class tries a lot to always use a different seed on every new instance whereas Kotlin hardcoded the same seed through the whole device. How can this be a default behavior for a Random implementation. It took me quite a lot to understand it.
See Java implementation:
public Random() {
this(seedUniquifier() ^ System.nanoTime());
}
private static long seedUniquifier() {
// L'Ecuyer, "Tables of Linear Congruential Generators of
// Different Sizes and Good Lattice Structure", 1999
for (;;) {
long current = seedUniquifier.get();
long next = current * 181783497276652981L;
if (seedUniquifier.compareAndSet(current, next))
return next;
}
}
private static final AtomicLong seedUniquifier
= new AtomicLong(8682522807148012L);
Aaaaaand here comes Kotlin one:
companion object Default : Random(), Serializable {
private val defaultRandom: Random = defaultPlatformRandom()
private object Serialized : Serializable {
private const val serialVersionUID = 0L
private fun readResolve(): Any = Random
}
private fun writeReplace(): Any = Serialized
override fun nextBits(bitCount: Int): Int = defaultRandom.nextBits(bitCount)
override fun nextInt(): Int = defaultRandom.nextInt()
override fun nextInt(until: Int): Int = defaultRandom.nextInt(until)
override fun nextInt(from: Int, until: Int): Int = defaultRandom.nextInt(from, until)
defaultRandom is a singleton always initiates with same seed...
(I took this code through the Android Studio sources...)
Note: So it was a bug on kotlin version 1.7.10 and Android api less than 33-34 something. Fixed on 1.7.20...
It looks like you're calling loadNextImage() from activity's onCreate(). That means that unless the activity is destroyed, it'll never re-generate the random IDs that you want. What happens if you force-stop the activity, and then relaunch it? I would expect that you get a new set of IDs.
If I'm right, and you want a new set of IDs every time you open the activity, then the solution is to call loadNextImage() from onResume() (and if you don't want it generated every time the activity is resumed, you'll need to include some logic that decides when to regenerate those IDs)

how to write Android Custom lint rule to forbid calling specific function in all classes that extends specific type?

I want to write a custom lint rule to ban calling function states.accept() in all classes that extends BaseViewModel where states is a BehaviorRelay object.
how can I achieve something like this.
I’ve written the check using visitMethodCall but this only can check the function name and if it’s member of BehaviorRelay,
the missing part is how to check if this function is being called in children’s of BaseViewModel.
below is the part that works: using visitMethodCall but detecting the function in whole code.
override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) {
val evaluator = context.evaluator
if (evaluator.isMemberInClass(method, BEHAVIOR_RELAY)) {
if (method.name == ACCEPT_FUNCTION) {
context.report(
Incident(
issue = ISSUE,
scope = node,
location = context.getNameLocation(node),
message = "View Models implements `BaseViewModel` must not update `states`"
)
)
}
}
}
applicableSuperClasses will filter only the classes that extends passed types, in my case BaseViewModel. this function works with visitClass.
Then using AbstractUastVisitor() to visit all calls in that class and find the specific function by name, also checking if it's a member function in target type.
full working code.
override fun applicableSuperClasses(): List<String>? {
return listOf(BASE_VIEW_MODEL)
}
override fun visitClass(context: JavaContext, declaration: UClass) {
val evaluator = context.evaluator
declaration.accept(object : AbstractUastVisitor() {
override fun visitCallExpression(node: UCallExpression): Boolean {
val isRelayFunction = evaluator.isMemberInClass(
node.resolve(),
BEHAVIOR_RELAY
)
if (node.methodName == ACCEPT_FUNCTION && isRelayFunction) {
context.report(
issue = ISSUE,
scope = node,
location = context.getNameLocation(node),
message = "View Models implements `BaseViewModel` must not update `states`"
)
}
return super.visitCallExpression(node)
}
})
}

getParcelableArrayListExtra causes a different type to be set to a variable

The problem starts with getParcelableArrayListExtra doesn't support type check when we try to set it to a variable. Let me give an example as basic as I can.
A User Class.
import kotlinx.parcelize.Parcelize
import android.os.Parcelable
#Parcelize
data class UserClass(
var name: String? = null,
var text: String? = null,
var age: Int? = null
) : Parcelable
The random class which we'll try to set to the User variable.
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
#Parcelize
data class MessageClass(
val title: String?, = Constant.STRING_EMPTY
val text: String? = Constant.STRING_EMPTY
) : Parcelable
The class that fills intent
class FillIntentClass(){
//Let's say one of the developers added the MessageClass object inside our intent.
//Or BE sent the wrong type of object and I passed its value to the intent.
private fun DummyFunctionToSetIntent(){
val messageList = arraylistOf(MessageClass(title = "hello",text ="dummy text")
intent.putParcelableArrayListExtra(EXTRA_PAYMENT_OPTIONS_EXTRA, messageList)
}
}
Test class
class MyTestClass(){
// UserList variable
private var mUserList: ArrayList<UserClass>? = null
override fun onCreate(savedInstanceState: Bundle?) {
...
with(intent) {
// In this situation, mUserList became the type of ArrayList<MessageClass>
// But it shouldn't be possible. Because it must accept only ArrayList<UserClass>
// And that causes mostly crashes when the other code parts use it.
mUserList = getParcelableArrayListExtra(EXTRA_PAYMENT_OPTIONS_EXTRA)
// mUserList now pretend its like ArrayList<MessageClass>. But i set it as ArrayList<UserClass> at the top of the class.
// The best way to solve this is to type check with as?. If the type is not as expected it must return null.
// But I cannot use type check here. It gives me a "Not enough information to infer type variable T" error.
mUserList = getParcelableArrayListExtra(EXTRA_PAYMENT_OPTIONS_EXTRA) as? ArrayList<UserClass> //(compile error here on IDE)
// So I had to come out with the below solution. But I cannot say it's the best practice.
if (getParcelableArrayListExtra<UserClass>(EXTRA_PAYMENT_OPTIONS_EXTRA)
?.filterIsInstance<UserClass>()?.isNotEmpty() == true
) {
mUserList = getParcelableArrayListExtra(EXTRA_PAYMENT_OPTIONS_EXTRA)
}
}
}
}
Type check(as,as?) works with getParcelable functions as expected. But when it comes to the getParcelableArrayListExtra it just doesn't work and gives compile error as I explained above.
Do you have any knowledge of what's the best option for as, as? check? And how it's possible for mUserList to accept a different type of Array and pretend like it?
This is a mess for a few reasons:
You are coding in Kotlin, but the classes you are dealing with (Parcelable, Bundle, Intent, ArrayList) are actually Java
Generics in Java are a hack
I would split the problem into 2 parts:
Unparcel the ArrayList into ArrayList<Parcelable>
Check/convert the contents of the ArrayList<Parcelable> into the expected type
Check the API level and code accordingly:
if (Build.VERSION.SDK_INT >= 33) {
data = intent.getParcelableExtra (String name, Class<T> clazz)
}else{
data = intent.getParcelableExtra("data")
}
Also you can use these extensions for bundle and intent:
inline fun <reified T : Parcelable> Intent.parcelable(key: String): T? = when {
SDK_INT >= 33 -> getParcelableExtra(key, T::class.java)
else -> #Suppress("DEPRECATION") getParcelableExtra(key) as? T
}
inline fun <reified T : Parcelable> Bundle.parcelable(key: String): T? = when {
SDK_INT >= 33 -> getParcelable(key, T::class.java)
else -> #Suppress("DEPRECATION") getParcelable(key) as? T
}

ListView updates only in onCreate() method when using Firebase

I'm writing ToDo list, and I want ListView to display changes, when user adds new taks to the list, or removes them. I'm not sure why, but
adapter.notifyDataSetChanged()
works only when app uses onCreate() method (turning on, changing to horizontal).
I tried to put
adapter.notifyDataSetChanged() everywhere and it does not update content. Only after adding task to database (it shows on Firebase console) and changing to horizontal/restarting you can see new entery in ListView.
I also created button, that uses only adapter.notifyDataSetChanged() in onClick() method.
MainActivity.kt :
package com.example.toodoo
import android.app.AlertDialog
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.support.design.widget.FloatingActionButton
import android.util.Log
import android.view.View
import android.widget.EditText
import android.widget.ListView
import android.widget.Toast
import com.google.firebase.database.*
class MainActivity : AppCompatActivity(), ItemRowListener {
//Get Access to Firebase database, no need of any URL, Firebase
//identifies the connection via the package name of the app
lateinit var mDatabase: DatabaseReference
var toDoItemList: MutableList<ToDoItem>? = null
lateinit var adapter: ToDoItemAdapter
private var listViewItems: ListView? = null
override fun modifyItemState(itemObjectId: String, isDone: Boolean) {
val itemReference = mDatabase.child(Constants.FIREBASE_ITEM).child(itemObjectId)
itemReference.child("done").setValue(isDone);
}
//delete an item
override fun onItemDelete(itemObjectId: String) {
//get child reference in database via the ObjectID
val itemReference = mDatabase.child(Constants.FIREBASE_ITEM).child(itemObjectId)
//deletion can be done via removeValue() method
itemReference.removeValue()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//reference for FAB
val fab = findViewById<View>(R.id.fab) as FloatingActionButton
listViewItems = findViewById<View>(R.id.items_list) as ListView
//Adding click listener for FAB
fab.setOnClickListener { view ->
//Show Dialog here to add new Item
addNewItemDialog()
}
mDatabase = FirebaseDatabase.getInstance().reference
toDoItemList = mutableListOf<ToDoItem>()
adapter = ToDoItemAdapter(this, toDoItemList!!)
listViewItems!!.setAdapter(adapter)
mDatabase.orderByKey().addListenerForSingleValueEvent(itemListener)
}
private fun addNewItemDialog() {
val alert = AlertDialog.Builder(this)
val itemEditText = EditText(this)
alert.setMessage("Add New Item")
alert.setTitle("Enter To Do Item Text")
alert.setView(itemEditText)
alert.setPositiveButton("Submit") { dialog, positiveButton ->
val todoItem = ToDoItem.create()
todoItem.itemText = itemEditText.text.toString()
todoItem.done = false
//We first make a push so that a new item is made with a unique ID
val newItem = mDatabase.child(Constants.FIREBASE_ITEM).push()
todoItem.objectId = newItem.key
//then, we used the reference to set the value on that ID
newItem.setValue(todoItem)
dialog.dismiss()
Toast.makeText(this, "Item saved with ID " + todoItem.objectId, Toast.LENGTH_SHORT).show()
}
alert.show()
}
var itemListener: ValueEventListener = object : ValueEventListener {
override fun onDataChange(dataSnapshot: DataSnapshot) {
// Get Post object and use the values to update the UI
addDataToList(dataSnapshot)
}
override fun onCancelled(databaseError: DatabaseError) {
// Getting Item failed, log a message
Log.w("MainActivity", "loadItem:onCancelled", databaseError.toException())
}
}
private fun addDataToList(dataSnapshot: DataSnapshot) {
val items = dataSnapshot.children.iterator()
//Check if current database contains any collection
if (items.hasNext()) {
val toDoListindex = items.next()
val itemsIterator = toDoListindex.children.iterator()
//check if the collection has any to do items or not
while (itemsIterator.hasNext()) {
//get current item
val currentItem = itemsIterator.next()
val todoItem = ToDoItem.create()
//get current data in a map
val map = currentItem.getValue() as HashMap<String, Any>
//key will return Firebase ID
todoItem.objectId = currentItem.key
todoItem.done = map.get("done") as Boolean?
todoItem.itemText = map.get("itemText") as String?
toDoItemList!!.add(todoItem);
}
}
//alert adapter that has changed
adapter.notifyDataSetChanged()
}
fun onClick(view: View){
adapter.notifyDataSetChanged()
}
}
I think it might be also a problem connected with syncing Firebase data with ListView, but I'm using it first time and I cannot resolve that problem.
It's my first time with that database, so mabe I'm missing something out.
You're adding a listener for the data with:
mDatabase.orderByKey().addListenerForSingleValueEvent(itemListener)
Since you're using addListenerForSingleValueEvent, this only listens for the current data, and then removes the listener. So after loading the current data, you're no longer listening for changes.
To continue to listen for the initial data and changes afterwards, use:
mDatabase.orderByKey().addValueEventListener(itemListener)
Note that you might want to empty toDoItemList in addDataToList, as you'll otherwise be adding all existing items again and again whenever there's a change.
Or alternatively use addChildEventListener, which gives you more granular information on what has changed about the child nodes, so that you perform fine-grained updates to the adapter.

Required lifecycle owner found Activity

I am using android library androidx.appcompat:appcompat:1.0.2. Working on a sample of codelabs work manager. I need to get live data from ViewModel and I am using this
mViewModel!!.getOutputWorkInfo()?.observe(this, Observer<List<WorkInfo>> {
})
but this variable shows error -
Type mismatch. Required:Lifecycle Owner. Found:BlurActivity
I googled all says no need to extend lifecycle owner, by default appcompact activity implements lifecycle owner.
And I also worked this in another project, no issues found. I don't know why I am getting this error in this project.
`
import android.os.Bundle
import android.view.View
import android.widget.Button
import android.widget.ImageView
import android.widget.ProgressBar
import android.widget.RadioGroup
import com.bumptech.glide.Glide
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import androidx.work.WorkInfo
class BlurActivity : AppCompatActivity() {
private var mViewModel: BlurViewModel? = null
private var mImageView: ImageView? = null
private var mProgressBar: ProgressBar? = null
private var mGoButton: Button? = null
private var mOutputButton: Button? = null
private var mCancelButton: Button? = null
/**
* Get the blur level from the radio button as an integer
* #return Integer representing the amount of times to blur the image
*/
private val blurLevel: Int
get() {
val radioGroup = findViewById<RadioGroup>(R.id.radio_blur_group)
return when (radioGroup.checkedRadioButtonId) {
R.id.radio_blur_lv_1 -> 1
R.id.radio_blur_lv_2 -> 2
R.id.radio_blur_lv_3 -> 3
else -> 1
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_blur)
// Get the ViewModel
mViewModel = ViewModelProviders.of(this).get(BlurViewModel::class.java)
// Get all of the Views
mImageView = findViewById(R.id.image_view)
mProgressBar = findViewById(R.id.progress_bar)
mGoButton = findViewById(R.id.go_button)
mOutputButton = findViewById(R.id.see_file_button)
mCancelButton = findViewById(R.id.cancel_button)
// Image uri should be stored in the ViewModel; put it there then display
val intent = intent
val imageUriExtra = intent.getStringExtra(Constants.KEY_IMAGE_URI)
mViewModel!!.setImageUri(imageUriExtra)
if (mViewModel!!.imageUri != null) {
Glide.with(this).load(mViewModel!!.imageUri).into(mImageView!!)
}
mViewModel!!.getOutputWorkInfo()?.observe(this, Observer<List<WorkInfo>> {
// If there are no matching work info, do nothing
if (it == null || it.isEmpty()) return#Observer
// We only care about the first output status.
// Every continuation has only one worker tagged TAG_OUTPUT
val workInfo = it[0]
val finished = workInfo.state.isFinished
if (!finished) showWorkInProgress() else showWorkFinished()
})
// Setup blur image file button
mGoButton!!.setOnClickListener { view -> mViewModel!!.applyBlur(blurLevel) }
}
/**
* Shows and hides views for when the Activity is processing an image
*/
private fun showWorkInProgress() {
mProgressBar!!.visibility = View.VISIBLE
mCancelButton!!.visibility = View.VISIBLE
mGoButton!!.visibility = View.GONE
mOutputButton!!.visibility = View.GONE
}
/**
* Shows and hides views for when the Activity is done processing an image
*/
private fun showWorkFinished() {
mProgressBar!!.visibility = View.GONE
mCancelButton!!.visibility = View.GONE
mGoButton!!.visibility = View.VISIBLE
}
}
`
Same problem here, so I had to update my androidx.appcompat dependency, like below:
implementation 'androidx.appcompat:appcompat:1.1.0-alpha04'
no need to implement LifecycleOwner (as its implemented by default now {as mentioned by Darthcow})
After implementing LifeCycleOwner in Main Activity, error goes and work properly
Updated
Use latest androidx lib and u don't need to implement LifecycleOwner. Now it is implemented by default in ComponentActivity which AppcompatActivity implements
This issue occurs when there is mismatch between appcompat and Lifecycle dependency.
Either use this set of dependencies:
implementation "androidx.lifecycle:lifecycle-extensions:$lifecycle_version
implementation 'androidx.appcompat:appcompat:1.1.0-alpha04'
Or:
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation "android.arch.lifecycle:extensions:$lifecycle_version"
I got this error while trying to parse a context as a Life cycle owner and a helpful way to solve it is using a type cast
context as LifecycleOwner

Categories

Resources