avoid fragment recreation BottomNavigationView - android-fragments

i want to avoid fragment recreation by using BottomNavigationView
i read about that FragmentTransaction.replace is the problem and changing to add would help, but that didn't work for me..
maybe you can see here where i'm wrong
this is my Host Activity which hosting 3 fragments with BottomNavigationView
'''
class Host : AppCompatActivity() {
var fragment: Fragment? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_host)
//for hide the actionBar (contains Fragment name) on top of the screen
val actionBar = supportActionBar
actionBar?.hide()
val navController = Navigation.findNavController(this, R.id.nav_host_fragment)
val navView = findViewById<BottomNavigationView>(R.id.nav_view)
navView?.setupWithNavController(navController)
NavigationUI.setupWithNavController(navView, navController)
mAdapter = NfcAdapter.getDefaultAdapter(this)
fragmentStayAlive()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
for (fragment in supportFragmentManager.fragments) {
fragment.onActivityResult(requestCode, resultCode, data)
}
}
fun ByteArray.toHexString() = joinToString("") { "%02x".format(it) }
private fun fragmentStayAlive(){
val fragment1: Fragment = LobbyFragment()
val fragment2: Fragment = GameSessionFragment()
val fragment3: Fragment = UserStatusFragment()
val fm: FragmentManager = supportFragmentManager
var active = fragment1
fm.beginTransaction().add(R.id.nav_host_fragment, fragment3, "UserStatusFragment").hide(
fragment3
).commit();
fm.beginTransaction().add(R.id.nav_host_fragment, fragment2, "GameSessionFragment").hide(
fragment2
).commit();
fm.beginTransaction().add(R.id.nav_host_fragment, fragment1, "LobbyFragment").commit();
val mOnNavigationItemSelectedListener: BottomNavigationView.OnNavigationItemSelectedListener =
object : BottomNavigationView.OnNavigationItemSelectedListener {
override fun onNavigationItemSelected(item: MenuItem): Boolean {
when (item.getItemId()) {
R.id.lobbyFragment -> {
fm.beginTransaction().hide(active).show(fragment1).commit()
active = fragment1
return true
}
R.id.gameSessionFragment -> {
fm.beginTransaction().hide(active).show(fragment2).commit()
active = fragment2
return true
}
R.id.userStatusFragment -> {
fm.beginTransaction().hide(active).show(fragment3).commit()
active = fragment3
return true
}
}
replaceFragment(active, null, true, true)
return false
}
}
}
fun replaceFragment(
fragment: Fragment,
#Nullable bundle: Bundle?,
popBackStack: Boolean,
findInStack: Boolean
) {
val fm = supportFragmentManager
val ft: FragmentTransaction = fm.beginTransaction()
val tag = fragment.javaClass.name
val parentFragment: Fragment?
parentFragment = if (findInStack && fm.findFragmentByTag(tag) != null) {
fm.findFragmentByTag(tag)
} else {
fragment
}
// if user passes the #bundle in not null, then can be added to the fragment
if (bundle != null) {
parentFragment!!.arguments = bundle
} else {
parentFragment!!.arguments = null
}
// this is for the very first fragment not to be added into the back stack.
if (popBackStack) {
fm.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE)
} else {
ft.addToBackStack(parentFragment.javaClass.name + "")
}
ft.add(R.id.nav_view, parentFragment, tag)
ft.commit()
fm.executePendingTransactions()
}
'''
thanks for all the helpers!

Related

updat listview in an activity after click update button in custom adapter

I have an activity (ProductList) contain listview to view all products in my database, and a custom adapter for the list (MyListAdapter) that contains update button when I click on it a dialoge open and update the product info.
I want that when I update the product info and close the dialog the listview updated in the same time.
ProductsList Activity
class ProductsList : AppCompatActivity() {
private lateinit var databaseHandler:DatabaseHandler
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_products_list)
databaseHandler = DatabaseHandler(this)
val product: ArrayList<Product> = databaseHandler.listProduct()
val productArrayId = Array(product.size){"0"}
val productArrayName = Array(product.size){"null"}
val productArrayQuantity = Array(product.size){"null"}
val allInfo = Array(product.size){"null"}
for((index, e) in product.withIndex()){
productArrayId[index] = e.getProductID().toString()
productArrayName[index] = e.getProductName()
productArrayQuantity[index] = e.getProductQuantity().toString()
allInfo[index] = e.getProductID().toString() + " " + e.getProductName() + " " + e.getProductQuantity().toString()
}
var myListAdapter = MyListAdapter(this,product)
lv_products.adapter = myListAdapter
}
}
MyListAdapter class
class MyListAdapter(private val context: Activity, private val products: ArrayList<Product>) : BaseAdapter() {
private var databaseHandler = DatabaseHandler(this.context)
override fun getCount(): Int {
return products.size
}
override fun getItem(position: Int): Any {
return products[position]
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
#SuppressLint("ViewHolder")
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
val inflater = LayoutInflater.from(context)
val customView = inflater.inflate(R.layout.custom_list, parent, false)
customView.tv_product_id.text = products[position].getProductID().toString()
customView.tv_product_name.text = products[position].getProductName()
customView.tv_product_quantity.text = products[position].getProductQuantity().toString()
customView.btn_edit_product.setOnClickListener {
val layout = LayoutInflater.from(context)
val view = layout.inflate(R.layout.update_dialog, null)
view.et_product_id.setText(products[position].getProductID().toString())
view.et_product_name.setText(products[position].getProductName())
view.et_product_quantity.setText(products[position].getProductQuantity().toString())
AlertDialog.Builder(context).setView(view).setTitle("update product info")
.setPositiveButton("yes") { _, _ ->
val status = databaseHandler.updateProduct(
view.et_product_id.text.toString().toInt(),
view.et_product_name.text.toString(),
view.et_product_quantity.text.toString().toInt()
)
if (status > -1) {
Toast.makeText(this.context, "record updated", Toast.LENGTH_LONG).show()
this.notifyDataSetChanged()
} else {
Toast.makeText(this.context, "update error", Toast.LENGTH_LONG).show()
}
}
.setNegativeButton("no") { _, _ -> }
.setIcon(R.drawable.ic_baseline_warning_24)
.show()
this.notifyDataSetChanged()
}
return customView
}
}

Notifications are not shown when the app is closed, how can I fix it?

It successfully shows notifications when the app is open. It shows even when the app is in the background. When I close the app it doesn't show up anymore. I don't want to use FCM. because I want to remember this when doing other applications. In a video, she said that the service above Android 8 does not work permanently, and that startForeground () should be used as a solution for this.But I don't want to use it because it creates a permanent notification on top
class MyFirebaseMessagingService : Service() {
private val channelId = "notification_channel"
private val channelName = "com.dombikpanda.doktarasor.service"
private val notificationTitle = "Sorunuz Cevaplanmıştır"
private val notificationMessage =
"Doktor tarafından sorunuz cevaplanmıştır.Görmek için tıklayınız"
private var importance = 0
private var notifManagerId = 0
override fun onBind(intent: Intent): IBinder? {
return null
}
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int {
questionNotification()
return START_STICKY
}
override fun onDestroy() {
super.onDestroy()
}
override fun onCreate() {
createNotifChannel()
super.onCreate()
}
private val crudRepository = CrudRepository()
private fun questionNotification() {
val shared = getSharedPreferences("kontrol", MODE_PRIVATE)
val control = shared.getLong("date", 0)
val collection = Firebase.firestore.collection("questions")
collection
.addSnapshotListener { value, error ->
error.let {
}
value?.let { result ->
for (document in result) {
if (document["userid"] == crudRepository.getFirebaseAuth().uid) {
if (document["cevapdurum"] == true && document["messageDurum"] == true && document["date"] == control) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
createNotification()
}
break
}
}
}
}
}
}
private fun createNotifChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
importance = NotificationManager.IMPORTANCE_HIGH //normal high
val notificationChannel =
NotificationChannel(channelId, channelName, importance).apply {
description = notificationMessage
}
val manager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
manager.createNotificationChannel(notificationChannel)
}
}
#RequiresApi(Build.VERSION_CODES.O)
private fun createNotification() {
val intent = Intent(this, MainActivity::class.java).apply {
flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK
}
val pendingIntent: PendingIntent =
PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_IMMUTABLE)
val notification = NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.drawable.ic_stat_name)
.setContentTitle(notificationTitle)
.setContentText(notificationMessage)
.setAutoCancel(true)
.setOnlyAlertOnce(true)
.setStyle(NotificationCompat.DecoratedCustomViewStyle())
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setVibrate(longArrayOf(1000, 1000, 1000, 1000))
.setSound(Settings.System.DEFAULT_NOTIFICATION_URI)
.setContentIntent(pendingIntent)
with(NotificationManagerCompat.from(this)) {
notify(notifManagerId, notification.build())
notifManagerId++
}
}
}

Kotlin searchView does not reload Firebase array

I have one activity with 2 recyclerViews, both recyclers are used with Firebase. One of the recyclers displays the results of a query, the other recycler has a listener that updates every time there is an update in Firebase. I added a searchView to filter the results from Firebase. The issue I'm having is when I'm trying to search the results from the Firebase query, when I start typing I see results but when I click the X to stop searching, the adapter does not reload the array and i don't see the list of items unless I reload the activity. I'm not sure what I'm missing here. Any help/suggestion is greatly appreciated. Here is my code:
Adapter
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Filter
import android.widget.Filterable
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.eduardoz.ezmdapp.Model.Charges
import com.eduardoz.ezmdapp.R
class ChargesAdapter (private var charges: ArrayList<Charges>
, private var chargesAll: ArrayList<Charges>
, private val itemClick: (Charges) -> Unit)
: RecyclerView.Adapter<ChargesAdapter.ViewHolder>()
, Filterable {
inner class ViewHolder(itemView: View, val itemClick: (Charges) -> Unit) :
RecyclerView.ViewHolder(itemView) {
private val chargeCode = itemView.findViewById<TextView>(R.id.chargeCodeTxt)
private val chargeDescription = itemView.findViewById<TextView>(R.id.chargeDescriptionTxt)
fun bindCharges(charges: Charges) {
chargeCode?.text = charges.chargeCode
chargeDescription?.text = charges.chargeDescription
itemView.setOnClickListener { itemClick(charges) }
}
}
init {
this.charges = charges
chargesAll = java.util.ArrayList(charges)
}
override fun getItemCount(): Int {
return charges.count()
}
override fun onBindViewHolder(holder: ChargesAdapter.ViewHolder, position: Int) {
holder.bindCharges(charges[position])
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ChargesAdapter.ViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.charges_list, parent, false)
return ViewHolder(view, itemClick)
}
override fun getFilter(): Filter {
return searchFilter
}
private val searchFilter: Filter = object: Filter() {
override fun performFiltering(constraint: CharSequence?): FilterResults {
val filteredList: ArrayList<Charges> = ArrayList()
if (constraint!!.isEmpty()) {
filteredList.addAll(chargesAll)
} else {
for(item in chargesAll) {
if
(item.chargeDescription.toLowerCase().contains(constraint.toString().toLowerCase())) {
filteredList.add(item)
}
}
}
val searchResults = FilterResults()
searchResults.values = filteredList
return searchResults
}
override fun publishResults(constraint: CharSequence?, results: FilterResults?) {
charges.clear()
charges.addAll(results!!.values as Collection<Charges>)
notifyDataSetChanged()
}
}
}
Activity
descriptionSearch.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String): Boolean {
return false
}
override fun onQueryTextChange(newText: String): Boolean {
if (newText.isNotEmpty()) {
searchViewBar(newText)
} else {
if (newText.isEmpty()) { //I ADDED THIS TO RELOAD THE ADAPTER
charges.clear()
chargeList()
}
}
return false
}
})
private fun searchViewBar(newText: String) {
chargesListener = chargesCollectionRef
.whereGreaterThanOrEqualTo(CHARGE_DESCRIPTION, newText)
.whereLessThanOrEqualTo(CHARGE_DESCRIPTION, newText+"z")
.addSnapshotListener(this) { snapshot, exception ->
if (exception != null) {
println("error")
}
if (snapshot != null) {
charges.clear()
parseData(snapshot)
}
}
}
fun parseData(snapshot: QuerySnapshot) {
for (document in snapshot.documents) {
val data = document.data
val chargeCode = data!![CHARGE_CODE] as String
val chargeDescription = data[CHARGE_DESCRIPTION] as String
val chargeSpecialty = data[CHARGE_SPECIALTY] as String
val newChargeList = Charges(chargeCode, chargeDescription, chargeSpecialty)
charges.add(newChargeList)
}
chargesFromAdapter.notifyDataSetChanged()
}

Get data from a Firebase Realtime Database child

This my project I have 2 RecyclewView, the first selects the user I want to manipulate, which is working perfectly.
When selecting it I store your id and transfer it to a next screen that should show your medical history (using your id to search your database for your history).
But this recycler view remains blank, does not give an error but also does not return anything, maybe I'm missing the time to put the path to be taken to bring this history.
image BD Firestore: [1]: https://imgur.com/HOxQTsI
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_verificar_historico)
setSupportActionBar(toolbar_historico)
toolbar_historico.setTitle("Titulo Aqui")
userId = intent.extras?.getString("userId")
textViewX.setText(userId)
getLastKey()
val layoutManager = LinearLayoutManager(this)
recycler_view_historico.layoutManager = layoutManager
val dividerItemDecoration = DividerItemDecoration(recycler_view_historico.context, layoutManager.orientation)
recycler_view_historico.addItemDecoration(dividerItemDecoration)
adapter = HistoricoAdapter(this)
recycler_view_historico.adapter = adapter
getHistorico()
recycler_view_historico.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
total_item = layoutManager.itemCount
last_visible_item = layoutManager.findLastVisibleItemPosition()
if (isLoading && total_item <= last_visible_item + ITEM_COUNT) {
getHistorico()
isLoading = true
}
}
})
}
private fun getHistorico() {
if (!isMaxData) {
val query: Query
if (TextUtils.isEmpty(last_node))
query = FirebaseDatabase.getInstance().reference
.child("pacientes/$userId/historico")
.orderByKey()
.limitToFirst(ITEM_COUNT)
else
query = FirebaseDatabase.getInstance().reference
.child("pacientes/$userId/historico")
.orderByKey()
.startAt(last_node)
.limitToFirst(ITEM_COUNT)
query.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onCancelled(p0: DatabaseError) {
}
override fun onDataChange(p0: DataSnapshot) {
if (p0.hasChildren()) {
val historicoLista = ArrayList<HistoricoRecycle>()
for (snapshot in p0.children)
historicoLista.add(snapshot.getValue(HistoricoRecycle::class.java)!!)
last_node = historicoLista[historicoLista.size - 1].data
if (!last_node.equals(last_key))
historicoLista.removeAt(historicoLista.size - 1)
else
last_node = "end"
adapter.addAll(historicoLista)
isLoading = false
} else {
isLoading = false
isMaxData = true
}
}
})
}
}
private fun getLastKey() {
val get_last_key = FirebaseDatabase.getInstance().getReference()
.child("pacientes/$userId/historico")
.orderByKey()
.limitToLast(1)
get_last_key.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onCancelled(p0: DatabaseError) {
}
override fun onDataChange(p0: DataSnapshot) {
for (userSnapShot in p0.children)
last_key = userSnapShot.key
}
})
}

Cannot fetch messages from another user FirebaseDatabase

This is a simple chat messaging app, using Firebase Realtime Database and the Authentication. I have successfully created the database, but I cannot fetch the message from one user to another. Because, when I send the message/click the send button, it creates different nodes, I think its a string node with quotation mark in the name. The node structure I created is user-messages --> fromId(current user uid) --> toUid(to whom the messages are sent).
To make more clear explanation, this is the screenshot of what happened.
I think the problem is, it creates a different nodes with the "uid", which means string. So the database has two nodes, one with the "...", and the other the normal one. For some info, I use some library such as Picasso image load, groupie, and parcelize.
This is the source code for the ChatLogActivity
import...
class ChatLogActivity : AppCompatActivity() {
companion object {
val TAG = "ChatLog"
}
val adapter = GroupAdapter<ViewHolder>()
var toUser: User? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_chat_log)
recyclerview_chat_log.adapter = adapter
toUser = intent.getParcelableExtra(NewMessageActivity.USER_KEY)
titleChatLog.text = toUser?.nama
listenForMessages()
arrowBack.setOnClickListener {
finish()
}
send_button_chat_log.setOnClickListener {
Log.d(TAG, "Attempt to send message.....")
performSendMessage()
}
}
private fun listenForMessages() {
val fromId = FirebaseAuth.getInstance().uid
val toId = toUser?.uid
val ref = FirebaseDatabase.getInstance().getReference("/user-messages/$fromId/$toId")
ref.addChildEventListener(object : ChildEventListener {
override fun onChildAdded(p0: DataSnapshot, p1: String?) {
val chatMessage = p0.getValue(ChatMessage::class.java)
if (chatMessage != null) {
Log.d(TAG, chatMessage.text)
if (chatMessage.fromId == FirebaseAuth.getInstance().uid) {
val currentUser = LatestMessageActivity.currentUser?: return
adapter.add(ChatFromItem(chatMessage.text, currentUser))
} else {
adapter.add(ChatToItem(chatMessage.text, toUser!!))
}
}
}
override fun onCancelled(p0: DatabaseError) {
}
override fun onChildChanged(p0: DataSnapshot, p1: String?) {
}
override fun onChildMoved(p0: DataSnapshot, p1: String?) {
}
override fun onChildRemoved(p0: DataSnapshot) {
}
})
}
private fun performSendMessage() {
val text = edittext_chat_log.text.toString()
val fromId = FirebaseAuth.getInstance().uid
val user = intent.getParcelableExtra<User>(NewMessageActivity.USER_KEY)
val toId = user.uid
val ref = FirebaseDatabase.getInstance().getReference("/user-messages/$fromId/$toId").push()
val toRef = FirebaseDatabase.getInstance().getReference("/user-messages/$toId/$fromId ").push()
if (fromId == null) return
val chatMessage = ChatMessage(ref.key!!, text, fromId, toId, System.currentTimeMillis() / 1000)
ref.setValue(chatMessage)
.addOnSuccessListener {
Log.d(TAG, "Save our chat message: ${ref.key}")
edittext_chat_log.text.clear()
recyclerview_chat_log.scrollToPosition(adapter.itemCount - 1)
}
toRef.setValue(chatMessage)
}
}
class ChatFromItem(val text: String, val user: User) : Item<ViewHolder>() {
override fun getLayout(): Int {
return R.layout.chat_from_row
}
override fun bind(viewHolder: ViewHolder, position: Int) {
val uri = user.profileImageUrl
val targetImageView = viewHolder.itemView.imageViewFrom
Picasso.get().load(uri).into(targetImageView)
viewHolder.itemView.textViewFrom.text = text
}
}
class ChatToItem(val text: String, val user: User) : Item<ViewHolder>() {
override fun getLayout(): Int {
return R.layout.chat_to_row
}
override fun bind(viewHolder: ViewHolder, position: Int) {
val uri = user.profileImageUrl
val targetImageView = viewHolder.itemView.imageViewTo
Picasso.get().load(uri).into(targetImageView)
viewHolder.itemView.textViewTo.text = text
}
}
And this is the ChatMessage, class that store the messages.
class ChatMessage(val id:String, val text: String, val fromId: String, val toId: String, val timeStamp: Long) {
constructor(): this("", "", "", "", -1)
}
I'm very glad if anyone can help this problem. Thank you

Resources