I am developing an app where there are different user interfaces depending on what kind of client u are. I wanted to create different Bottom Navigations depending on what type of user is logged in. The if- clause works, so the Log tells me the correct user type but I am getting a fatal exception because it tells me that the id of the second bottom navigation is not existent, but like the first one works. I now it's not the cleanest way to do so but I couldn't find a different way. Here is my code:
This is the main.kt
class MainActivity : AppCompatActivity() {
lateinit var homeFragment: HomeFragment
lateinit var mapsFragment: MapsFragment
lateinit var profil: Profil
lateinit var chat: Chat
lateinit var homeFoto: HomeFoto
val COARSE_LOCATION_RQ = 101
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val mAuth = FirebaseAuth.getInstance()
lateinit var mDatabase : DatabaseReference
val user = mAuth.currentUser
val uid = user!!.uid
var snapshot: DataSnapshot
var anwender = "Suchender"
mDatabase = FirebaseDatabase.getInstance().getReference("User").child(uid)
//Log.e("keyKey",mDatabase.database.getReference("Anwendertyp").child(anwender).toString())
mDatabase!!.addValueEventListener(object : ValueEventListener {
override fun onDataChange(snapshot: DataSnapshot) {
if (snapshot.exists() && snapshot.child("Anwendertyp").value.toString() == "Suchender" ){
Log.e("keyKey",snapshot.child("Anwendertyp").value.toString())
//findNavController(R.id.suchenderNavigation)
var bottomnav = findViewById<BottomNavigationView>(R.id.BottomNavMenu)
bottomnav.setOnNavigationItemSelectedListener { item ->
when (item.itemId) {
R.id.navigation_home -> {
homeFragment = HomeFragment()
supportFragmentManager
.beginTransaction()
.replace(R.id.frameLayout, homeFragment)
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.commit()
}
R.id.mapsFragment -> {
mapsFragment = MapsFragment()
supportFragmentManager
.beginTransaction()
.replace(R.id.frameLayout, mapsFragment)
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.commit()
}
R.id.navigation_notifications -> {
profil = Profil()
supportFragmentManager
.beginTransaction()
.replace(R.id.frameLayout, profil)
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.commit()
}
}
true
}
}
else{
setContentView(R.layout.startseite_fotografvideograf)
Log.e("key",snapshot.child("Anwendertyp").value.toString())
// Navigation.findNavController(HomeFoto().requireActivity(), R.id.navigation_home_fotografvideograf)
//findNavController(R.id.fotografNavigation)
//This is the variable that triggers the fatal exception
var bottomn = findViewById<BottomNavigationView>(R.id.bottomNavFoto)
Log.e("heyo", bottomn.toString())
bottomn.setOnNavigationItemSelectedListener { item ->
when (item.itemId) {
R.id.navigation_home_fotografvideograf -> {
homeFoto = HomeFoto()
supportFragmentManager
.beginTransaction()
.replace(R.id.frameLayout, homeFoto)
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.commit()
}
R.id.navigation_notifications -> {
profil = Profil()
supportFragmentManager
.beginTransaction()
.replace(R.id.frameLayout, profil)
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.commit()
}
R.id.chatchat -> {
chat = Chat()
supportFragmentManager
.beginTransaction()
.replace(R.id.frameLayout, chat)
.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
.commit()
}
}
true
}
}
}
override fun onCancelled(error: DatabaseError) {
}
})
}
This is the main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#E8E8E8">
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottomNavigation"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_margin="30dp"
android:background="#drawable/buttom_bg"
android:elevation="2dp"
app:itemIconSize="30dp"
app:itemIconTint="#drawable/item_selector"
app:itemRippleColor="#android:color/transparent"
app:labelVisibilityMode="unlabeled"
app:menu="#menu/bottom_nav_menu" />
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottomNavFoto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_margin="30dp"
android:background="#drawable/buttom_bg"
android:elevation="2dp"
app:itemIconSize="30dp"
app:itemIconTint="#drawable/item_selector"
app:itemRippleColor="#android:color/transparent"
app:labelVisibilityMode="unlabeled"
app:menu="#menu/bottom_nav_fotograf" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
And here is the xml of the second bottom navigation:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/BottomNavFotograf"
>
<item
android:id="#+id/navigation_home_fotografvideograf"
android:icon="#drawable/ic_home_black_24dp"
android:title="#string/title_home" />
<item
android:id="#+id/navigation_notifications"
android:icon="#drawable/ic_baseline_person_24"
android:title="#string/profil" />
<item
android:id="#+id/chatchat"
android:icon="#drawable/ic_chat"
android:title="Chat" />
</menu>
Update
This is the FATAL EXCEPTION I'm getting:
E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.discoverme, PID: 4430 java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String com.google.android.material.bottomnavigation.BottomNavigationView.toString()' on a null object reference at com.example.discoverme.MainActivity$onCreate$1.onDataChange(MainActivity.kt:114) at com.google.firebase.database.core.ValueEventRegistration.fireEvent(ValueEventRegistration.java:75) at com.google.firebase.database.core.view.DataEvent.fire(DataEvent.java:63) at – Luzie Ewert 19 hours ago Delete
com.google.firebase.database.core.view.EventRaiser$1.run(EventRaiser.java:55) at android.os.Handler.handleCallback(Handler.java:751) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:154)
like, it's so confusing. I know it has to be something with the id's or the fact that there can not be two bottom navigations in one layout but I can't help myself any other way and I can't tell where the first id of the first bottom navigation is coming from, because it is nowhere declared and if I'm using one of the id's I used in the xml's the app crashes and I am getting trhe same fatal (axception that tells me the reference is on a null object.
okay so update: I found the correct id. Apparently there have been two existing main.xml files and I had to delete one, but now I am only getting one of the bottom navigations, no matter what user (wether searching person or photographer) is logged in. The question is still, how can I separate them?
Here is the updated xml:
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#E8E8E8">
<FrameLayout
android:id="#+id/frameLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/BottomNavMenu"
android:layout_width="300dp"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center"
android:layout_margin="30dp"
android:background="#drawable/buttom_bg"
android:elevation="2dp"
app:itemIconSize="30dp"
app:itemIconTint="#drawable/item_selector"
app:itemRippleColor="#android:color/transparent"
app:labelVisibilityMode="unlabeled"
app:menu="#menu/bottom_nav_menu"
tools:ignore="MissingConstraints">
</com.google.android.material.bottomnavigation.BottomNavigationView>
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="#+id/bottomNavFoto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_margin="30dp"
android:background="#drawable/buttom_bg"
android:elevation="2dp"
app:itemIconSize="30dp"
app:itemIconTint="#drawable/item_selector"
app:itemRippleColor="#android:color/transparent"
app:labelVisibilityMode="unlabeled"
app:layout_constraintBottom_toBottomOf="#+id/frameLayout"
app:menu="#menu/bottom_nav_fotograf"
tools:ignore="MissingConstraints"
tools:layout_editor_absoluteX="30dp"></com.google.android.material.bottomnavigation.BottomNavigationView>
</androidx.constraintlayout.widget.ConstraintLayout>
Okay, I managed it by outsourcing the bottom navigations in new activities and starting those in the if-clause of the main activity.kt with new layouts.
Related
I made a dialogue box and I put radio group in it and I add three radio button 1)male 2)female 3)others if user select male so the selected radio button male should be shown in text View
Here, I would like to share you here a simple app with both the activity and layout code. I hope this will help you.
First the layout
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:padding="100dp"
tools:context=".TestActivity">
<TextView
android:id="#+id/textView3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="20dp"
android:text="What is your gender?"
android:textSize="20sp"
android:textStyle="bold" />
<TextView
android:id="#+id/txtViewGender"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="20dp"
android:text="-- Selected Gender --"
android:textSize="16sp" />
<Button
android:id="#+id/button"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="Select" />
</LinearLayout>
Second the Main Activity code
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.dialog.MaterialAlertDialogBuilder
class GenderActivity: AppCompatActivity() {
private lateinit var selectedGender: String
private var selectedGenderIndex: Int = 0
private val gender = arrayOf("Male", "Female", "Others")
private lateinit var txtViewGender: TextView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_test4)
txtViewGender = findViewById<TextView>(R.id.txtViewGender)
var androidButton: Button = findViewById<Button>(R.id.button)
androidButton.setOnClickListener {
showRadioDialog()
}
}
private fun showRadioDialog() {
selectedGender = gender[selectedGenderIndex]
MaterialAlertDialogBuilder(this)
.setTitle("Select your gender")
.setSingleChoiceItems(gender, selectedGenderIndex) { dialog, which ->
selectedGenderIndex = which
selectedGender = gender[which]
}
.setPositiveButton("Ok") { dialog, which ->
Toast.makeText(this, "Selected --> $selectedGender ", Toast.LENGTH_SHORT)
.show()
txtViewGender.text = selectedGender
}
.setNegativeButton("Cancel") { dialog, which ->
dialog.dismiss()
}
.show()
}
}
When you run the code, you will get the following two screens.
Screen 1
Screen 2
I’m using Android Studio with Kotlin. I’d like to be able to drag and drop items in a ListView to reorder them. I also want to swipe left to delete. This was pretty straightforward in XCode/Swift for iOS, but I’m having trouble finding examples for Android/Kotlin. I’ve seen some fairly old discussions with Java and with RecyclerView, but it would be great to be able to do it in Kotlin with ListView. I should add that the ListView does everything I need so far – I realise there is much discussion about ListView vs RecyclerView.
I’m not asking for people to solve this for me, but it would be great if you could point me to anything that might get me going.
By way of background, here is my code. It is just a ListView with numbers ‘zero’ to ‘ten’ and the selected row highlighted. I should add that I wrote this code with the help of many discussions here and on YouTube, for which I’m very grateful.
I also have a ListView with sections that needs these options, but I’ve not put the code here for that (happy to do so if required).
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<ListView
android:id="#+id/list_view"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:layout_margin="16dp" />
</androidx.constraintlayout.widget.ConstraintLayout>
listview_row.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/rowText"
android:layout_width="match_parent"
android:layout_height="48dp"
android:textColor="#color/black"
android:paddingLeft="0dp"
android:paddingTop="8dp"
android:paddingRight="0dp"
android:paddingBottom="8dp"
android:autoSizeTextType="uniform"
android:autoSizeMaxTextSize="40sp"
android:autoSizeMinTextSize="8sp"
android:autoSizeStepGranularity="2sp"
android:lines="1" />
</LinearLayout>
listview_selected_row.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="#+id/selectedRowText"
android:layout_width="match_parent"
android:layout_height="48dp"
android:paddingLeft="0dp"
android:paddingRight="0dp"
android:paddingTop="8dp"
android:paddingBottom="8dp"
android:background="#color/teal_200"
android:textColor="#color/black"
android:autoSizeTextType="uniform"
android:autoSizeMaxTextSize="40sp"
android:autoSizeMinTextSize="8sp"
android:autoSizeStepGranularity="2sp"
android:lines="1" />
</LinearLayout>
ListViewAdapter.kt
package com.ijmusic.listviewrearrange
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import android.widget.TextView
val TYPE_LISTVIEW_ITEM = 0
val TYPE_LISTVIEW_SELECTED_ITEM = 1
class ListViewAdapter(private val context: Context): BaseAdapter() {
private val mData: ArrayList<String> = ArrayList()
private var mIndex: ArrayList<Int> = ArrayList()
private var mSelectedItem = -1
private lateinit var textView: TextView
fun addItem(item: String, index: Int) {
mData.add(item)
mIndex.add(index)
notifyDataSetChanged()
}
fun addSelectedItem(item: String, index: Int) {
mData.add(item)
mIndex.add(index)
mSelectedItem = mData.size - 1
notifyDataSetChanged()
}
fun highlightSelection(int: Int) {
mSelectedItem = int
notifyDataSetChanged()
}
override fun getItemViewType(position: Int): Int {
return if (position == mSelectedItem) TYPE_LISTVIEW_SELECTED_ITEM
else TYPE_LISTVIEW_ITEM
}
override fun getCount(): Int {
return mData.size
}
override fun getItem(position: Int): Any {
return mData[position]
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getView(position: Int, view: View?, parent: ViewGroup?): View? {
var view = view
var type = getItemViewType(position)
if (position == mSelectedItem) type = TYPE_LISTVIEW_SELECTED_ITEM
when (type) {
TYPE_LISTVIEW_ITEM -> {
view = LayoutInflater.from(context).inflate(R.layout.listview_row, parent, false)
textView = view.findViewById(R.id.rowText)
}
TYPE_LISTVIEW_SELECTED_ITEM -> {
view = LayoutInflater.from(context).inflate(R.layout.listview_selected_row, parent, false)
textView = view.findViewById(R.id.selectedRowText)
}
}
textView.text = mData[position]
return view
}
}
MainActivity.kt
package com.ijmusic.listviewrearrange
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.view.View
import android.widget.AdapterView
import com.ijmusic.listviewrearrange.databinding.ActivityMainBinding
val list = listOf("zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten")
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private lateinit var mAdapter: ListViewAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
mAdapter = ListViewAdapter(this)
setListView()
binding.listView.onItemClickListener = object: AdapterView.OnItemClickListener {
override fun onItemClick(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
binding.listView.setSelection(position)
mAdapter.highlightSelection(position)
}
}
}
fun setListView() {
for ( i in 0 until list.count() ) {
if ( i == 0 )
mAdapter.addSelectedItem(list[i], i)
else
mAdapter!!.addItem(list[i], i)
}
binding.listView.adapter = mAdapter
}
}
You can look into a concept called gestures in android Kotlin. It will help.
I am using a horizontal RecyclerView and showing images using the CircleImageView widget (See image below).
I am really struggling on how to make the list of items loop around, so that if you are in the last item, you will move to the first item in the list?
I have tried quite a few similar examples but I can’t make them work as they are in Java, or are quite complex. following is my code
MainActivity.kt
class MainActivity : AppCompatActivity() {
lateinit var adapter: ConcatAdapter
lateinit var userVerticalAdapter: UsersAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setupDataInRecyclerView()
}
private fun setupDataInRecyclerView() {
recyclerView.layoutManager = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, false)
userVerticalAdapter = UsersAdapter(DataSource.getUser())
val listOfAdapters = listOf(userVerticalAdapter)
adapter = ConcatAdapter(listOfAdapters)
recyclerView.adapter = adapter
}
}
Adapter.kt
class UsersAdapter(
private val users: ArrayList<User>
) : RecyclerView.Adapter<UsersAdapter.DataViewHolder>() {
class DataViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
fun bind(user: User) {
itemView.textViewUserName.text = user.name
Glide.with(itemView.imageViewAvatar.context)
.load(user.avatar)
.into(itemView.imageViewAvatar)
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int) =
DataViewHolder(LayoutInflater.from(parent.context)
.inflate(R.layout.item_layout, parent,false))
override fun getItemCount(): Int = users.size
override fun onBindViewHolder(holder: DataViewHolder, position: Int) =
holder.bind(users[position])
}
}
DataSource.kt
object DataSource {
fun getUser() = ArrayList<User>().apply {
add(User(1, "Chillis", R.drawable.chilli))
add(User(2, "Tomato", R.drawable.tomatoe))
add(User(3, "Sweetcorn", R.drawable.sweeetcorn))
add(User(4, "Potatoe", R.drawable.potatoe))
add(User(5, "Aubergine", R.drawable.aubmain))
add(User(12, "Onion", R.drawable.onion))
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:listitem="#layout/item_layout_banner"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
item_layout.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_margin="1dp">
<androidx.cardview.widget.CardView
android:layout_width="120dp"
android:layout_height="120dp"
app:cardCornerRadius="4dp"
app:cardMaxElevation="2dp"
app:cardElevation="1dp"
android:layout_centerInParent="true">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<de.hdodenhof.circleimageview.CircleImageView
android:layout_width="90dp"
android:layout_height="90dp"
android:scaleType="centerCrop"
android:layout_centerHorizontal="true"
app:civ_border_width= "3dp"
app:civ_border_color= "#color/colorPrimary"
android:id="#+id/imageViewAvatar"
android:src="#drawable/ic_launcher_background"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="20dp"
android:text="Veg"
android:layout_below="#+id/imageViewAvatar"
android:id="#+id/textViewUserName"
android:gravity="center"
android:layout_marginTop="5dp"
android:layout_centerHorizontal="true"
android:textColor="#000"
android:layout_marginBottom="5dp"
android:autoSizeTextType="uniform"
android:autoSizeMinTextSize="8sp"
android:autoSizeMaxTextSize="15sp"/>
</RelativeLayout>
</androidx.cardview.widget.CardView>
</RelativeLayout>
To achieve this first you have to override the getItemCount function of UsersAdapter to return a very large value such as Int.MAX_VALUE
// This enables your adapter to scroll past the actual list size
override fun getItemCount(): Int = Int.MAX_VALUE
Now change your onBindViewHolder to calculate actual position
// Lets say your list had 100 items
override fun onBindViewHolder(holder: DataViewHolder, position: Int) {
// position can be larger than 100 (ex 101), because our getItemCount doesn't return actual list size
// so if we receive position as 101, which item should we display?
// that should be item 1. (for 102 -> 2, 201 -> 1) and so on
// this suggests use of modules
val pos = position % users.size
holder.bind(users[pos]) // bind the actual item
}
Now in your MainActivity after recyclerView.adapter = adapter line, add following line
// When RV is loaded scroll it to middle, so that user doesn't hit limit on both ends(easily)
rv.scrollToPosition(Int.MAX_VALUE/2)
I have created a To do List app with a Floating Actin Button and my code is returning three errors:
Expecting ')'
Expecting an Element
Unresolved Reference fab
The code was fine until I decided to add another button to the bottom of my activity_main.xml file and needed to add a relativelayout inside a coordinator layout to do it. The new button is to allow users to change the colour of the background. Once adding this code into the MainActivity.kt file the original findViewById code for the fab no longer works and gives the above errors.
MainActivity.kt file
abstract class MainActivity : AppCompatActivity() ,UpdateAndDelete {
private lateinit var database: DatabaseReference
var toDoList: MutableList<ToDoModel>? = null
lateinit var adapter: ToDoAdapter
private var listViewItem : ListView?=null
internal abstract var screenView:View
internal abstract var clickMe:Button
internal abstract var color:Array<Int>
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
intArrayOf(Color.MAGENTA, Color.YELLOW, Color.BLUE, Color.BLACK)
screenView = findViewById(R.id.rView)
clickMe = findViewById(R.id.colorButton) as Button
clickMe.setOnClickListener(object:View.OnClickListener {
override fun onClick(view: View) {
val aryLength = color.size
val random = Random
val rNum = random.nextInt(aryLength)
screenView.setBackgroundColor(color[rNum])
}
}
val fab: View = findViewById(R.id.fab)
listViewItem = findViewById<ListView>(R.id.item_listView)
database = FirebaseDatabase.getInstance().reference
fab.setOnClickListener { view ->
val alertDialog = AlertDialog.Builder(this)
val textEditText = EditText (this)
alertDialog.setMessage("Add TODO Item")
alertDialog.setTitle("Enter TO DO Item")
alertDialog.setView(textEditText)
alertDialog.setPositiveButton("Add") {dialog, i ->
val todoItemData = ToDoModel.createList()
todoItemData.itemDataText = textEditText.text.toString()
todoItemData.done = false
val newItemData=database.child("todo").push()
todoItemData.UID = newItemData.key
newItemData.setValue(todoItemData)
dialog.dismiss()
Toast.makeText(this, "item saved", Toast.LENGTH_LONG).show()
}
alertDialog.show()
}
activity_main.xml file
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000000"
tools:context=".MainActivity">
<ListView
android:id="#+id/item_listView"
android:layout_width="match_parent"
android:layout_height="651dp"
android:background="#color/white"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:scrollbars="none" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="15dp"
android:layout_gravity="bottom|end"
android:elevation="6dp"
app:pressedTranslationZ="12dp"
android:src="#drawable/ic_baseline_add_24" />
<RelativeLayout
android:id="#+id/rView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="bottom"
android:gravity="bottom">
<Button
android:id="#+id/colorButton"
android:layout_width="170dp"
android:layout_height="58dp"
android:layout_alignParentStart="true"
android:layout_alignParentBottom="true"
android:layout_marginStart="22dp"
android:layout_marginBottom="11dp"
android:backgroundTint="#color/teal_200"
android:text="Change Colour"
android:textColor="#color/black" />
</RelativeLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Looking at this bit of your code:
clickMe.setOnClickListener(object:View.OnClickListener {
override fun onClick(view: View) {
val aryLength = color.size
val random = Random
val rNum = random.nextInt(aryLength)
screenView.setBackgroundColor(color[rNum])
}
}
val fab: View = findViewById(R.id.fab)
You are getting the first error because you are not properly closing the call to clickMe.setOnClickListener by providing a ) after the } on the second to last line. The compiler realizes this on the last line that defines fab, and so it is that line that the compiler is actually complaining about.
To fix this, add a ) to the second to last line, like this:
clickMe.setOnClickListener(object:View.OnClickListener {
override fun onClick(view: View) {
val aryLength = color.size
val random = Random
val rNum = random.nextInt(aryLength)
screenView.setBackgroundColor(color[rNum])
}
})
val fab: View = findViewById(R.id.fab)
Once you have an initial syntax error, it doesn't really matter what other errors the compiler is producing. Fix this first error and re-evaluate where you're at.
If the code you supply is supposed to be complete...that is, the entire contents of the file MainActivity.kt is provided, then you are missing a number of closing curlies (}) at the end of the code.
I have a RecyclerView in MainActivity that shows a list of CardViews and that is working properly. A click on the CardView finishes the RecyclerView Activity and launches a Detail Activity that shows the clicked on CardView in a new RecyclerView list. The Detail Activity is used only to show that single CardView in a RecyclerView (I do this so I can use RecyclerView's ItemTouchHelper.SimpleCallback code on the CardView for easy left swipe for the user).
Here is the problem: I hit the left caret on the Detail Activity's Toolbar to return to the MainActivity. Then a click on the exact same CardView brings the user back to the Detail Activity. But this time only the background View (a border) is showing. The view of the CardView and its database data is completely missing.
The error appears to happen randomly. I can click to go from the MainActivity to the Detail Activity back and forth 5 times successfully and then on the sixth try, no CardView will show in the Detail Activity. Or I'll click two times successfully and then the third time, the CardView in the Detail Activity will not show. Note the left caret click in Detail Activity uses onBackPressed() so the Detail Activity finishes. So I don't think there should be any backstack issues. I also tried to adjust the xml height for the CardView to match_parent rather than wrap_content but no luck. The Detail Activity's ViewModel to Repository to Dao returns a List wrapped in LiveData. Perhaps there is an observer problem with the ViewModel, but I thought the observer gets removed/destroyed when the Detail Activity is destroyed? What am I missing here?
Adapter
...
itemHolder.cardView.setOnClickListener(view -> {
Card adapterItem= TodosAdapter.this.getItem(itemHolder.getAdapterPosition());
int adapPos = itemHolder.getAdapterPosition();
if (adapPos !=RecyclerView.NO_POSITION) {
onItemClick(adapPos, adapterItem);
}
});
MainActivity
...
public void onItemClick(int clickPos, Card cardFromClick) {
Intent intent = new Intent(MainActivity.this, DetailActivity.class);
intent.putExtra("TAG","fromMain");
intent.putExtra("itemFromMain", cardFromClick);
startActivity(intent);
finish();
DetailActivity
...
public class DetailActivity extends AppCompatActivity {
private int cardId = -1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_details);
// Get a new or existing ViewModel from the ViewModelProvider.
detsViewModel = new ViewModelProvider(this).get(CardViewModel.class);
Toolbar toolbar = findViewById(R.id.toolbar);
// The left caret is for Up navigation to the previous activity
// for OS versions 4.0 and earlier.
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
toolbar.setNavigationIcon(R.drawable.ic_action_previous_item);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
onBackPressed();
}
});
}
Intent intent = getIntent();
Bundle extras = intent.getExtras();
if (extras != null) {
String classname = extras.getString("TAG");
// The user clicked on a Card in the MainActivity
if (classname != null && classname.equals("fromMain")) {
card = extras.getParcelable("itemFromMain");
if (card != null) {
cardId = card.getId(); // card data is stored in Room database.
}
}
}
detsViewModel.getSingleCard(cardId).observe(this, singleAdapterList -> {
adapter2.setCardList(singleAdapterList);
});
}
activity_details.xml
...
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#FFFFFF"
tools:context=".DetailsActivity" >
<include
android:id="#+id/toolbar"
layout="#layout/toolbar" >
</include>
<RelativeLayout
android:id="#+id/todoListLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/toolbar" >
<TextView
android:id="#+id/Card"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="6dp"
android:text="Card"
android:textStyle="bold"
android:textColor="#color/text_primary"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_centerHorizontal="true" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/details_recyclerview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"
android:layout_below="#+id/Card"
android:scrollbars="vertical" />
<TextView
android:id="#+id/skytext5"
android:text="Cards"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/details_recyclerview"
android:background="#color/colorPrimary"
android:textAppearance="?android:attr/textAppearanceMedium"
android:clickable="true"
android:focusable="true" />
</RelativeLayout>
DetailsAdapter
...
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(mContext).inflate(R.layout.details_list_item, parent, false);
}
private List<Card> oneCardList
public void setCardList(List<Card> singleCardList) {
if (oneCardList != null) {
oneCardList.clear();
this.oneCardList = singleCardList;
} else {
// First initialization
this.oneCardList = singleCardList;
}
}
details_list_item.xml
...
<FrameLayout
xmlns:card_view="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/detsinglecard_view"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:orientation="vertical"
android:foreground="?android:attr/selectableItemBackground"
android:background="#FFFFFF"
tools:context=".DetailActivity">
<RelativeLayout
android:id="#+id/view_background2"
android:layout_width="wrap_content"
android:layout_height="match_parent"
...
</RelativeLayout>
<RelativeLayout
android:id="#+id/view_foreground2"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:background="#color/colorFlLabelFinal" >
<androidx.cardview.widget.CardView
android:id="#+id/cardview_dets"
android:layout_height="match_parent"
android:layout_width="match_parent"
...
}
ViewModel
...
LiveData<List<Card>> getSingleCard(int cardId) {
return repository.getSingleCard(cardId);
}
Repository
...
public LiveData<List<Card>> getSingleCard(int cardId) {
return quickcardDao.getSingleCard(cardId);
}
Dao
...
#Query("SELECT * FROM cards WHERE cardId = :cardId LIMIT 1")
LiveData<List<Card>> getSingleCard(int cardId);
So if the data does not change then going back to the same DetailActivity will not refresh the View. The answer was to re-use the LiveData (rather than re-loading the LiveData again from the database) if the data has not changed. See the Android Developers Architecture Components guide for ViewModel, "Implement a ViewModel" section for the "loadUsers()" example that solved my problem: https://developer.android.com/topic/libraries/architecture/viewmodel.