i m new to kotlin and i am trying to send bitmap. like i in recyclerview card i add an image and after that i have to edit the card so for that how can i send the bitmap there can anyone please help me in this. Thanks in advance.
here is my code:
MainActivity.kt:-
package com.example.itemgetset
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.os.Handler
import android.os.Message
import android.util.Log
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.widget.Button
import android.widget.LinearLayout
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
#Suppress("DEPRECATION")
class MainActivity : AppCompatActivity() {
lateinit var activity: Activity
val userList = ArrayList<ProductInfoGetSet>()
private lateinit var btnProductAdd: Button
lateinit var llEmptyView: LinearLayout
lateinit var llMain: LinearLayout
lateinit var recyclerView: RecyclerView
private lateinit var llFab: LinearLayout
private lateinit var linearLayoutManager: LinearLayoutManager
private lateinit var gridLayoutManager: GridLayoutManager
private lateinit var adapter: CustomAdapter
companion object {
var handler: Handler = Handler()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
activity = this
initView()
onClicks()
setUpData()
handler = #SuppressLint("HandlerLeak")
object : Handler() {
override fun handleMessage(msg: Message) {
if (msg.what == 111) {
val temp: Temp = msg.obj as Temp
if (temp.id == "") {
userList.add(
ProductInfoGetSet(
(userList.size + 1).toString(),
temp.image,
temp.name,
temp.quantity,
temp.price,
temp.total
)
)
adapter = CustomAdapter(activity, userList)
recyclerView.adapter = adapter
} else {
for (i in userList.indices) {
if (userList[i].id == temp.id) {
userList[i].id = temp.id
userList[i].image = temp.image
userList[i].name = temp.name
userList[i].quantity = temp.quantity
userList[i].price = temp.price
userList[i].total = temp.total
}
}
adapter.notifyDataSetChanged()
}
}
if (userList.size > 0) {
llEmptyView.visibility = View.GONE
llMain.visibility = View.VISIBLE
} else {
llEmptyView.visibility = View.VISIBLE
llMain.visibility = View.GONE
}
}
}
}
private fun changeLayoutManager() {
if (recyclerView.layoutManager == linearLayoutManager) {
recyclerView.layoutManager = gridLayoutManager
} else {
recyclerView.layoutManager = linearLayoutManager
}
}
override fun onWindowFocusChanged(hasFocus: Boolean) {
super.onWindowFocusChanged(hasFocus)
if (hasFocus) Toast.makeText(applicationContext, "Phone Rotated", Toast.LENGTH_SHORT).show()
}
private fun initView() {
btnProductAdd = findViewById(R.id.btn_product_add)
llFab = findViewById(R.id.ll_fab)
llEmptyView = findViewById(R.id.llEmptyView)
llMain = findViewById(R.id.llMain)
recyclerView = findViewById(R.id.recycler_view)
recyclerView.layoutManager = LinearLayoutManager(this)
linearLayoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
gridLayoutManager = GridLayoutManager(this, 2)
}
private fun onClicks() {
btnProductAdd.setOnClickListener {
val intent = Intent(this#MainActivity, AddDetails::class.java)
intent.putExtra("isFor", "Add")
startActivity(intent)
}
llFab.setOnClickListener {
val intent = Intent(this#MainActivity, AddDetails::class.java)
intent.putExtra("isFor", "Add")
startActivity(intent)
}
}
private fun setUpData() {
if (userList.size > 0) {
llEmptyView.visibility = View.GONE
llMain.visibility = View.VISIBLE
} else {
llEmptyView.visibility = View.VISIBLE
llMain.visibility = View.GONE
}
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menu_main, menu)
return true
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == R.id.menu_view) {
if (userList.size > 0) {
changeLayoutManager()
}
return true
}
return super.onOptionsItemSelected(item)
}
}
CustomeAdapter.kt: -
package com.example.itemgetset
import android.R.attr.bitmap
import android.app.Activity
import android.app.AlertDialog
import android.content.ContentValues.TAG
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.Bitmap.CompressFormat
import android.os.Build
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.PopupMenu
import android.widget.TextView
import androidx.annotation.RequiresApi
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.snackbar.Snackbar
import java.io.ByteArrayOutputStream
#Suppress("UNREACHABLE_CODE")
class CustomAdapter(
private var activity: Activity,
private val userList: ArrayList<ProductInfoGetSet>,
) :
RecyclerView.Adapter<CustomAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val itemview =
LayoutInflater.from(parent.context).inflate(R.layout.list_layout, parent, false)
return ViewHolder(itemview)
}
#RequiresApi(Build.VERSION_CODES.N)
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val productInfoGetSet: ProductInfoGetSet = userList[position]
holder.txtId.text = productInfoGetSet.id
holder.txtName.text = productInfoGetSet.name
holder.txtQuantity.text = productInfoGetSet.quantity
holder.txtPrice.text = productInfoGetSet.price
holder.txtTotal.text = productInfoGetSet.total
holder.imgList.setImageBitmap(productInfoGetSet.image)
val id = userList[position].id
Log.e(TAG, "List item ID: $id")
holder.buttonViewOption.setOnClickListener {
val popup = PopupMenu(activity, holder.buttonViewOption)
popup.inflate(R.menu.pop_menu)
popup.setOnMenuItemClickListener { item ->
when (item.itemId) {
R.id.edit -> {
val intent = Intent(activity, AddDetails::class.java)
intent.putExtra("isFor", "Update")
val bStream = ByteArrayOutputStream()
productInfoGetSet.image?.compress(CompressFormat.PNG, 100, bStream)
val byteArray = bStream.toByteArray()
intent.putExtra("imagebitmap", byteArray)
intent.putExtra("id", productInfoGetSet.id)
intent.putExtra("name", productInfoGetSet.name)
intent.putExtra("quantity", productInfoGetSet.quantity)
intent.putExtra("price", productInfoGetSet.price)
intent.putExtra("total", productInfoGetSet.total)
activity.startActivity(intent)
}
R.id.delete -> {
val builder = AlertDialog.Builder(activity)
builder.setTitle("Delete")
builder.setMessage("Do you want to delete the item?")
builder.setPositiveButton("Yes") { _, _ ->
userList.removeAt(position)
notifyItemRemoved(position)
val snack = Snackbar
.make(
holder.linearly,
"Item was removed from the list.",
Snackbar.LENGTH_SHORT
)
snack.show()
}
builder.setNegativeButton("No") { _, _ ->
}
val dialog: AlertDialog = builder.create()
dialog.show()
}
}
false
}
popup.show()
}
}
override fun getItemId(position: Int): Long {
return position.toLong()
}
override fun getItemCount(): Int {
return userList.size
}
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val txtName = itemView.findViewById(R.id.txt_name) as TextView
val txtId = itemView.findViewById(R.id.txt_id) as TextView
var imgList = itemView.findViewById(R.id.img_list) as ImageView
val txtQuantity = itemView.findViewById(R.id.txt_quantity) as TextView
val txtPrice = itemView.findViewById(R.id.txt_price) as TextView
val txtTotal = itemView.findViewById(R.id.txt_result1) as TextView
val linearly: LinearLayout = itemView.findViewById(R.id.linearlayout)
val buttonViewOption = itemView.findViewById<View>(R.id.txt_Options) as TextView
}
}
AddDetails:-
package com.example.itemgetset
import android.annotation.SuppressLint
import android.content.Intent
import android.content.pm.PackageManager
import android.database.Cursor
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.os.Message
import android.provider.MediaStore
import android.text.Editable
import android.text.TextWatcher
import android.util.Log
import android.widget.*
import androidx.appcompat.app.AppCompatActivity
#Suppress("DEPRECATION")
class AddDetails : AppCompatActivity() {
private lateinit var btnSubmit: Button
private lateinit var edtName: EditText
private lateinit var img_add: ImageView
private var edtQuantity: EditText? = null
private var edtPrice: EditText? = null
private var txtResult: TextView? = null
private var txtTotal: TextView? = null
private var bitmap: Bitmap? = null
companion object {
private const val IMAGE_PICK_CODE = 1000
private const val PERMISSION_CODE = 1001
}
#SuppressLint("SetTextI18n", "ResourceType")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.add_item)
supportActionBar?.hide()
findViewById()
onclick()
edtPrice?.addTextChangedListener(priceWatcher)
edtQuantity?.addTextChangedListener(textWatcher)
if (intent.getStringExtra("isFor").equals("Update")) {
val byteArray = intent.getByteArrayExtra("imagebitmap")
bitmap = byteArray?.size?.let { BitmapFactory.decodeByteArray(byteArray, 0, it) }
img_add.setImageBitmap(bitmap)
edtName.setText(intent.getStringExtra("name"))
edtQuantity?.setText(intent.getStringExtra("quantity"))
edtPrice?.setText(intent.getStringExtra("price"))
}
}
private fun findViewById() {
btnSubmit = findViewById(R.id.btn_submit)
txtResult = findViewById(R.id.txt_result)
txtTotal = findViewById(R.id.txt_final)
edtName = findViewById(R.id.edt_name)
edtQuantity = findViewById(R.id.edt_quantity)
edtPrice = findViewById(R.id.edt_price)
img_add = findViewById(R.id.img_add)
}
#SuppressLint("ResourceType")
private fun onclick() {
btnSubmit.setOnClickListener {
when {
edtName.text.trim().isEmpty() -> {
edtName.error = "Please Enter Product Name"
Toast.makeText(
applicationContext,
"Please Enter Product Name",
Toast.LENGTH_SHORT
)
.show()
}
edtQuantity?.text?.trim()?.isEmpty()!! -> {
edtQuantity?.error = "Please Enter Product Quantity"
Toast.makeText(
applicationContext,
"Please Enter Product Quantity",
Toast.LENGTH_SHORT
).show()
}
edtPrice?.text?.trim()?.isEmpty()!! -> {
edtPrice?.error = "Please Enter Product Price"
Toast.makeText(
applicationContext,
"Please Enter Product Price",
Toast.LENGTH_SHORT
)
.show()
}
else -> {
Toast.makeText(
applicationContext,
"Product Added Successfully ",
Toast.LENGTH_SHORT
).show()
val temp = Temp()
temp.image = bitmap
temp.name = edtName.text.toString()
temp.quantity = edtQuantity?.text.toString()
temp.price = edtPrice?.text.toString()
temp.total = txtResult?.text.toString()
if (intent.getStringExtra("isFor").equals("Update")) {
temp.id = intent.getStringExtra("id").toString()
}
val message: Message = Message.obtain()
message.what = 111
message.obj = temp
MainActivity.handler.sendMessage(message)
finish()
}
}
}
img_add.setOnClickListener {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (checkSelfPermission(android.Manifest.permission.READ_EXTERNAL_STORAGE) ==
PackageManager.PERMISSION_DENIED
) {
val permissions = arrayOf(android.Manifest.permission.READ_EXTERNAL_STORAGE)
requestPermissions(permissions, PERMISSION_CODE)
} else {
pickImageFromGallery()
}
} else {
pickImageFromGallery()
}
}
}
private val priceWatcher = object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
override fun afterTextChanged(s: Editable?) {
val num1: String = edtPrice?.text.toString()
val mnum1 = num1.toIntOrNull()
val num2: String = edtQuantity?.text.toString()
val mnum2 = num2.toIntOrNull()
val res = mnum2?.let { mnum1?.times(it) }
Log.e("<><> res1", res.toString())
txtResult?.text = res.toString()
}
}
private val textWatcher = object : TextWatcher {
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {
}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
}
override fun afterTextChanged(s: Editable?) {
val num1: String = edtPrice?.text.toString()
val mnum1 = num1.toIntOrNull()
val num2: String = edtQuantity?.text.toString()
val mnum2 = num2.toIntOrNull()
val res = mnum2?.let { mnum1?.times(it) }
Log.e("<><> res1", res.toString())
txtResult?.text = res.toString()
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray,
) {
when (requestCode) {
PERMISSION_CODE -> {
if (grantResults.isNotEmpty() && grantResults[0] ==
PackageManager.PERMISSION_GRANTED
) {
pickImageFromGallery()
} else {
Toast.makeText(this, "Permission denied", Toast.LENGTH_SHORT).show()
}
}
}
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}
private fun pickImageFromGallery() {
val intent = Intent(Intent.ACTION_PICK)
intent.type = "image/*"
startActivityForResult(intent, IMAGE_PICK_CODE)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == IMAGE_PICK_CODE && resultCode == RESULT_OK && data != null) {
img_add.setImageURI(data.data)
val pickedImage: Uri? = data.data
val filePath = arrayOf(MediaStore.Images.Media.DATA)
val cursor: Cursor? =
pickedImage?.let { contentResolver.query(it, filePath, null, null, null) }
cursor?.moveToFirst()
val imagePath: String = cursor!!.getString(cursor.getColumnIndex(filePath[0]))
val options = BitmapFactory.Options()
options.inPreferredConfig = Bitmap.Config.ARGB_8888
bitmap = BitmapFactory.decodeFile(imagePath, options)
cursor.close()
}
}
}
Logcat: -
2020-09-14 19:46:21.834 26263-26263/? E/mple.itemgetse: Unknown bits set in runtime_flags: 0x28000
2020-09-14 19:46:43.406 26263-26263/com.example.itemgetset E/<><> res1: null
2020-09-14 19:46:43.754 26263-26263/com.example.itemgetset E/<><> res1: null
2020-09-14 19:46:45.992 26263-26263/com.example.itemgetset E/<><> res1: 32
2020-09-14 19:46:47.908 26263-26263/com.example.itemgetset E/<><> res1: null
2020-09-14 19:46:48.491 26263-26263/com.example.itemgetset E/<><> res1: 64
2020-09-14 19:46:51.002 26263-26263/com.example.itemgetset E/ContentValues: List item ID: 1
2020-09-14 19:46:54.533 26263-26263/com.example.itemgetset E/ContentValues: List item ID: 1
2020-09-14 19:46:55.167 26263-26263/com.example.itemgetset E/ContentValues: List item ID: 1
2020-09-14 19:47:02.993 26263-26263/com.example.itemgetset E/JavaBinder: !!! FAILED BINDER TRANSACTION !!! (parcel size = 16777976)
2020-09-14 19:47:02.995 26263-26263/com.example.itemgetset E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.itemgetset, PID: 26263
java.lang.RuntimeException: Failure from system
at android.app.Instrumentation.execStartActivity(Instrumentation.java:1904)
at android.app.Activity.startActivityForResult(Activity.java:5215)
at androidx.fragment.app.FragmentActivity.startActivityForResult(FragmentActivity.java:676)
at android.app.Activity.startActivityForResult(Activity.java:5173)
at androidx.fragment.app.FragmentActivity.startActivityForResult(FragmentActivity.java:663)
at android.app.Activity.startActivity(Activity.java:5544)
at android.app.Activity.startActivity(Activity.java:5512)
at com.example.itemgetset.CustomAdapter$onBindViewHolder$1$1.onMenuItemClick(CustomAdapter.kt:69)
at android.widget.PopupMenu$1.onMenuItemSelected(PopupMenu.java:108)
at com.android.internal.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:787)
at com.android.internal.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:151)
at com.android.internal.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:934)
at com.android.internal.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:924)
at com.android.internal.view.menu.MenuPopup.onItemClick(MenuPopup.java:128)
at android.widget.AdapterView.performItemClick(AdapterView.java:330)
at android.widget.AbsListView.performItemClick(AbsListView.java:1257)
at android.widget.AbsListView$PerformClick.run(AbsListView.java:3265)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7707)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:516)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)
Caused by: android.os.TransactionTooLargeException: data parcel size 16777976 bytes
at android.os.BinderProxy.transactNative(Native Method)
at android.os.BinderProxy.transact(BinderProxy.java:557)
at android.app.IActivityTaskManager$Stub$Proxy.startActivity(IActivityTaskManager.java:3887)
at android.app.Instrumentation.execStartActivity(Instrumentation.java:1898)
at android.app.Activity.startActivityForResult(Activity.java:5215)
at androidx.fragment.app.FragmentActivity.startActivityForResult(FragmentActivity.java:676)
at android.app.Activity.startActivityForResult(Activity.java:5173)
at androidx.fragment.app.FragmentActivity.startActivityForResult(FragmentActivity.java:663)
at android.app.Activity.startActivity(Activity.java:5544)
at android.app.Activity.startActivity(Activity.java:5512)
at com.example.itemgetset.CustomAdapter$onBindViewHolder$1$1.onMenuItemClick(CustomAdapter.kt:69)
at android.widget.PopupMenu$1.onMenuItemSelected(PopupMenu.java:108)
at com.android.internal.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:787)
at com.android.internal.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:151)
at com.android.internal.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:934)
at com.android.internal.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:924)
at com.android.internal.view.menu.MenuPopup.onItemClick(MenuPopup.java:128)
at android.widget.AdapterView.performItemClick(AdapterView.java:330)
at android.widget.AbsListView.performItemClick(AbsListView.java:1257)
at android.widget.AbsListView$PerformClick.run(AbsListView.java:3265)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7707)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:516)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:950)
From Customadpate to adddetails i have to send the bitmap.
In onActivityResult you receive the picked image Uri, this can then be passed from one activity to the next by converting the Uri to a string then attaching it to the intent with .putExtra(), as seen below:
val intent = Intent(this, Activity::class.java)
intent.putExtra("Uri", imageUri)
startActivity(intent)
The information can then be received in the next activity by:
if (intent.getStringExtra("Uri") != null){
val uri = intent.getStringExtra("Uri")
}
The Uri will be in string form so all you have to do is convert it back to Uri form.
To convert bitmap to Uri , use the code below:
public Uri getImageUri(Context inContext, Bitmap inImage) {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
inImage.compress(Bitmap.CompressFormat.JPEG, 100, bytes);
String path = MediaStore.Images.Media.insertImage(inContext.getContentResolver(), inImage, "Title", null);
return Uri.parse(path);
}
Related
My code gives me below error
package com.example.productsadder
import android.app.Activity
import android.content.Intent
import android.content.Intent.ACTION_GET_CONTENT
import android.graphics.Bitmap
import android.net.Uri
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.provider.MediaStore
import android.util.Log
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.lifecycle.lifecycleScope
import com.example.productsadder.databinding.ActivityMainBinding
import com.google.firebase.firestore.ktx.firestore
import com.google.firebase.ktx.Firebase
import com.google.firebase.storage.ktx.storage
import com.skydoves.colorpickerview.ColorEnvelope
import com.skydoves.colorpickerview.ColorPickerDialog
import com.skydoves.colorpickerview.listeners.ColorEnvelopeListener
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.async
import kotlinx.coroutines.launch
import kotlinx.coroutines.tasks.await
import kotlinx.coroutines.withContext
import java.io.ByteArrayOutputStream
import java.lang.Exception
import java.util.UUID
class MainActivity : AppCompatActivity() {
private val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }
private var selectedImages = mutableListOf<Uri>()
private val selectedColors = mutableListOf<Int>()
private val firestore = Firebase.firestore
private val productsStorage = Firebase.storage.reference
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(binding.root)
binding.buttonColorPicker.setOnClickListener{
ColorPickerDialog.Builder(this)
.setTitle("Product color")
.setPositiveButton("Select", object : ColorEnvelopeListener{
override fun onColorSelected(envelope: ColorEnvelope?, fromUser: Boolean) {
envelope?.let {
selectedColors.add(it.color)
updateColor()
}
}
})
.setNegativeButton("Cancel"){ colorPicker, _ ->
colorPicker.dismiss()
}.show()
}
val selectImagesActivityResult =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()){ result ->
if(result.resultCode == Activity.RESULT_OK){
val intent = result.data
if(intent?.clipData != null){
val count = intent.clipData?.itemCount ?: 0
(0 until count).forEach{
val imageUri = intent.clipData?.getItemAt(it)?.uri
imageUri?.let{
selectedImages.add(it)
}
}
} else {
val imageUri = intent?.data
imageUri?.let { selectedImages.add(it) }
}
updateImages()
}
}
binding.buttonImagesPicker.setOnClickListener{
val intent = Intent(ACTION_GET_CONTENT)
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true)
intent.type = "image/*"
selectImagesActivityResult.launch(intent)
}
}
private fun updateColor(){
var colors = ""
selectedColors.forEach{
colors = "$colors ${Integer.toHexString(it)}"
}
binding.tvSelectedColors.text = colors
}
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
menuInflater.inflate(R.menu.toolbar_menu, menu)
return true
}
private fun updateImages(){
binding.tvSelectedImages.text = selectedImages.size.toString()
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if(item.itemId == R.id.saveProduct){
val productValidation = validateInformation()
if (!productValidation){
Toast.makeText(this, "Check your inputs", Toast.LENGTH_SHORT).show()
return false
}
saveProducts() {
Log.d("test", it.toString())
}
}
return super.onOptionsItemSelected(item)
}
private fun saveProducts(state: (Boolean) -> Unit){
val name = binding.edName.text.toString().trim()
val category = binding.edCategory.text.toString().trim()
val price = binding.edPrice.text.toString().trim()
val offerPercentage = binding.offerPercentage.text.toString().trim()
val description = binding.edDescription.text.toString().trim()
val sizes = getSizesList(binding.edSizes.text.toString().trim())
val imagesByteArrays = getImagesByteArrays()
val images = mutableListOf<String>()
lifecycleScope.launch(Dispatchers.IO){
withContext(Dispatchers.Main){
showLoading()
}
try{
async {
imagesByteArrays.forEach{
val id = UUID.randomUUID().toString()
launch {
val imageStorage = productsStorage.child("products/images/$id")
val result = imageStorage.putBytes(it).await()
val downloadUrl = result.storage.downloadUrl.await().toString()
images.add(downloadUrl)
}
}
}.await()
}catch (e: Exception){
e.printStackTrace()
withContext(Dispatchers.Main){
hideLoading()
}
}
val product = Product(
UUID.randomUUID().toString(),
name,
category,
price.toFloat(),
if(offerPercentage.isEmpty()) null else offerPercentage.toFloat(),
if(description.isEmpty()) null else description,
if (selectedColors.isEmpty()) null else selectedColors,
sizes,
images,
)
firestore.collection("Products").add(product).addOnSuccessListener {
hideLoading()
} .addOnFailureListener{
hideLoading()
Log.e("Error", it.message.toString())
}
}
}
private fun hideLoading() {
binding.progressbar.visibility = View.INVISIBLE
}
private fun showLoading() {
binding.progressbar.visibility = View.VISIBLE
}
private fun getImagesByteArrays(): List<ByteArray>{
val imagesByteArray = mutableListOf<ByteArray>()
selectedImages.forEach{
val stream = ByteArrayOutputStream()
val imageBmp = MediaStore.Images.Media.getBitmap(contentResolver,it)
if (imageBmp.compress(Bitmap.CompressFormat.JPEG,100,stream)){
imagesByteArray.add(stream.toByteArray())
}
}
return imagesByteArray
}
private fun getSizesList(sizesStr:String): List<String>? {
if (sizesStr.isEmpty())
return null
val sizesList = sizesStr.split(",")
return sizesList
}
private fun validateInformation(): Boolean{
if(binding.edPrice.text.toString().trim().isEmpty())
return false
if(binding.edName.text.toString().trim().isEmpty())
return false
if(binding.edCategory.text.toString().trim().isEmpty())
return false
if (selectedImages.isEmpty())
return false
return true
}
}
This is the error i get
E/AndroidRuntime: FATAL EXCEPTION: DefaultDispatcher-worker-1
Process: com.example.productsadder, PID: 20855
com.google.firebase.storage.StorageException: Object does not exist at location.
at com.google.firebase.storage.UploadTask.snapStateImpl(UploadTask.java:573)
at com.google.firebase.storage.UploadTask.snapStateImpl(UploadTask.java:57)
at com.google.firebase.storage.StorageTask.snapState(StorageTask.java:343)
at com.google.firebase.storage.StorageTask.getFinalResult(StorageTask.java:453)
at com.google.firebase.storage.StorageTask.getException(StorageTask.java:313)
at kotlinx.coroutines.tasks.TasksKt$awaitImpl$2$1.onComplete(Tasks.kt:142)
at com.google.firebase.storage.StorageTask.lambda$new$2$com-google-firebase-storage-StorageTask(StorageTask.java:143)
at com.google.firebase.storage.StorageTask$$ExternalSyntheticLambda11.raise(Unknown Source:6)
at com.google.firebase.storage.TaskListenerImpl.lambda$onInternalStateChanged$2$com-google-firebase-storage-TaskListenerImpl(TaskListenerImpl.java:90)
at com.google.firebase.storage.TaskListenerImpl$$ExternalSyntheticLambda0.run(Unknown Source:6)
at kotlinx.coroutines.tasks.DirectExecutor.execute(Tasks.kt:164)
at com.google.firebase.storage.internal.SmartHandler.callBack(SmartHandler.java:70)
at com.google.firebase.storage.TaskListenerImpl.onInternalStateChanged(TaskListenerImpl.java:90)
at com.google.firebase.storage.StorageTask.tryChangeState(StorageTask.java:392)
at com.google.firebase.storage.StorageTask.tryChangeState(StorageTask.java:426)
at com.google.firebase.storage.UploadTask.serverStateValid(UploadTask.java:361)
at com.google.firebase.storage.UploadTask.shouldContinue(UploadTask.java:324)
at com.google.firebase.storage.UploadTask.run(UploadTask.java:245)
at com.google.firebase.storage.StorageTask.lambda$getRunnable$7$com-google-firebase-storage-StorageTask(StorageTask.java:1072)
at com.google.firebase.storage.StorageTask$$ExternalSyntheticLambda7.run(Unknown Source:2)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1137)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:637)
at java.lang.Thread.run(Thread.java:1012)
Suppressed: com.google.firebase.storage.StorageException: Object does not exist at location.
... 23 more
Caused by: java.io.IOException: The server has terminated the upload session
at com.google.firebase.storage.UploadTask.serverStateValid(UploadTask.java:358)
... 7 more
Caused by: java.io.IOException: { "error": { "code": 404, "message": "Not Found." }}
at com.google.firebase.storage.network.NetworkRequest.parseResponse(NetworkRequest.java:445)
at com.google.firebase.storage.network.NetworkRequest.parseErrorResponse(NetworkRequest.java:462)
at com.google.firebase.storage.network.NetworkRequest.processResponseStream(NetworkRequest.java:453)
at com.google.firebase.storage.network.NetworkRequest.performRequest(NetworkRequest.java:272)
at com.google.firebase.storage.network.NetworkRequest.performRequest(NetworkRequest.java:289)
at com.google.firebase.storage.internal.ExponentialBackoffSender.sendWithExponentialBackoff(ExponentialBackoffSender.java:76)
at com.google.firebase.storage.internal.ExponentialBackoffSender.sendWithExponentialBackoff(ExponentialBackoffSender.java:68)
at com.google.firebase.storage.UploadTask.sendWithRetry(UploadTask.java:526)
at com.google.firebase.storage.UploadTask.beginResumableUpload(UploadTask.java:292)
at com.google.firebase.storage.UploadTask.run(UploadTask.java:240)
... 5 more
Suppressed: kotlinx.coroutines.DiagnosticCoroutineContextException: [StandaloneCoroutine{Cancelling}#edc0c51, Dispatchers.IO]
Caused by: java.io.IOException: The server has terminated the upload session
at com.google.firebase.storage.UploadTask.serverStateValid(UploadTask.java:358)
... 7 more
Caused by: java.io.IOException: { "error": { "code": 404, "message": "Not Found." }}
E/AndroidRuntime: at com.google.firebase.storage.network.NetworkRequest.parseResponse(NetworkRequest.java:445)
at com.google.firebase.storage.network.NetworkRequest.parseErrorResponse(NetworkRequest.java:462)
at com.google.firebase.storage.network.NetworkRequest.processResponseStream(NetworkRequest.java:453)
at com.google.firebase.storage.network.NetworkRequest.performRequest(NetworkRequest.java:272)
at com.google.firebase.storage.network.NetworkRequest.performRequest(NetworkRequest.java:289)
at com.google.firebase.storage.internal.ExponentialBackoffSender.sendWithExponentialBackoff(ExponentialBackoffSender.java:76)
at com.google.firebase.storage.internal.ExponentialBackoffSender.sendWithExponentialBackoff(ExponentialBackoffSender.java:68)
at com.google.firebase.storage.UploadTask.sendWithRetry(UploadTask.java:526)
at com.google.firebase.storage.UploadTask.beginResumableUpload(UploadTask.java:292)
at com.google.firebase.storage.UploadTask.run(UploadTask.java:240)
... 5 more
Below is my app_bar_main file which contains a toolbar and fab to create boards.
This layout file is included from main_content, which has a recycler view.
app_bar_main
<?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"
tools:context=".activities.MainActivity">
<com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="#style/Theme.Manageio.AppBarOverlay">
<androidx.appcompat.widget.Toolbar
android:id="#+id/toolbar_main_activity"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="#style/Theme.Manageio.PopUpOverlay" />
</com.google.android.material.appbar.AppBarLayout>
<include layout="#layout/main_content" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/fab_createBoard"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="24dp"
app:srcCompat="#drawable/ic_vector_add"
android:background="#color/primaryColor" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
main_content
<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="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:background="#color/lightPrimaryColor"
android:orientation="vertical"
android:padding="16dp"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:context=".activities.MainActivity">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white"
android:elevation="5dp"
app:cardCornerRadius="10dp">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rv_boardList"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:item_layout="#layout/item_board"
android:visibility="gone"
/>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/tv_noBoardsAvailable"
android:gravity="center"
android:textSize="32sp"
android:fontFamily="#font/boogaloo"
android:textColor="#color/secondaryText"
android:text="No Boards Available!"/>
</androidx.cardview.widget.CardView>
</LinearLayout>
Now whenever I click on fab it takes me to CreateBoardActivity which creates boards and store it in the firestore
CreateBoardActivity
import android.Manifest
import android.app.Activity
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.bumptech.glide.Glide
import com.example.manageio.R
import com.example.manageio.firebase.FirestoreClass
import com.example.manageio.models.Board
import com.example.manageio.utils.Constants
import com.google.firebase.storage.FirebaseStorage
import com.google.firebase.storage.StorageReference
import kotlinx.android.synthetic.main.activity_create_board.*
import kotlinx.android.synthetic.main.activity_profile.*
import java.io.IOException
class CreateBoardActivity : BaseActivity() {
private var mSelectedImageFileUri : Uri?= null
private lateinit var mUserName : String
private var mBoardImageURL : String = ""
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_create_board)
if(intent.hasExtra(Constants.NAME)){
mUserName = intent.getStringExtra(Constants.NAME).toString()
}
iv_boardImage.setOnClickListener {
if (ContextCompat.checkSelfPermission(
this,
Manifest.permission.READ_EXTERNAL_STORAGE
) == PackageManager.PERMISSION_GRANTED
) {
Constants.showImageChooser(this)
} else {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE),
Constants.READ_STORAGE_PERMISSION_CODE
)
}
}
createBoard_createBtn.setOnClickListener {
if(mSelectedImageFileUri!=null){
uploadBoardImage()
}else{
showProgressDialog(resources.getString(R.string.please_wait))
createBoard()
}
}
}
private fun createBoard(){
val assignedUserArrayList : ArrayList<String> = ArrayList()
assignedUserArrayList.add(getCurrentUserId())
var board = Board(
createBoard_et_boardName.text.toString(),
mBoardImageURL,
mUserName,
assignedUserArrayList
)
FirestoreClass().createBoard(this,board)
}
private fun uploadBoardImage(){
showProgressDialog(resources.getString(R.string.please_wait))
val sRef: StorageReference = FirebaseStorage.getInstance()
.reference.child(
"BOARD_IMAGE" + System.currentTimeMillis() + "." +
Constants.getFileExtension(this,mSelectedImageFileUri!!)
)
sRef.putFile(mSelectedImageFileUri!!).addOnSuccessListener { taskSnapshot ->
Log.i(
"FirebaseBoardImageUrl",
taskSnapshot.metadata!!.reference!!.downloadUrl.toString()
)
taskSnapshot.metadata!!.reference!!.downloadUrl.addOnSuccessListener { uri ->
Log.i("DownloadBoardImageUrl", uri.toString())
mBoardImageURL = uri.toString()
createBoard()
}
}.addOnFailureListener { exception ->
Toast.makeText(this#CreateBoardActivity, exception.message, Toast.LENGTH_LONG).show()
hideProgressDialog()
}
}
fun boardCreatedSuccessfully(){
hideProgressDialog()
setResult(Activity.RESULT_OK)
finish()
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == Constants.READ_STORAGE_PERMISSION_CODE) {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
Constants.showImageChooser(this)
} else {
Toast.makeText(
this,
"You denied the permission for storage.You can allow it from settings",
Toast.LENGTH_LONG
).show()
}
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK && requestCode == Constants.PICK_IMAGE_REQUEST_CODE && data!!.data != null) {
mSelectedImageFileUri = data.data
try {
Glide
.with(this)
.load(mSelectedImageFileUri)
.centerCrop()
.placeholder(R.color.lightPrimaryColor)
.into(iv_boardImage)
} catch (e: IOException) {
e.printStackTrace()
}
}
}
}
FireStoreClass
import android.app.Activity
import android.util.Log
import android.widget.Toast
import com.example.manageio.activities.*
import com.example.manageio.models.Board
import com.example.manageio.models.User
import com.example.manageio.utils.Constants
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.firestore.FirebaseFirestore
import com.google.firebase.firestore.SetOptions
class FirestoreClass {
private val mFireStore = FirebaseFirestore.getInstance()
fun getBoardDetails(activity: TaskListActivity, documentId: String) {
mFireStore.collection(Constants.BOARDS)
.document(documentId)
.get()
.addOnSuccessListener { document ->
val board = document.toObject(Board::class.java)!!
board.documentId = document.id
activity.boardDetails(board)
}.addOnFailureListener { e ->
activity.hideProgressDialog()
Log.e("FirestoreClass", "Error with exception ", e)
}
}
fun createBoard(activity: CreateBoardActivity, board: Board) {
mFireStore.collection(Constants.BOARDS)
.document()
.set(board, SetOptions.merge())
.addOnSuccessListener {
Toast.makeText(activity, "Board Created Successfully", Toast.LENGTH_SHORT).show()
activity.boardCreatedSuccessfully()
}.addOnFailureListener { e ->
activity.hideProgressDialog()
Log.e("FirestoreClass", "Error with exception ", e)
}
}
fun getBoardsList(activity: MainActivity) {
mFireStore.collection(Constants.BOARDS)
.whereArrayContains(Constants.ASSIGNED_TO, getCurrentUserId())
.get()
.addOnSuccessListener { document ->
val boardlist: ArrayList<Board> = ArrayList()
for (i in document.documents) {
val board = i.toObject(Board::class.java)!!
board.documentId = i.id
boardlist.add(board)
}
activity.populateBoardsListToUI(boardlist)
}.addOnFailureListener { e ->
activity.hideProgressDialog()
Log.e("FireStoreClass", "Error while creating board.", e)
}
}
fun updateUserProfileData(activity: Activity, userHashMap: HashMap<String, Any>) {
mFireStore.collection(Constants.USERS)
.document(getCurrentUserId())
.update(userHashMap)
.addOnSuccessListener {
Log.i("FirestoreClass", "Profile Data Updated Successfully")
Toast.makeText(
activity,
"You profile has been updated successfully",
Toast.LENGTH_SHORT
).show()
when(activity){
is MainActivity ->{
activity.tokenUpdateSuccess()
}
is ProfileActivity ->{
activity.profileUpdateSuccess()
}
}
}.addOnFailureListener { e ->
when(activity){
is MainActivity ->{
activity.hideProgressDialog()
}
is ProfileActivity ->{
activity.hideProgressDialog()
}
}
Log.e("FirestoreClass", "Error while updating profile", e)
Toast.makeText(activity, "Error while updating profile", Toast.LENGTH_SHORT).show()
}
}
fun loadUserData(activity: Activity, readBoardsList: Boolean = false) {
mFireStore.collection(Constants.USERS)
.document(getCurrentUserId())
.get()
.addOnSuccessListener { document ->
val loggedInUser = document.toObject(User::class.java)!!
when (activity) {
is LoginActivity -> {
activity.loginSuccess(loggedInUser)
}
is MainActivity -> {
activity.updateNavigationUserDetails(loggedInUser, readBoardsList)
}
is ProfileActivity -> {
activity.setUserDataInUi(loggedInUser)
}
}
}.addOnFailureListener { e ->
when (activity) {
is LoginActivity -> {
activity.hideProgressDialog()
}
is MainActivity -> {
activity.hideProgressDialog()
}
}
Log.e("FirestoreClass", "Error with exception $e")
}
}
fun getCurrentUserId(): String {
val currentUser = FirebaseAuth.getInstance().currentUser
var currentUserId = ""
if (currentUser != null) {
currentUserId = currentUser.uid
}
return currentUserId
}
fun assignMemberToBoard(activity: MembersActivity, board : Board, user : User){
val assignedToHashmap = HashMap<String,Any>()
assignedToHashmap[Constants.ASSIGNED_TO] = board.assignedTo
mFireStore.collection(Constants.BOARDS)
.document(board.documentId)
.update(assignedToHashmap)
.addOnSuccessListener {
activity.memberAssignSuccess(user)
}.addOnFailureListener { e ->
activity.hideProgressDialog()
Log.e("FirestoreClass", "Error while creating board",e)
}
}
}
Main Activity
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.SharedPreferences
import android.os.Bundle
import android.util.Log
import android.view.MenuItem
import android.view.View
import androidx.core.view.GravityCompat
import androidx.recyclerview.widget.LinearLayoutManager
import com.bumptech.glide.Glide
import com.example.manageio.R
import com.example.manageio.adapters.BoardItemsAdapter
import com.example.manageio.firebase.FirestoreClass
import com.example.manageio.models.Board
import com.example.manageio.models.User
import com.example.manageio.utils.Constants
import com.google.android.material.navigation.NavigationView
import com.google.firebase.FirebaseApp.getInstance
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.installations.FirebaseInstallations
import com.google.firebase.messaging.FirebaseMessaging
import com.google.firebase.messaging.FirebaseMessaging.getInstance
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.app_bar_main.*
import kotlinx.android.synthetic.main.main_content.*
import kotlinx.android.synthetic.main.nav_header_main.*
class MainActivity : BaseActivity(), NavigationView.OnNavigationItemSelectedListener {
companion object{
const val MY_PROFILE_REQUEST_CODE : Int = 99
const val CREATE_BOARD_REQUEST_CODE : Int =98
}
private lateinit var mUserName : String
private lateinit var mSharedPreferences : SharedPreferences
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setUpActionBar()
nav_view.setNavigationItemSelectedListener(this)
mSharedPreferences = this.getSharedPreferences(Constants.MANAGEIO_PREFERENCES, Context.MODE_PRIVATE)
val tokenUpdated = mSharedPreferences.getBoolean(Constants.FCM_TOKEN_UPDATED,false)
if(tokenUpdated){
showProgressDialog(resources.getString(R.string.please_wait))
FirestoreClass().loadUserData(this#MainActivity,true)
}
else{
FirebaseInstallations.getInstance().getToken(tokenUpdated).addOnSuccessListener(this#MainActivity){
instanceIdResult ->
updateFCMTOKEN(instanceIdResult.token)
}
}
// TODO Check 1
// FirestoreClass().loadUserData(this , true)
fab_createBoard.setOnClickListener{
val intent = Intent(this#MainActivity,CreateBoardActivity::class.java)
intent.putExtra(Constants.NAME,mUserName)
startActivityForResult(intent, CREATE_BOARD_REQUEST_CODE)
}
}
fun populateBoardsListToUI(boardsList : ArrayList<Board>){
hideProgressDialog()
if(boardsList.size > 0){
rv_boardList.visibility = View.VISIBLE
tv_noBoardsAvailable.visibility = View.GONE
rv_boardList.layoutManager = LinearLayoutManager(this)
rv_boardList.setHasFixedSize(true)
val adapter = BoardItemsAdapter(this,boardsList)
rv_boardList.adapter = adapter
adapter.setOnClickListener(object :BoardItemsAdapter.OnClickListener{
override fun onClick(position: Int, model: Board) {
val intent = Intent(this#MainActivity,TaskListActivity::class.java)
intent.putExtra(Constants.DOCUMENT_ID,model.documentId)
startActivity(intent)
}
})
}else{
rv_boardList.visibility = View.GONE
tv_noBoardsAvailable.visibility = View.VISIBLE
}
}
private fun setUpActionBar() {
setSupportActionBar(toolbar_main_activity)
toolbar_main_activity.setNavigationIcon(R.drawable.ic_nav_menu)
toolbar_main_activity.setNavigationOnClickListener {
toggleDrawer()
}
}
private fun toggleDrawer() {
if (drawer_layout.isDrawerOpen(GravityCompat.START)) {
drawer_layout.closeDrawer(GravityCompat.START)
} else {
drawer_layout.openDrawer(GravityCompat.START)
}
}
fun updateNavigationUserDetails(user: User, readBoardsList : Boolean){
hideProgressDialog()
mUserName = user.name
Glide
.with(this)
.load(user.image)
.centerCrop()
.placeholder(R.drawable.ic_nav_user)
.into(iv_userImage);
tv_username.text = user.name
if(readBoardsList){
showProgressDialog(resources.getString(R.string.please_wait))
FirestoreClass().getBoardsList(this)
}
}
override fun onBackPressed() {
if (drawer_layout.isDrawerOpen(GravityCompat.START)) {
drawer_layout.closeDrawer(GravityCompat.START)
} else {
doubleBackToExit()
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if(resultCode == Activity.RESULT_OK && requestCode == MY_PROFILE_REQUEST_CODE){
FirestoreClass().loadUserData(this)
}else if(resultCode == Activity.RESULT_OK && requestCode == CREATE_BOARD_REQUEST_CODE){
FirestoreClass().getBoardsList(this)
}
else{
Log.e("MainActivity", "Cancelled")
}
}
override fun onNavigationItemSelected(item: MenuItem): Boolean {
when(item.itemId){
R.id.nav_my_profile -> {
startActivityForResult(Intent(this#MainActivity,ProfileActivity::class.java),
MY_PROFILE_REQUEST_CODE)
}
R.id.nav_logout -> {
FirebaseAuth.getInstance().signOut()
mSharedPreferences.edit().clear().apply()
val intent = Intent(this,WelcomeActivity::class.java)
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
startActivity(intent)
finish()
}
}
drawer_layout.closeDrawer(GravityCompat.START)
return true
}
}
**BoardItemsAdapter
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.example.manageio.R
import com.example.manageio.firebase.FirestoreClass
import com.example.manageio.models.Board
import com.example.manageio.utils.Constants
import kotlinx.android.synthetic.main.item_board.view.*
open class BoardItemsAdapter(private val context: Context,private var list: ArrayList<Board>) : RecyclerView.Adapter<RecyclerView.ViewHolder>(){
private var onClickListener : OnClickListener ?= null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
return MyViewHolder(LayoutInflater.from(context).inflate(R.layout.item_board,parent,false))
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val model = list[position]
if(holder is MyViewHolder){
Glide
.with(context)
.load(model.image)
.centerCrop()
.placeholder(R.color.lightPrimaryColor)
.into(holder.itemView.iv_itemBoardImage)
holder.itemView.tv_name.text = model.name
holder.itemView.tv_createdBy.text = "Created By: ${model.createdBy}"
holder.itemView.setOnClickListener {
if(onClickListener!=null){
onClickListener!!.onClick(position,model)
}
}
}
}
interface OnClickListener{
fun onClick(position: Int,model : Board)
}
fun setOnClickListener(onClickListener: OnClickListener){
this.onClickListener = onClickListener
}
override fun getItemCount(): Int {
return list.size
}
private class MyViewHolder(view : View) : RecyclerView.ViewHolder(view)
}
Board(model)
package com.example.manageio.models
import android.os.Parcel
import android.os.Parcelable
data class Board(
val name : String = "",
val image : String = "",
val createdBy : String = "",
val assignedTo : ArrayList<String> = ArrayList(),
var documentId : String = "",
var taskList : ArrayList<Task> = ArrayList()
) : Parcelable {
constructor(parcel: Parcel) : this(
parcel.readString()!!,
parcel.readString()!!,
parcel.readString()!!,
parcel.createStringArrayList()!!,
parcel.readString()!!,
parcel.createTypedArrayList(Task.CREATOR)!!
)
override fun writeToParcel(parcel: Parcel, flags: Int) = with(parcel){
parcel.writeString(name)
parcel.writeString(image)
parcel.writeString(createdBy)
parcel.writeStringList(assignedTo)
parcel.writeString(documentId)
parcel.writeTypedList(taskList)
}
override fun describeContents(): Int {
return 0
}
companion object CREATOR : Parcelable.Creator<Board> {
override fun createFromParcel(parcel: Parcel): Board {
return Board(parcel)
}
override fun newArray(size: Int): Array<Board?> {
return arrayOfNulls(size)
}
}
}
And then the created boards are shown in the main activity
Please refer these images
Firestore Image
Main activity image
Not what I want is whenever I swipe one recycler view list then it should be deleted .
How to implement it so it also gets deleted from firestore?
And please don't mind the other functions which are not important. Actually it is my first time asking so i pasted it all there
You will need an ItemTouchHelper Callback Method in order to implement swipe to delete in Android Recycler view. something like this below
abstract class SwipeToDeleteCallback internal constructor(internal var mContext: Context) : ItemTouchHelper.Callback() {
private val mClearPaint: Paint
private val mBackground: ColorDrawable
private val backgroundColor: Int
private val deleteDrawable: Drawable?
private val intrinsicWidth: Int
private val intrinsicHeight: Int
init {
mBackground = ColorDrawable()
backgroundColor = Color.parseColor("#b80f0a")
mClearPaint = Paint()
mClearPaint.xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR)
deleteDrawable = ContextCompat.getDrawable(mContext, R.drawable.ic_delete)
intrinsicWidth = deleteDrawable!!.intrinsicWidth
intrinsicHeight = deleteDrawable.intrinsicHeight
}
override fun getMovementFlags(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder): Int {
return ItemTouchHelper.Callback.makeMovementFlags(0, ItemTouchHelper.LEFT)
}
override fun onMove(recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, viewHolder1: RecyclerView.ViewHolder): Boolean {
return false
}
override fun onChildDraw(
c: Canvas, recyclerView: RecyclerView, viewHolder: RecyclerView.ViewHolder, dX: Float,
dY: Float,
actionState: Int,
isCurrentlyActive: Boolean
) {
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
val itemView = viewHolder.itemView
val itemHeight = itemView.height
val isCancelled = dX == 0f && !isCurrentlyActive
if (isCancelled) {
clearCanvas(
c,
itemView.right + dX,
itemView.top + 0f,
itemView.right + 0f,
itemView.bottom + 0f
)
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
return
}
mBackground.color = backgroundColor
mBackground.setBounds(itemView.right + dX.toInt(), itemView.top, itemView.right, itemView.bottom)
mBackground.draw(c)
val deleteIconTop = itemView.top + (itemHeight - intrinsicHeight) / 2
val deleteIconMargin = (itemHeight - intrinsicHeight) / 2
val deleteIconLeft = itemView.right - deleteIconMargin - intrinsicWidth
val deleteIconRight = itemView.right - deleteIconMargin
val deleteIconBottom = deleteIconTop + intrinsicHeight
deleteDrawable!!.setBounds(deleteIconLeft, deleteIconTop, deleteIconRight, deleteIconBottom)
deleteDrawable.draw(c)
super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
}
private fun clearCanvas(c: Canvas, left: Float, top: Float, right: Float, bottom: Float) {
c.drawRect(left, top, right, bottom, mClearPaint)
}
override fun getSwipeThreshold(viewHolder: RecyclerView.ViewHolder): Float {
return 0.7f
}
}
Then you can use like this
recyclerView..addOnItemTouchListener(YourItemTouchHere)
Implement the onMove method. The to delete on firestore just set the value for the object path in firestore to FieldValue.delete() and it will be deleted
I have integrated mesibo chat and tried to integrate the mesibo push-notification but not receiving the notification. I had set up all the things related push notification and already success integrate with the backend also.
Not sure why i can't receive notification from mesibo related new chat and new call.
This is my code:
package com.project.bucynapp.ui.message
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.LinearLayoutManager
import com.mesibo.api.Mesibo.*
import com.mesibo.calls.api.MesiboCall
import com.project.bucynapp.R
import com.project.bucynapp.models.*
import com.project.bucynapp.ui.message.adapter.ChatListAdapter
import com.project.bucynapp.ui.message.presenter.ChatListPresenter
import com.project.bucynapp.ui.message.view.ChatListView
import com.project.bucynapp.utils.*
import com.squareup.picasso.Picasso
import kotlinx.android.synthetic.main.activity_chat_list.*
import kotlinx.android.synthetic.main.app_bar.toolbar
import kotlinx.android.synthetic.main.app_bar_chat_list.*
import kotlinx.android.synthetic.main.loading_view.*
class ChatListActivity : AppCompatActivity(), View.OnClickListener, ChatListView,
MessageListener, ConnectionListener, SyncListener {
private lateinit var presenter: ChatListPresenter
private lateinit var chatListAdapter: ChatListAdapter
private var chatList: MutableList<ChatModel> = mutableListOf()
private val layoutManager = LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
private lateinit var readSession: ReadDbSession
private var userMesibo: MesiboAccountData? = null
var userProfile: UserProfile? = null
private var imageProfile: String? = null
private var nameProfile: String? = null
private var userId: Int = 0
private var email: String? = null
companion object {
private const val USER_ID = "user_id"
private const val IMAGE_PROFILE = "img_profile"
private const val NAME_PROFILE = "name_profile"
private val TAG = ChatListActivity::class.java.canonicalName
fun startActivity(
context: Context,
userId: Int?,
imageProfile: String,
nameProfile: String
) {
Intent(context, ChatListActivity::class.java).apply {
putExtra(USER_ID, userId)
putExtra(IMAGE_PROFILE, imageProfile)
putExtra(NAME_PROFILE, nameProfile)
context.startActivity(this)
}
}
}
private val message: String
get() = edtSendChat.text.toString()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_chat_list)
initToolbar()
userMesibo = ApplicationPrefs.get(Constant.MESIBO_USER)
presenter = ChatListPresenter(this)
userId = intent.getIntExtra(USER_ID, 0)
imageProfile = intent.getStringExtra(IMAGE_PROFILE)
nameProfile = intent.getStringExtra(NAME_PROFILE)
chatListAdapter = ChatListAdapter(chatList)
rvChatList.adapter = chatListAdapter
rvChatList.layoutManager = layoutManager
rvChatList.addItemDecoration(DefaultItemDecoration(spacing = 10.dp, includeEdge = true))
tvName.text = nameProfile
Picasso.get().load(imageProfile)
.error(R.drawable.com_facebook_profile_picture_blank_square)
.placeholder(R.drawable.com_facebook_profile_picture_blank_square).into(imgProfile)
presenter.getEmailUser(userId)
}
private fun initToolbar() {
setSupportActionBar(toolbar)
val backArrow = ContextCompat.getDrawable(this, R.drawable.ic_back_black)
supportActionBar?.setHomeAsUpIndicator(backArrow)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
supportActionBar?.setDisplayShowHomeEnabled(true)
supportActionBar?.setDisplayShowTitleEnabled(false)
tvSeeProfile.setOnClickListener(this)
imgCalling.setOnClickListener(this)
imgVideoCall.setOnClickListener(this)
imgSendChat.setOnClickListener(this)
tilChat.setStartIconOnClickListener {
NotMatchActivity.startActivity(this)
}
}
override fun onSupportNavigateUp(): Boolean {
onBackPressed()
return true
}
override fun getChatListSuccess(response: MutableList<DataAttributes>) {
}
override fun getChatListFailed(message: String) {
}
override fun successPost(response: SuccessModel?) {
}
override fun failedPost(message: String) {
shortToast(message)
}
override fun onGetEmailUser(data: UserEmailResponse?) {
email = data?.email
startMesibo()
email?.let { loadFromDb(it) }
}
override fun onLoading(isShow: Boolean) {
if (isShow) {
rvChatList.gone()
loadingView.visible()
} else {
rvChatList.visible()
loadingView.gone()
}
}
override fun onNoData(msg: String?) {
shortToast(msg.toString())
}
override fun onBadRequest(msg: String?) {
shortToast(msg.toString())
}
override fun onUnauthorized(msg: String?) {
shortToast(msg.toString())
badToken()
}
override fun onClick(v: View?) {
when (v) {
imgSendChat -> if (message.isNotBlank()) onSendMessage()
tvSeeProfile -> {
UserProfileActivity.startActivity(this, userId)
}
imgCalling -> MesiboCall.getInstance().callUi(this, email, false)
imgVideoCall -> MesiboCall.getInstance().callUi(this, email, true)
}
}
override fun Mesibo_onMessage(p0: MessageParams?, p1: ByteArray?): Boolean {
val type: Int = if (p0?.isIncoming == true) 0 else 1
val msg = String(p1!!)
chatList.add(
ChatModel(
id = p0!!.mid,
msg = msg,
date = p0.ts,
type = type,
status = p0.status
)
)
chatListAdapter.notifyItemInserted(chatList.size)
layoutManager.scrollToPositionWithOffset(chatList.size - 1, 0)
return true
}
override fun Mesibo_onMessageStatus(p0: MessageParams?) {
chatList.find { p0?.mid == it.id }?.status = p0?.status
chatListAdapter.notifyDataSetChanged()
Log.i("TAG", "Mesibo_onMessageStatus: ${p0?.status}}")
}
override fun Mesibo_onActivity(p0: MessageParams?, p1: Int) {
Log.i("TAG", "Mesibo_onActivity: $p1")
when (p1) {
ACTIVITY_ONLINE -> {
imgDotOnline.visible()
imgDotOffline.gone()
Log.i(TAG, "MESIBO_ACTIVITY: activity on")
}
ACTIVITY_TYPING -> Log.i(TAG, "MESIBO_ACTIVITY: user typing")
else -> {
imgDotOnline.gone()
imgDotOffline.visible()
Log.i(TAG, "Mesibo_onActivity: $p1")
}
}
}
override fun Mesibo_onLocation(p0: MessageParams?, p1: Location?) {}
override fun Mesibo_onFile(p0: MessageParams?, p1: FileInfo?) {}
override fun Mesibo_onConnectionStatus(p0: Int) {
when (p0) {
STATUS_ONLINE -> {
setPushToken(ApplicationPrefs.tokenFcm)
tvConnectionStatus.gone()
Log.d(TAG, "MESIBO_CONNECTION_STATUS: online")
}
STATUS_OFFLINE -> {
tvConnectionStatus.gone()
Log.d(TAG, "MESIBO_CONNECTION_STATUS: offline")
}
STATUS_CONNECTING -> {
tvConnectionStatus.visible()
tvConnectionStatus.text = getString(R.string.connecting)
Log.d(TAG, "MESIBO_CONNECTION_STATUS: offline")
}
STATUS_CONNECTFAILURE, STATUS_NONETWORK -> {
tvConnectionStatus.visible()
tvConnectionStatus.text = getString(R.string.mesibo_connect_fail_msg)
}
else -> {
Log.d(TAG, "MESIBO_CONNECTION_STATUS: $p0")
Log.d(TAG, "MESIBO_TOKEN: ${userMesibo?.token}")
}
}
}
override fun Mesibo_onSync(p0: Int) {
if (p0 <= 0) return
readSession.read(p0)
}
private fun onSendMessage() {
val p = MessageParams()
p.profile = userProfile
p.peer = email
p.mid = random()
p.flag = FLAG_DELIVERYRECEIPT or FLAG_READRECEIPT
sendMessage(p, p.mid, message)
chatList.add(
ChatModel(
id = p.mid,
msg = edtSendChat.text.toString(),
date = getTimestamp(),
type = 1,
status = 0
)
)
chatListAdapter.notifyItemInserted(chatList.lastIndex)
layoutManager.scrollToPositionWithOffset(chatList.size - 1, 0)
edtSendChat.text?.clear()
}
private fun loadFromDb(address: String) {
setAppInForeground(this, ChatListActivity.hashCode(), true)
readSession = ReadDbSession(address, this)
readSession.enableReadReceipt(true)
readSession.enableCalls(false)
readSession.enableIncomingCalls(false)
readSession.enableMissedCalls(false)
readSession.enableOutgoingCalls(false)
readSession.enableFifo(true)
readSession.read(500)
}
private fun startMesibo() {
addListener(this)
setSecureConnection(true)
setAccessToken(userMesibo?.token)
setDatabase("db_mesibo", 0)
start()
userProfile = UserProfile()
userProfile?.address = email
setUserProfile(userProfile, true)
}
}
Any clue about how to resolve and debug?
this is my env:
Mesibo AP = 2.7.0
Build tools = 29.0.0
compile SDK versions = 30
appid = com.project.bucynapp
Thanks!
Have you tried the custom scripts or mesibo webhook to debug the issue? Have you referred to the Troubleshooting section in the mesibo push-notification document?
https://mesibo.com/documentation/api/push-notifications/
Unless you post logs and steps you have taken, we have no clue what is happening.
I have been stuck on this issue for a bit of time now and I have looked through other questions on the subject. However, I do not fully understand their solutions and how it could be applied to my case.
Logcat
java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.example.realtimechat/com.example.realtimechat.chats.ChatActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.LayoutInflater android.view.Window.getLayoutInflater()' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3022)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3259)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1950)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7073)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:965)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.LayoutInflater android.view.Window.getLayoutInflater()' on a null object reference
at android.app.Activity.getLayoutInflater(Activity.java:4435)
at com.example.realtimechat.chats.ChatActivity.<init>(ChatActivity.kt:66)
at java.lang.Class.newInstance(Native Method)
at android.app.AppComponentFactory.instantiateActivity(AppComponentFactory.java:69)
at androidx.core.app.CoreComponentFactory.instantiateActivity(CoreComponentFactory.java:45)
at android.app.Instrumentation.newActivity(Instrumentation.java:1215)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3010)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3259)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1950)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7073)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:965)
Chat Activity
package com.example.realtimechat.chats
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.Intent.ACTION_PICK
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.net.Uri
import android.os.Bundle
import android.provider.MediaStore
import android.provider.MediaStore.ACTION_IMAGE_CAPTURE
import android.view.View
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import android.widget.ImageView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.example.realtimechat.R
import com.example.realtimechat.common.Constants
import com.example.realtimechat.common.Extras
import com.example.realtimechat.common.NodeNames
import com.example.realtimechat.common.Utils
import com.google.android.material.bottomsheet.BottomSheetDialog
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.database.*
import com.google.firebase.storage.FirebaseStorage
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream
class ChatActivity : AppCompatActivity(), View.OnClickListener {
private lateinit var etMessage: EditText
private lateinit var ivSend: ImageView
private lateinit var ivAttachment: ImageView
private lateinit var mAuth: FirebaseAuth
private lateinit var mRootRef: DatabaseReference
private lateinit var currentUserId: String
private lateinit var chatUserId: String
private lateinit var rvMessages: RecyclerView
private lateinit var srlMessages: SwipeRefreshLayout
private lateinit var messagesAdapter: MessagesAdapter
private lateinit var messagesList: MutableList<MessageModel>
private var currentPage = 1
companion object {
private const val RECORD_PER_PAGE = 30
}
private val REQUEST_CODE_CAPTURE_IMAGE=102
private val REQUEST_CODE_PICK_IMAGE=101
private val REQUEST_CODE_PICK_VIDEO=103
private lateinit var databaseReferenceMessages: DatabaseReference
private lateinit var childEventListener: ChildEventListener
private lateinit var bottomSheetDialog: BottomSheetDialog
val view: View = layoutInflater.inflate(R.layout.chat_file_options, null)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_chat)
etMessage = findViewById(R.id.etMessage)
ivSend = findViewById(R.id.ivSend)
ivAttachment = findViewById(R.id.ivAttachment)
ivSend.setOnClickListener(this)
ivAttachment.setOnClickListener(this)
mAuth = FirebaseAuth.getInstance()
mRootRef = FirebaseDatabase.getInstance().reference
currentUserId = mAuth.currentUser!!.uid
if(intent.hasExtra(Extras.USER_KEY)){
chatUserId = intent.getStringExtra(Extras.USER_KEY)!!
}
rvMessages = findViewById(R.id.rvMessages)
srlMessages = findViewById(R.id.srlMessages)
val layoutManager = LinearLayoutManager(applicationContext)
layoutManager.orientation = RecyclerView.VERTICAL
rvMessages.layoutManager = layoutManager
rvMessages.setHasFixedSize(true)
messagesList = ArrayList()
messagesAdapter = MessagesAdapter(this, messagesList)
rvMessages.adapter = messagesAdapter
loadMessages()
rvMessages.scrollToPosition(messagesList.size-1)
srlMessages.setOnRefreshListener(object: SwipeRefreshLayout.OnRefreshListener{
override fun onRefresh() {
currentPage++
loadMessages()
}
})
bottomSheetDialog = BottomSheetDialog(this)
view.findViewById<View>(R.id.llCamera).setOnClickListener(this)
view.findViewById<View>(R.id.llGallery).setOnClickListener(this)
view.findViewById<View>(R.id.llVideo).setOnClickListener(this)
view.findViewById<View>(R.id.ivClose).setOnClickListener(this)
bottomSheetDialog.setContentView(view)
}
//send messages
private fun sendMessage(msg: String, msgType: String, pushId: String){
try {
if (msg != "") {
val messageMap = HashMap<Any, Any>()
messageMap[NodeNames.MESSAGE_ID] = pushId
messageMap[NodeNames.MESSAGE] = msg
messageMap[NodeNames.MESSAGE_TYPE] = msgType
messageMap[NodeNames.MESSAGE_FROM] = currentUserId
messageMap[NodeNames.MESSAGE_TIME] = ServerValue.TIMESTAMP
val currentUserRef = NodeNames.MESSAGES + "/" + currentUserId + "/" + chatUserId
val chatUserRef = NodeNames.MESSAGES + "/" + chatUserId + "/" + currentUserId
val messageUserMap = mutableMapOf<String, Any>()
messageUserMap["$currentUserRef/$pushId"] = messageMap
messageUserMap["$chatUserRef/$pushId"] = messageMap
etMessage.setText("")
mRootRef.updateChildren(messageUserMap, object : DatabaseReference.CompletionListener {
override fun onComplete(databaseError: DatabaseError?, databaseReference: DatabaseReference) {
if (databaseError != null) {
Toast.makeText(applicationContext, "Failed to send message: ${databaseError.message}", Toast.LENGTH_SHORT).show()
}
run{
Toast.makeText(applicationContext, "Message sent successfully!", Toast.LENGTH_SHORT).show()
}
}
})
}
} catch (e: Exception) {
Toast.makeText(applicationContext, "Failed to send message: ${e.localizedMessage}", Toast.LENGTH_SHORT).show()
}
}
private fun loadMessages(){
messagesList.clear()
databaseReferenceMessages = mRootRef.child(NodeNames.MESSAGES).child(currentUserId).child(chatUserId)
val messageQuery: Query = databaseReferenceMessages.limitToLast(currentPage * RECORD_PER_PAGE)
childEventListener = object: ChildEventListener{
override fun onChildAdded(snapshot: DataSnapshot, previousChildName: String?) {
val message: MessageModel = snapshot.getValue(MessageModel::class.java)!!
messagesList.add(message)
messagesAdapter.notifyDataSetChanged()
rvMessages.scrollToPosition(messagesList.size-1)
srlMessages.isRefreshing = false
}
override fun onChildChanged(snapshot: DataSnapshot, previousChildName: String?) {
}
override fun onChildRemoved(snapshot: DataSnapshot) {
}
override fun onChildMoved(snapshot: DataSnapshot, previousChildName: String?) {
}
override fun onCancelled(error: DatabaseError) {
srlMessages.isRefreshing = false
}
}
messageQuery.addChildEventListener(childEventListener)
}
private fun uploadFile(uri: Uri, messageType: String){
val databaseReference = mRootRef.child(NodeNames.MESSAGES).child(currentUserId).child(chatUserId).push()
val pushId = databaseReference.key!!
val folderName =
if (messageType == Constants.MESSAGE_TYPE_VIDEO) Constants.MESSAGE_VIDEOS else Constants.MESSAGE_IMAGES
val fileName: String =
if (messageType == Constants.MESSAGE_TYPE_VIDEO) "$pushId.mp4" else "$pushId.jpg"
val storageReference = FirebaseStorage.getInstance().reference
val fileReference = storageReference.child(folderName).child(fileName)
fileReference.putFile(uri)
}
private fun uploadBytes(bytes: ByteArrayOutputStream, messageType: String){
val databaseReference = mRootRef.child(NodeNames.MESSAGES).child(currentUserId).child(chatUserId).push()
val pushId = databaseReference.key!!
val folderName =
if (messageType == Constants.MESSAGE_TYPE_VIDEO) Constants.MESSAGE_VIDEOS else Constants.MESSAGE_IMAGES
val fileName: String =
if (messageType == Constants.MESSAGE_TYPE_VIDEO) "$pushId.mp4" else "$pushId.jpg"
val storageReference = FirebaseStorage.getInstance().reference
val fileReference = storageReference.child(folderName).child(fileName)
fileReference.putBytes(bytes.toByteArray())
}
//if any objects are clicked
override fun onClick(v: View?) {
when(v!!.id){
R.id.ivSend -> {
val utility = Utils()
if(utility.connectionAvailable(this)) {
val message = etMessage.text.toString().trim()
val messageType = NodeNames.MESSAGE_TYPE_TEXT
val userMessagePush =
mRootRef.child(NodeNames.MESSAGES).child(currentUserId).child(chatUserId)
.push()
val pushId = userMessagePush.key
sendMessage(message, messageType, pushId!!)
}else{
Toast.makeText(applicationContext, "No Internet connection available", Toast.LENGTH_SHORT).show()
}
}
R.id.ivAttachment -> {
if(ActivityCompat.checkSelfPermission(this, android.Manifest.permission.READ_EXTERNAL_STORAGE)==PackageManager.PERMISSION_GRANTED){
if(bottomSheetDialog!=null){
bottomSheetDialog.show()
}
}else{
ActivityCompat.requestPermissions(this, arrayOf(android.Manifest.permission.READ_EXTERNAL_STORAGE), 1)
}
val inputMethodManager = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
if(inputMethodManager!=null){
inputMethodManager.hideSoftInputFromWindow(view.windowToken, 0)
}
}
R.id.llCamera -> {
bottomSheetDialog.dismiss()
val intentCamera = Intent(ACTION_IMAGE_CAPTURE)
startActivityForResult(intentCamera, REQUEST_CODE_CAPTURE_IMAGE)
}
R.id.llGallery -> {
bottomSheetDialog.dismiss()
val intentImage = Intent(ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
startActivityForResult(intentImage, REQUEST_CODE_PICK_IMAGE)
}
R.id.llVideo -> {
bottomSheetDialog.dismiss()
val intentVideo = Intent(ACTION_PICK, MediaStore.Video.Media.EXTERNAL_CONTENT_URI)
startActivityForResult(intentVideo, REQUEST_CODE_PICK_VIDEO)
}
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if(resultCode== Activity.RESULT_OK){
if(requestCode==REQUEST_CODE_CAPTURE_IMAGE) {
val bitMap = data!!.extras!!.get("data") as Bitmap
val bytes = ByteArrayOutputStream()
bitMap.compress(Bitmap.CompressFormat.JPEG, 100, bytes)
uploadBytes(bytes, Constants.MESSAGE_TYPE_IMAGE)
}else if(requestCode==REQUEST_CODE_PICK_IMAGE){
val uri = data!!.data!!
uploadFile(uri, Constants.MESSAGE_TYPE_IMAGE)
}else if(requestCode==REQUEST_CODE_PICK_VIDEO){
val uri = data!!.data!!
uploadFile(uri, Constants.MESSAGE_TYPE_VIDEO)
}
}
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if(requestCode==1){
if(grantResults.size>1 && grantResults[0]==PackageManager.PERMISSION_GRANTED){
if(bottomSheetDialog!=null){
bottomSheetDialog.show()
}
}else{
Toast.makeText(this, "Permission needed", Toast.LENGTH_SHORT).show()
}
}
}
}
If anyone could explain (in an easy manner) how these types of problems could be approached and solved and how to solve it in my case, it would be greatly appreciated!
layoutInflater hasn't been instantiated yet. When doing anything with views, you pretty much have to wait until the onCreate method. So something like this:
var view: View? = null
// OR
lateinit var view: View
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_chat)
view = layoutInflater.inflate(R.layout.chat_file_options, null)
......
}
I have a problem using the method notifyDataSetChanged for a BaseAdapter. I think i don't really understand who it works. I want to add a new Item to the list of view to show a loading screen while an image is uploading. Once the image is uploaded, I remove the item and call the method but im receiving and error and I don't understand why.
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.drawable.BitmapDrawable
import android.net.Uri
import android.os.Build
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.provider.MediaStore
import android.support.v4.app.ActivityCompat
import android.view.View
import android.view.ViewGroup
import android.widget.BaseAdapter
import android.widget.Toast
import com.google.android.gms.tasks.OnSuccessListener
import com.google.android.gms.tasks.Task
import com.google.firebase.database.DataSnapshot
import com.google.firebase.database.DatabaseError
import com.google.firebase.database.FirebaseDatabase
import com.google.firebase.database.ValueEventListener
import com.google.firebase.storage.FirebaseStorage
import com.squareup.picasso.Picasso
import kotlinx.android.synthetic.main.activity_login.*
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.android.synthetic.main.add_ticket.*
import kotlinx.android.synthetic.main.add_ticket.view.*
import kotlinx.android.synthetic.main.tweets_ticket.view.*
import java.io.ByteArrayOutputStream
import java.lang.Exception
import java.text.SimpleDateFormat
import java.util.*
import kotlin.collections.ArrayList
import kotlin.collections.HashMap
class MainActivity : AppCompatActivity() {
private var listofTweets = ArrayList<Ticket>()
var adapter:TweetsAdapter? = null
private val PICK_IMG_CODE:Int = 123
var myEmail:String? = null
var downloadUrl:String? = null
private var database = FirebaseDatabase.getInstance()
private var myRef = database.reference
var userID:String? = null
private val READIMAGE:Int = 253
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
var b:Bundle = intent.extras
myEmail = b.getString("email")
userID = b.getString("uid")
listofTweets.add(Ticket("1", "My first tweet", "", "add"))
listofTweets.add(Ticket("2", "My third tweet", "https://firebasestorage.googleapis.com/v0/b/fir-demoapp-8edf3.appspot.com/o/imagesPost%2F160819173436.jpg?alt=media&token=29ac687e-0936-49d8-a42f-50ab0e751208", "normal"))
//listofTweets.add(Ticket("3", "My fourth tweet", "gs://fir-demoapp-8edf3.appspot.com/imagesPost/160819173436.jpg", "normal"))
//listofTweets.add(Ticket("4", "My fifth tweet", "http://i.imgur.com/DvpvklR.png", "normal"))
var adapter = TweetsAdapter(this, listofTweets)
lvTweets.adapter = adapter
loadPost()
}
inner class TweetsAdapter:BaseAdapter{
var listOfTweetsAdapter = ArrayList<Ticket>()
var context:Context? = null
constructor(context:Context, listOfTweetsAdapter:ArrayList<Ticket>):super(){
this.context = context
this.listOfTweetsAdapter = listOfTweetsAdapter
}
override fun getCount(): Int {
return listofTweets.size
}
override fun getItem(p0: Int): Any {
return listofTweets[p0]
}
override fun getItemId(p0: Int): Long {
return p0.toLong()
}
override fun getView(p0: Int, p1: View?, p2: ViewGroup?): View {
var tweet = listOfTweetsAdapter[p0]
if(tweet.tweetPersonUid.equals("add")) {
//Load add ticket
var myView = layoutInflater.inflate(R.layout.add_ticket, null)
myView.ivAttach.setOnClickListener {
//loadImage()
checkPermission()
}
myView.ivPost.setOnClickListener {
//Upload to the server
myRef.child("posts").push().setValue(
PostInfo(
userID.toString(), myView.etPost.text.toString(), downloadUrl.toString()
)
)
myView.etPost.setText("")
}
return myView
} else if (tweet.tweetPersonUid.equals("loading")) {
var myView = layoutInflater.inflate(R.layout.loading_ticket, null)
return myView
} else {
//Load tweet ticket
var myView = layoutInflater.inflate(R.layout.tweets_ticket, null)
myView.txt_tweet.setText(tweet.tweetText)
myView.txtUserName.setText(tweet.tweetPersonUid)
Picasso.get().load(tweet.tweetImageUrl).into(myView.tweet_picture)
myRef.child("Users").child(tweet.tweetPersonUid!!)
.addValueEventListener(object:ValueEventListener{
override fun onDataChange(p0: DataSnapshot) {
try {
var td = p0!!.value as HashMap<String, Any>
for (key in td.keys) {
var userInfo = td[key] as String
if(key.equals("profileImage")) {
Picasso.get().load(userInfo).into(myView.picture_path)
} else {
myView.txtUserName.setText(userInfo)
}
}
} catch (ex:Exception) {
}
}
override fun onCancelled(p0: DatabaseError) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
})
return myView
}
}
}
fun loadImage() {
var intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
startActivityForResult(intent, PICK_IMG_CODE)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if(requestCode == PICK_IMG_CODE && resultCode == Activity.RESULT_OK && data != null) {
val selectedImage = data.data
val filePathColumn = arrayOf(MediaStore.Images.Media.DATA)
val cursor = contentResolver.query(selectedImage, filePathColumn, null, null, null)
cursor.moveToFirst()
val columnIndex = cursor.getColumnIndex(filePathColumn[0])
val picturePath = cursor.getString(columnIndex)
cursor.close()
uploadImage(BitmapFactory.decodeFile(picturePath))
}
}
fun uploadImage(bitmap:Bitmap){
listofTweets.add(0, Ticket("0","him","url", "loading"))
adapter!!.notifyDataSetChanged()
val storage = FirebaseStorage.getInstance()
var storageRef = storage.getReferenceFromUrl("gs://fir-demoapp-8edf3.appspot.com/")
val df = SimpleDateFormat("ddMMyyHHmmss")
val dataObj = Date()
val imgPath = df.format(dataObj) + ".jpg"
val imgRef = storageRef.child("imagesPost/" + imgPath)
val baos = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos)
val data = baos.toByteArray()
val uploadTask = imgRef.putBytes(data)
uploadTask.addOnFailureListener{
Toast.makeText(applicationContext, it.toString(), Toast.LENGTH_LONG).show()
}.addOnSuccessListener { taskSnapshot ->
imgRef.downloadUrl.addOnCompleteListener() {taskSnapshot ->
downloadUrl = taskSnapshot.result.toString()
//listofTweets.removeAt(0)
//adapter!!.notifyDataSetChanged()
}
}
}
fun loadPost(){
myRef.child("posts")
.addValueEventListener(object:ValueEventListener{
override fun onDataChange(p0: DataSnapshot) {
try {
listofTweets.clear()
listofTweets.add(Ticket("1", "My first tweet", "", "add"))
var td = p0!!.value as HashMap<String, Any>
for (key in td.keys) {
var post = td[key] as HashMap<String, Any>
listofTweets.add(
Ticket(key,
post["text"] as String,
post["img"] as String,
post["userUID"] as String)
)
}
adapter!!.notifyDataSetChanged()
} catch (ex:Exception) {
}
}
override fun onCancelled(p0: DatabaseError) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
})
}
fun checkPermission() {
if(Build.VERSION.SDK_INT >= 23) {
if(ActivityCompat.checkSelfPermission(this,
android.Manifest.permission.READ_EXTERNAL_STORAGE) !=
PackageManager.PERMISSION_GRANTED) {
requestPermissions(arrayOf(android.Manifest.permission.READ_EXTERNAL_STORAGE), READIMAGE)
return
}
}
loadImage()
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
when(requestCode) {
READIMAGE -> {
if(grantResults[0] == PackageManager.PERMISSION_GRANTED) {loadImage()}
else {Toast.makeText(this, "Cannot acces your images", Toast.LENGTH_LONG).show()}
} else -> super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}
}
}
And the error log is (line 172 is adapter!!.notifyDataSetChanged()):
java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=123, result=-1, data=Intent { dat=content://com.google.android.apps.photos.contentprovider/-1/1/content://media/external/images/media/113490/ORIGINAL/NONE/549404385 flg=0x1 clip={text/uri-list U:content://com.google.android.apps.photos.contentprovider/-1/1/content%3A%2F%2Fmedia%2Fexternal%2Fimages%2Fmedia%2F113490/ORIGINAL/NONE/549404385} }} to activity {com.example.twitter/com.example.startup.MainActivity}: kotlin.KotlinNullPointerException
at android.app.ActivityThread.deliverResults(ActivityThread.java:4363)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:4405)
at android.app.servertransaction.ActivityResultItem.execute(ActivityResultItem.java:49)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1811)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6694)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Caused by: kotlin.KotlinNullPointerException
at com.example.startup.MainActivity.uploadImage(MainActivity.kt:172)
at com.example.startup.MainActivity.onActivityResult(MainActivity.kt:165)
at android.app.Activity.dispatchActivityResult(Activity.java:7454)
at android.app.ActivityThread.deliverResults(ActivityThread.java:4356)
at android.app.ActivityThread.handleSendResult(ActivityThread.java:4405)
at android.app.servertransaction.ActivityResultItem.execute(ActivityResultItem.java:49)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1811)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6694)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
Thanks in advance.
Your are getting a null pointer exception.
// You have this class member
var adapter:TweetsAdapter? = null
override fun onCreate(savedInstanceState: Bundle?) {
// During on create, you are creating the adapter
// However, you are holding the adapter in a local variable
var adapter = TweetsAdapter(this, listofTweets)
}
fun uploadImage(bitmap:Bitmap){
// Then, here, when you try to read the adapter, you are reading
// the class member adapter (which is still null)
adapter!!.notifyDataSetChanged()
}
In order to fix the null pointer, update your onCreate method:
From:
var adapter = TweetsAdapter(this, listofTweets)
To:
this.adapter = TweetsAdapter(this, listofTweets)