The application crashes as soon as it is run to the emulator. The main code runs perfectly but when it comes to the implementation in the emulator, it runs and the app crashes. The error is shown below:
2020-07-20 14:05:48.662 9135-9135/com.sam.sabinomeals E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.sam.sabinomeals, PID: 9135
java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{com.sam.sabinomeals/net.sam.sabinomeals.SplashActivity}: java.lang.ClassNotFoundException: Didn't find class "net.sam.sabinomeals.SplashActivity" on path: DexPathList[[zip file "/data/app/com.sam.sabinomeals-QJkZ4ORKUV6qLdDBZZ2Jvw==/base.apk"],nativeLibraryDirectories=[/data/app/com.sam.sabinomeals-QJkZ4ORKUV6qLdDBZZ2Jvw==/lib/x86, /system/lib, /system/product/lib]]
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3194)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
Caused by: java.lang.ClassNotFoundException: Didn't find class "net.sam.sabinomeals.SplashActivity" on path: DexPathList[[zip file "/data/app/com.sam.sabinomeals-QJkZ4ORKUV6qLdDBZZ2Jvw==/base.apk"],nativeLibraryDirectories=[/data/app/com.sam.sabinomeals-QJkZ4ORKUV6qLdDBZZ2Jvw==/lib/x86, /system/lib, /system/product/lib]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:196)
at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
at android.app.AppComponentFactory.instantiateActivity(AppComponentFactory.java:95)
at androidx.core.app.CoreComponentFactory.instantiateActivity(CoreComponentFactory.java:45)
at android.app.Instrumentation.newActivity(Instrumentation.java:1243)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3182)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
at android.os.Handler.dispatchMessage(Handler.java:107)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
The code below is for the splashactivity, it seems to be sure but I think you can still go through it.
package com.sam.sabinomeals
import android.Manifest
import android.app.DatePickerDialog
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.text.TextUtils
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.WindowManager
import android.view.animation.AnimationUtils
import android.widget.Toast
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import com.google.android.material.textfield.TextInputEditText
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.auth.FirebaseUser
import com.google.firebase.database.*
import com.google.firebase.iid.FirebaseInstanceId
import com.karumi.dexter.Dexter
import com.karumi.dexter.MultiplePermissionsReport
import com.karumi.dexter.PermissionToken
import com.karumi.dexter.listener.PermissionRequest
import com.karumi.dexter.listener.multi.MultiplePermissionsListener
import com.sam.sabinomeals.Remote.ICloudFunctions
import com.sam.sabinomeals.Remote.RetrofitCloudClient
import com.sam.sabinomeals.commons.Common
import com.sam.sabinomeals.models.BraintreeToken
import com.sam.sabinomeals.models.UserModel
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import kotlinx.android.synthetic.main.activity_splash.*
import net.sam.sabinomeals.R
import org.jetbrains.anko.longToast
import org.jetbrains.anko.toast
import java.util.*
class SplashActivity : AppCompatActivity() {
private lateinit var userReference: DatabaseReference
val SPLASH_SCREEN: Long = 5000
lateinit var handler: Handler
private var compositeDisposable: CompositeDisposable?= CompositeDisposable()
lateinit var cloudFunctions: ICloudFunctions
override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState)
setContentView(R.layout.activity_splash)
cloudFunctions= RetrofitCloudClient.getInstance().create(
ICloudFunctions::class.java)
window.setFlags(
WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN)
userReference = FirebaseDatabase.getInstance().getReference(Common.USER_REFERENCE)
//Animation
val logo_animation = AnimationUtils.loadAnimation(this,
R.anim.top_animation)
val txt_animation = AnimationUtils.loadAnimation(this,
R.anim.bottom_animation)
logo_splash.animation = logo_animation
urbanfood.animation = txt_animation
handler = Handler()
checkInternet()
}
private fun checkInternet() {
Dexter.withActivity(this)
.withPermissions(Manifest.permission.INTERNET,
Manifest.permission.ACCESS_FINE_LOCATION)
.withListener(object :MultiplePermissionsListener{
#RequiresApi(Build.VERSION_CODES.M)
override fun onPermissionsChecked(p0: MultiplePermissionsReport?) {
if (isOnline(this#SplashActivity)) {
// showHome()
val currentUser = FirebaseAuth.getInstance().currentUser
if (currentUser != null) {
checkUserFromFirebase(currentUser)
} else {
longToast("Kindly Login")
showLogin()
}
} else {
longToast("Please ensure you are connected to the Internet")
handler.postDelayed({
finish()
}, SPLASH_SCREEN)
}
}
override fun onPermissionRationaleShouldBeShown(
p0: MutableList<PermissionRequest>?,
p1: PermissionToken?
) {
AlertDialog.Builder(this#SplashActivity)
.setTitle(R.string.internet_permission_title)
.setMessage(R.string.internet_permission_message)
.setNegativeButton(
android.R.string.cancel,
DialogInterface.OnClickListener { dialog, which ->
dialog.dismiss()
p1?.cancelPermissionRequest()
})
.setPositiveButton(
android.R.string.ok,
DialogInterface.OnClickListener { dialog, which ->
dialog.dismiss()
p1?.continuePermissionRequest()
}).show()
}
} ).check()
}
private fun checkUserFromFirebase(currentUser: FirebaseUser) {
userReference.child(currentUser.uid)
.addListenerForSingleValueEvent(object : ValueEventListener {
#RequiresApi(Build.VERSION_CODES.N)
override fun onCancelled(p0: DatabaseError) {
showRegisterDialog(currentUser)
finish()
}
#RequiresApi(Build.VERSION_CODES.N)
override fun onDataChange(p0: DataSnapshot) {
if (p0.exists()) {
val userModel = p0.getValue(UserModel::class.java)
if (userModel != null) {
FirebaseAuth.getInstance().currentUser!!
.getIdToken(true)
.addOnFailureListener{
exception -> Toast.makeText(this#SplashActivity,""+exception.message,Toast.LENGTH_SHORT).show()
}
.addOnCompleteListener{
Common.authorizeToken=it.result!!.token
val headers = HashMap<String,String>()
headers["Authorization"] = Common.buildToken(
Common.authorizeToken)
compositeDisposable!!.add(cloudFunctions.getToken(headers)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({braintreeToken: BraintreeToken? ->
goToHomeActivity(userModel,braintreeToken!!.token)
},{throwable: Throwable? ->
Toast.makeText(this#SplashActivity,""+throwable!!.message,Toast.LENGTH_SHORT).show()
}))
}
}
} else {
showRegisterDialog(currentUser)
}
}
})
}
#RequiresApi(Build.VERSION_CODES.M)
private fun isOnline(context: Context): Boolean {
val connectivityManager =
context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
val capabilities =
connectivityManager.getNetworkCapabilities(connectivityManager.activeNetwork)
if (capabilities != null) {
if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
Log.i("Internet", "NetworkCapabilities.TRANSPORT_CELLULAR")
return true
} else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
Log.i("Internet", "NetworkCapabilities.TRANSPORT_WIFI")
return true
} else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) {
Log.i("Internet", "NetworkCapabilities.TRANSPORT_ETHERNET")
return true
}
}
return false
}
private fun showLogin() {
handler.postDelayed({
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
finish()
}, SPLASH_SCREEN)
}
#RequiresApi(Build.VERSION_CODES.N)
private fun showRegisterDialog(currentUser: FirebaseUser?) {
val builder = AlertDialog.Builder(this)
builder.setTitle("Updated Profile")
builder.setMessage("Please fill in your information")
val itemView = LayoutInflater.from(this)
.inflate(R.layout.layout_register, null)
val edt_name = itemView.findViewById<TextInputEditText>(R.id.edt_name)
val birth_date = itemView.findViewById<TextInputEditText>(R.id.birth_date)
val edt_address = itemView.findViewById<TextInputEditText>(R.id.edt_address)
val edt_phone = itemView.findViewById<TextInputEditText>(R.id.edt_phone)
//setPhone
edt_phone.setText(currentUser!!.phoneNumber)
//Date
birth_date.setOnClickListener(View.OnClickListener {
val c = Calendar.getInstance()
val mYear = c.get(Calendar.YEAR)
val mMonth = c.get(Calendar.MONTH)
val mDay = c.get(Calendar.DAY_OF_MONTH)
val datePickerDialog =
DatePickerDialog(
this,
DatePickerDialog.OnDateSetListener { view, year, month, dayOfMonth ->
birth_date.setText("" + dayOfMonth + "/" + month + "/" + year)
},
mYear,
mMonth,
mDay
)
datePickerDialog.show()
})
builder.setView(itemView)
builder.setNegativeButton("Cancel") { dialog, which -> dialog.dismiss() }
builder.setPositiveButton("Record") { dialog, which ->
if (TextUtils.isDigitsOnly(edt_name.text.toString())) {
toast("Enter your name")
return#setPositiveButton
} else if (TextUtils.isDigitsOnly(edt_address.text.toString())) {
toast("Enter your address")
return#setPositiveButton
}
val userModel = UserModel()
userModel.uid = currentUser.uid
userModel.name = edt_name.text.toString()
userModel.address = edt_address.text.toString()
userModel.aniversaire = birth_date.text.toString()
userReference.child(currentUser.uid)
.setValue(userModel)
.addOnCompleteListener { task ->
if (task.isSuccessful) {
FirebaseAuth.getInstance().currentUser!!
.getIdToken(true)
.addOnFailureListener{
exception -> Toast.makeText(this,""+exception.message,Toast.LENGTH_SHORT).show()
}
.addOnCompleteListener{
Common.authorizeToken=it.result!!.token
val headers = HashMap<String,String>()
headers.put("Authorization",
Common.buildToken(
Common.authorizeToken))
compositeDisposable!!.add(cloudFunctions.getToken(headers)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe({braintreeToken: BraintreeToken? ->
dialog.dismiss()
goToHomeActivity(userModel, braintreeToken!!.token)
},
{throwable: Throwable? ->
dialog.dismiss()
Toast.makeText(this,""+throwable!!.message,Toast.LENGTH_SHORT).show()
}))
}
}
}
}
//Important
val dialog = builder.create()
dialog.show()
}
private fun goToHomeActivity(
userModel: UserModel?,
token: String
) {
FirebaseInstanceId.getInstance()
.instanceId
.addOnFailureListener { exception ->
Toast.makeText(this,""+exception.message,Toast.LENGTH_SHORT).show()
Common.currentUser= userModel
Common.currentToken=token
startActivity(Intent(this, HomeActivity::class.java))
finish()
}
.addOnCompleteListener { task->
if(task.isSuccessful){
Common.currentUser= userModel
Common.currentToken=token
Common.updateToken(this,task.result!!.token)
startActivity(Intent(this, HomeActivity::class.java))
finish()
}
}
}
}
It's because your AndroidManifest.xml is looking for net.sam.sabinomeals.SplashActivity, but your activity is actually in com.sam.sabinomeals.SplashActivity
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
i'm tring to figure out where my app does not pass data.
Here is my login fragment
package com.example.progettoprogrammazione.intro
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.navigation.findNavController
import com.example.progettoprogrammazione.R
import com.example.progettoprogrammazione.activity.EmployeeActivity
import com.example.progettoprogrammazione.activity.UserActivity
import com.example.progettoprogrammazione.activity.RestaurateurActivity
import com.example.progettoprogrammazione.databinding.FragmentLoginBinding
import com.example.progettoprogrammazione.models.Dipendente
import com.example.progettoprogrammazione.models.Restaurant
import com.example.progettoprogrammazione.models.dipendenteList
import com.example.progettoprogrammazione.utils.*
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.database.DataSnapshot
import com.google.firebase.database.DatabaseError
import com.google.firebase.database.FirebaseDatabase
import com.google.firebase.database.ValueEventListener
class FragmentLogin : Fragment(), UserUtil,DipendenteUtil,RestaurantUtils {
private lateinit var binding: FragmentLoginBinding
override var firebaseAuth: FirebaseAuth = FirebaseAuth.getInstance()
override var firebaseDatabase: FirebaseDatabase = FirebaseDatabase.getInstance()
private lateinit var restArrayList: ArrayList<Restaurant>
private lateinit var dipArrayList: ArrayList<Dipendente>
private var userlvl: String? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
binding = FragmentLoginBinding.inflate(layoutInflater)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
firebaseAuth = FirebaseAuth.getInstance()
binding.ConstraintLogin.setOnClickListener() {
val email = binding.email.text.toString()
val password = binding.password.text.toString()
if (email.isNotEmpty() && password.isNotEmpty()) {
firebaseAuth.signInWithEmailAndPassword(email, password).addOnCompleteListener {
if (it.isSuccessful) {
//FUNZIONE CHE PRENDE DATI RISTORANTI
/*
FUNZIONE CHE PRENDE I DATI DI DIPENDENTE
dipArrayList = arrayListOf()
getDipendenteData(object : FireBaseCallbackDipendente {
override fun onResponse(response: ResponseDipendente) {
dipArrayList = response.dipendenti
}
}, context)
*/
//LOGIN
getUserData(object : FireBaseCallbackUser {
override fun onResponse(response: ResponseUser) {
userlvl = response.user!!.Livello
Toast.makeText(context,"Login effettuato con successo!", Toast.LENGTH_LONG).show()
when (userlvl) {
"1" -> {
getRestaurantData(object : FireBaseCallbackRestaurant {
override fun onResponse(responseR: ResponseRistorante) {
restArrayList = responseR.ristoranti
val args = Bundle()
args.putParcelableArrayList("listaRistoranti", restArrayList)
val intent =
Intent(context, UserActivity::class.java).apply {
putExtra("user", response.user)
putExtra("listaRistoranti", responseR.ristoranti)
}
startActivity(intent)
activity?.finish()
}
}, context)
}
"2" -> {
getRestaurantData(object : FireBaseCallbackRestaurant {
override fun onResponse(responseR: ResponseRistorante) {
restArrayList = arrayListOf()
restArrayList = responseR.ristoranti
val args = Bundle()
args.putParcelableArrayList("listaRistoranti", restArrayList)
val intent =
Intent(context, EmployeeActivity::class.java).apply {
putExtra("user", response.user)
putExtra("listaRistoranti", responseR.ristoranti)
}
startActivity(intent)
activity?.finish()
}
}, context)
}
"3" -> {
getRestaurantData(object : FireBaseCallbackRestaurant {
override fun onResponse(responseR: ResponseRistorante) {
restArrayList = arrayListOf()
restArrayList = responseR.ristoranti
val args = Bundle()
args.putParcelableArrayList("listaRistoranti", restArrayList)
//args.putSerializable("arraylist", restArrayList)
val intent =
Intent(context, RestaurateurActivity::class.java).apply {
putExtra("user", response.user)
putExtra("ristoranti", args)
}
startActivity(intent)
activity?.finish()
}
}, context)
}
else -> {
Toast.makeText(
context,
"Errore durante il caricamento.",
Toast.LENGTH_LONG
).show()
}
}
}
}, context)
} else Toast.makeText(
context,
"Email e password non corrispondono!",
Toast.LENGTH_LONG
).show()
}
} else {
Toast.makeText(context, "Nessun campo può essere vuoto!", Toast.LENGTH_LONG).show()
}
}
binding.noaccount.setOnClickListener {
view.findNavController().navigate(R.id.LoginToRegister)
}
}
}
I wanted to focus on this portion of code
getRestaurantData(object : FireBaseCallbackRestaurant {
override fun onResponse(responseR: ResponseRistorante) {
restArrayList = responseR.ristoranti
val args = Bundle()
args.putParcelableArrayList("listaRistoranti", restArrayList)
val intent =
Intent(context, UserActivity::class.java).apply {
putExtra("user", response.user)
putExtra("listaRistoranti", responseR.ristoranti)
}
startActivity(intent)
activity?.finish()
}
}, context)
}
Here it's my userActivity class
package com.example.progettoprogrammazione.activity
import android.content.Context
import android.content.Intent
import android.graphics.Rect
import android.os.Bundle
import android.view.MotionEvent
import android.view.View
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.navigation.findNavController
import com.example.progettoprogrammazione.R
import com.example.progettoprogrammazione.databinding.ActivityUserBinding
import com.example.progettoprogrammazione.fragment.FragmentRistoranti
import com.example.progettoprogrammazione.models.Restaurant
import com.example.progettoprogrammazione.models.User
import com.google.firebase.auth.FirebaseAuth
class UserActivity : AppCompatActivity() {
private lateinit var binding: ActivityUserBinding
private lateinit var user: FirebaseAuth
private var pressedTime = 0L
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityUserBinding.inflate(layoutInflater)
setContentView(binding.root)
user = FirebaseAuth.getInstance()
val u = intent.getParcelableExtra("user") as User?
val bundleU = Bundle()
bundleU.putParcelable("user", u)
val r = intent.getParcelableArrayListExtra<Restaurant>("listaRistoranti") as ArrayList<Restaurant>?
val bundleR = Bundle()
bundleR.putParcelableArrayList("listaRistoranti", r)
binding.navbarUser.setOnNavigationItemSelectedListener {
when (it.itemId) {
R.id.ic_ristorantiU -> {
val navController = this.findNavController(R.id.user_nav)
navController.navigate(R.id.Ristoranti_U, bundleR)
}
R.id.ic_profileU -> {
val navController = this.findNavController(R.id.user_nav)
navController.navigate(R.id.Profilo_U, bundleU)
}
R.id.ic_logoutU -> {
user.signOut()
Toast.makeText(this, "Logout effettuato con successo", Toast.LENGTH_LONG).show()
val intent = Intent(this, IntroActivity::class.java)
startActivity(intent)
finish()
}
}
true
}
}
override fun onBackPressed() {
if (pressedTime + 2000 > System.currentTimeMillis()) {
super.onBackPressed()
finishAffinity()
} else {
Toast.makeText(baseContext, "Premi indietro di nuovo per uscire.", Toast.LENGTH_SHORT).show()
}
pressedTime = System.currentTimeMillis()
}
override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {
if (ev?.action == MotionEvent.ACTION_UP) {
val v: View? = currentFocus
if (v is EditText) {
val outRect = Rect()
v.getGlobalVisibleRect(outRect)
if (!outRect.contains(ev.rawX.toInt(), ev.rawY.toInt())) {
v.clearFocus()
val imm: InputMethodManager =
getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
imm.toggleSoftInput(InputMethodManager.HIDE_IMPLICIT_ONLY, 0)
}
}
}
return super.dispatchTouchEvent(ev)
}
}
In particular at this lines of code,cause I tried debbugging as you can see here , only to find out that I get null so I guess I'm not getting data from the intent (more in depth from
putExtra("listaRistoranti", responseR.ristoranti)
this line of code)
val r = intent.getParcelableArrayListExtra<Restaurant>("listaRistoranti") as ArrayList<Restaurant>?
val bundleR = Bundle()
bundleR.putParcelableArrayList("listaRistoranti", r)
can somebody help me and also explain what I did wrong
I am making a studymaterial app, where i want to add a functionality where - when a user download a particular chapter from recyclerview and after the successful download of that item the Download button visivity should make GONE of that item at that time.
I have implemented a method to do thisd but it only works when user finish the activity and come back again on that activity then the download button automatic not showing, but i want to implement at that point of time when user download something.
Here is my DownloadHandler.kt class
package com.tworoot2.class9thhistoryncert.downloadHandler
import android.app.AlertDialog
import android.app.ProgressDialog
import android.content.Context
import android.content.Intent
import android.widget.Toast
import com.downloader.*
import com.tworoot2.class9thhistoryncert.DownloadedFiles
import java.io.File
import com.tworoot2.class9thhistoryncert.R
class DownloadHandler {
lateinit var alertDialog: AlertDialog.Builder
lateinit var failed: AlertDialog.Builder
var progressDialog: ProgressDialog? = null
var fileDestination: File? = null
var down: Boolean = false
fun downloadFile(url: String?, fileName: String, context: Context, filePath: File): Boolean {
progressDialog = ProgressDialog(context)
progressDialog!!.setMessage("Downloading....")
progressDialog!!.setCancelable(false)
progressDialog!!.max = 100
progressDialog!!.setProgressStyle(ProgressDialog.STYLE_SPINNER)
progressDialog!!.show()
alertDialog = AlertDialog.Builder(context)
alertDialog.setTitle("Downloaded successfully")
alertDialog.setMessage("$fileName is downloaded successfully")
alertDialog.setIcon(R.drawable.check)
alertDialog.setPositiveButton(
"Open"
) { _, i ->
val intent = Intent(context, DownloadedFiles::class.java)
context.startActivity(intent)
}
failed = AlertDialog.Builder(context)
failed.setTitle("Downloading failed")
failed.setMessage("Your file is not downloaded successfully")
failed.setIcon(R.drawable.failed)
PRDownloader.download(url, filePath.path, fileName)
.build()
.setOnStartOrResumeListener { }
.setOnPauseListener { }
.setOnCancelListener { }
.setOnProgressListener { progress ->
val per = progress.currentBytes * 100 / progress.totalBytes
progressDialog!!.setMessage("Downloading : $per %")
}
.start(object : OnDownloadListener {
override fun onDownloadComplete() {
down = true
Toast.makeText(context, "Download completed ", Toast.LENGTH_SHORT).show()
progressDialog!!.dismiss()
alertDialog.show()
}
override fun onError(error: Error) {
down = false
Toast.makeText(context, "Something went wrong", Toast.LENGTH_SHORT).show()
failed.show()
progressDialog!!.dismiss()
}
})
return down
}
}
Adapter Class
package com.tworoot2.class9thhistoryncert.adapters
import android.content.Context
import android.content.Intent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import com.tworoot2.class9thhistoryncert.Interface.OnPDFSelectListener
import com.tworoot2.class9thhistoryncert.Interface.PDFDownloadListner
import com.tworoot2.class9thhistoryncert.PDFActivity
import com.tworoot2.class9thhistoryncert.R
import com.tworoot2.class9thhistoryncert.models.StudyMaterials
import java.io.File
import java.lang.String
import kotlin.Int
class MaterialsAdapter(
var context: Context,
var arrayList: List<StudyMaterials>,
var listener: PDFDownloadListner,
var pdfSelectListener: OnPDFSelectListener,
var folderLocations: File
) :
RecyclerView.Adapter<MaterialsAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = LayoutInflater.from(parent.context)
.inflate(R.layout.custom_materials, parent, false)
return ViewHolder(view)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.subjectHead.text = arrayList[position].chNo
holder.subjectName.text = arrayList[position].Title
val file =
File(
"$folderLocations/" + String.valueOf(
"Ch-" + arrayList[position].chNo + ". "
+ arrayList[position].Title + " [twoRoot2]" + ".pdf"
)
)
if (file.exists()) {
holder.downloadBtn.visibility = View.GONE
}
holder.itemView.setOnClickListener {
if (file.exists()) {
pdfSelectListener.onPDFSelected(file)
} else {
val intent = Intent(holder.itemView.context, PDFActivity::class.java)
intent.putExtra("link", arrayList[position].Link)
intent.putExtra("flag", "y")
intent.putExtra("title", arrayList[position].Title)
intent.putExtra("chNo", arrayList[position].chNo)
it.context.startActivity(intent)
}
}
holder.downloadBtn.setOnClickListener {
val downloaded = listener.onDownload(
arrayList[position].Link,
String.valueOf("Ch-" + arrayList[position].chNo)
.toString() + ". " + arrayList[position].Title
)
}
}
override fun getItemCount(): Int {
return arrayList.size
}
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val subjectName = itemView.findViewById<TextView>(R.id.subjectName);
val subjectHead = itemView.findViewById<TextView>(R.id.subjectHead);
val downloadBtn = itemView.findViewById<LinearLayout>(R.id.downloadBtn);
}
}
Activity Class
package com.tworoot2.class9thhistoryncert
import android.app.ProgressDialog
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.os.Environment
import android.view.MenuItem
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModelProvider
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.tworoot2.class9thhistoryncert.Interface.OnPDFSelectListener
import com.tworoot2.class9thhistoryncert.Interface.PDFDownloadListner
import com.tworoot2.class9thhistoryncert.adapters.MaterialsAdapter
import com.tworoot2.class9thhistoryncert.application.MyApplicationClass
import com.tworoot2.class9thhistoryncert.downloadHandler.DownloadHandler
import com.tworoot2.class9thhistoryncert.viewModels.MainViewModel
import com.tworoot2.class9thhistoryncert.viewModels.MainViewModelFactory
import com.tworoot2.result10th_12th.Internetconnection.NetworkUtils
import java.io.File
class MaterialsActivity : AppCompatActivity(), PDFDownloadListner, OnPDFSelectListener {
lateinit var recyclerView: RecyclerView
lateinit var mainViewModel: MainViewModel
lateinit var file: File
lateinit var fileDestination: File
lateinit var downloadHandler: DownloadHandler
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_materials)
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
supportActionBar!!.setDisplayShowHomeEnabled(true)
recyclerView = findViewById(R.id.recView)
recyclerView.layoutManager = LinearLayoutManager(this)
// download listener
downloadHandler = DownloadHandler()
file = File(getExternalFilesDir(null).toString() + "/" + "Class")
fileDestination = File(Environment.getExternalStorageDirectory(), "/Class")
if (!fileDestination.exists()) {
fileDestination.mkdirs()
}
if (!NetworkUtils.isInternetAvailable(this#MaterialsActivity)) {
Toast.makeText(this#MaterialsActivity, "No internet connection", Toast.LENGTH_SHORT)
.show()
}
val progressDialog = ProgressDialog(this)
progressDialog.setMessage("Loading....")
progressDialog.setCancelable(false)
progressDialog.show()
val medium = intent.getStringExtra("medium")
val repository = (application as MyApplicationClass).materialsRepo
mainViewModel =
ViewModelProvider(this, MainViewModelFactory(repository))[MainViewModel::class.java]
if (medium.equals("h")) {
mainViewModel.hisHinLiveData.observe(this) {
this#MaterialsActivity.runOnUiThread(java.lang.Runnable {
val adapter =
MaterialsAdapter(
this#MaterialsActivity, it!!.studyMaterialCS,
this, this, file
)
progressDialog.dismiss()
recyclerView.adapter = adapter
})
}
} else if (medium.equals("e")) {
mainViewModel.hisEngLiveData.observe(this) {
this#MaterialsActivity.runOnUiThread(java.lang.Runnable {
val adapter =
MaterialsAdapter(
this#MaterialsActivity, it!!.studyMaterialCS,
this, this, file
)
progressDialog.dismiss()
recyclerView.adapter = adapter
})
}
} else {
Toast.makeText(this#MaterialsActivity, "Everything is invalid", Toast.LENGTH_SHORT)
.show()
}
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
android.R.id.home -> {
finish()
return true
}
}
return super.onOptionsItemSelected(item)
}
override fun onDownload(url: String?, title: String?) {
val time = System.currentTimeMillis().toString()
val shortTime = time.substring(8, 12)
val fileName = "$title [twoRoot2]"
// downloadFile(url, fileName + ".pdf");
// downloadFile(url, fileName + ".pdf");
Toast.makeText(applicationContext, "Downloading....", Toast.LENGTH_SHORT).show()
val downloaded =
downloadHandler.downloadFile(url, "$fileName.pdf", this#MaterialsActivity, file)
// Toast.makeText(applicationContext, "D...." + downloaded, Toast.LENGTH_SHORT).show()
}
override fun onPDFSelected(file: File?) {
val intent = Intent(this#MaterialsActivity, PDFActivity::class.java)
intent.putExtra("path", file!!.absolutePath)
intent.putExtra("flag", "n")
startActivity(intent)
}
override fun onDelete(file: File?, position: Int) {
TODO("Not yet implemented")
}
override fun inExternalApp(file: File?, context: Context?) {
TODO("Not yet implemented")
}
}
Repository Class
package com.tworoot2.class9thhistoryncert.repository
import android.content.Context
import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import com.tworoot2.class9thhistoryncert.api.MaterialsService
import com.tworoot2.class9thhistoryncert.models.MaterialsElist
import com.tworoot2.class9thhistoryncert.models.MaterialsList
import com.tworoot2.result10th_12th.Internetconnection.NetworkUtils
class MaterialsRepo(private val service: MaterialsService, private val context: Context) {
private val hisHinMutableLiveData = MutableLiveData<MaterialsList>()
private val hisEngMutableLiveData = MutableLiveData<MaterialsList>()
val hisHinLiveData: LiveData<MaterialsList>
get() = hisHinMutableLiveData
val hisEngLiveData: LiveData<MaterialsList>
get() = hisEngMutableLiveData
suspend fun getHisHindi() {
if (NetworkUtils.isInternetAvailable(context)) {
val result = service.getHistoryHindiFromAPI()
if (result.body() != null) {
hisHinMutableLiveData.postValue(result.body())
}
} else {
Log.e("InternetError", "No Internet Connection")
}
}
suspend fun getHisEnglish() {
if (NetworkUtils.isInternetAvailable(context)) {
val result = service.getHistoryEnglishFromAPI()
if (result.body() != null) {
hisEngMutableLiveData.postValue(result.body())
}
}else{
Log.e("InternetError", "No Internet Connection")
}
}
}
[Screen Shot 1]
[Screen Shot 2]
Maybe you want to use LiveData to handle realtime update UI for your case. After download thread run completed, let observer call update item in recyclerview.
Hope it help!
I have a problem building a second viewModel for my app.
In my project, the first viewModel observes a list of Contact, while the second viewModel observes a single contact.
Both viewModels are really similar, but the first builds, while the second cannot construct
E/AndroidRuntime: FATAL EXCEPTION: main
Process: fr.dleurs.android.contactapp, PID: 12324
java.lang.RuntimeException: Unable to start activity ComponentInfo{fr.dleurs.android.contactapp/fr.dleurs.android.contactapp.ui.detailsContact.DetailsContactActivity}: java.lang.IllegalArgumentException: Unable to construct viewmodel
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3449)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
Caused by: java.lang.IllegalArgumentException: Unable to construct viewmodel
at fr.dleurs.android.contactapp.viewmodel.ContactViewModel$Factory.create(ContactViewModel.kt:33)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:187)
at androidx.lifecycle.ViewModelProvider.get(ViewModelProvider.java:150)
at fr.dleurs.android.contactapp.ui.detailsContact.DetailsContactActivity.onCreate(DetailsContactActivity.kt:40)
at android.app.Activity.performCreate(Activity.java:8000)
at android.app.Activity.performCreate(Activity.java:7984)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3422)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601)
at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
I/Process: Sending signal. PID: 12324 SIG: 9
The second viewModel : ContactViewModel.kt
package fr.dleurs.android.contactapp.viewmodel
import android.app.Application
import androidx.lifecycle.*
import fr.dleurs.android.contactapp.database.ContactDatabase
import fr.dleurs.android.contactapp.database.ContactsDatabase.Companion.getInstance
import fr.dleurs.android.contactapp.model.Contact
import fr.dleurs.android.contactapp.repository.ContactRepository
import kotlinx.coroutines.launch
class ContactViewModel(application: Application) : AndroidViewModel(application) {
private val contactsRepository = ContactRepository(getInstance(application).contactDtbDao())
fun liveContact(contactId: String): LiveData<Contact> = contactsRepository.contact(contactId)
public fun updateContact(contact: ContactDatabase) {
viewModelScope.launch {
contactsRepository.updateContact(contact);
}
}
public fun deleteContact(contactId: String) {
viewModelScope.launch {
contactsRepository.deleteContact(contactId);
}
}
class Factory(val app: Application) : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(ContactsViewModel::class.java)) {
#Suppress("UNCHECKED_CAST")
return ContactViewModel(app) as T
}
throw IllegalArgumentException("Unable to construct viewmodel")
}
}
}
The second activity, DetailsContactActivity.kt
package fr.dleurs.android.contactapp.ui.detailsContact
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.widget.ImageButton
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import fr.dleurs.android.contactapp.R
import fr.dleurs.android.contactapp.database.ContactDatabase
import fr.dleurs.android.contactapp.databinding.DetailsContactActivityBinding
import fr.dleurs.android.contactapp.model.Contact
import fr.dleurs.android.contactapp.model.asDatabaseModel
import fr.dleurs.android.contactapp.ui.main.createContactActivityRequestCode
import fr.dleurs.android.contactapp.ui.main.detailContactActivityRequestCode
import fr.dleurs.android.contactapp.ui.newModifyContact.CreateModifyContactActivity
import fr.dleurs.android.contactapp.viewmodel.ContactViewModel
import fr.dleurs.android.contactapp.viewmodel.ContactsViewModel
import timber.log.Timber
class DetailsContactActivity : AppCompatActivity() {
private lateinit var binding: DetailsContactActivityBinding
private lateinit var contactId: String
private lateinit var viewModel: ContactViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
contactId = intent?.getStringExtra("contactId") ?: ""
assert(!contactId.isNullOrEmpty())
viewModel = ViewModelProvider(
this,
ContactViewModel.Factory(this.application)
).get(ContactViewModel::class.java)
val buttonEdit = findViewById<ImageButton>(R.id.ibEdit)
val buttonDelete = findViewById<ImageButton>(R.id.ibDelete)
val buttonBack = findViewById<ImageButton>(R.id.ibBack)
binding = DataBindingUtil.setContentView(this, R.layout.details_contact_activity)
viewModel.liveContact(contactId).observe(this, Observer<Contact> { theContact -> // this or viewLifecycleOwner ?
theContact?.let {
binding.apply { contact = it }
}
})
buttonEdit.setOnClickListener {
val editIntent = Intent(this, CreateModifyContactActivity::class.java)
//editIntent.putExtra("contact", it)
startActivityForResult(editIntent, createContactActivityRequestCode)
}
buttonDelete.setOnClickListener {
viewModel.deleteContact(contactId)
finish()
}
buttonBack.setOnClickListener {
val replyIntent = Intent()
setResult(Activity.RESULT_CANCELED, replyIntent)
finish()
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, intentData: Intent?) {
if (requestCode == createContactActivityRequestCode && resultCode == Activity.RESULT_OK ) {
val modifiedIntent = Intent()
val modifiedContact = intentData?.getParcelableExtra<ContactDatabase>("contact")
Timber.i("modifiedContact : " + modifiedContact.toString())
val contact: Contact = Contact(
id = modifiedContact!!.id.toString(),
firstName = modifiedContact!!.firstName,
lastName = modifiedContact!!.lastName,
mail = modifiedContact!!.mail
)
modifiedIntent.putExtra("action", "modify")
modifiedIntent.putExtra("contact", contact)
setResult(Activity.RESULT_OK, modifiedIntent)
finish()
}
super.onActivityResult(requestCode, resultCode, intentData)
}
}
The repository : ContactRepository.kt
package fr.dleurs.android.contactapp.repository
import android.util.Log
import androidx.lifecycle.LiveData
import androidx.lifecycle.Transformations
import fr.dleurs.android.contactapp.database.*
import fr.dleurs.android.contactapp.model.Contact
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import timber.log.Timber
import fr.dleurs.android.contactapp.network.asDatabaseModel
import java.util.logging.Level.INFO
class ContactRepository(private val contactDtbDao: ContactDtbDao) {
val contacts: LiveData<List<Contact>> =
Transformations.map(contactDtbDao.getContacts()) {
it.asDomainModel()
}
fun contact(contactId: String): LiveData<Contact> =
Transformations.map(contactDtbDao.getContact(contactId)) { it.asDomailModel() }
suspend fun refreshContacts() {
withContext(Dispatchers.IO) {
Log.i("ContactRepo", "Refresh contacts is called");
val contactList = ContactRetrofitApi.contacts.getContacts()
Log.i("ContactRepo", "ContactList created ${contactList.toString()}");
contactDtbDao.insertAll(contactList.asDatabaseModel())
}
}
suspend fun insertContact(contact: ContactDatabase) {
withContext(Dispatchers.IO) {
contactDtbDao.insert(contact);
}
}
suspend fun deleteContact(contactId: String) {
withContext(Dispatchers.IO) {
contactDtbDao.delete(contactId);
}
}
suspend fun updateContact(contact: ContactDatabase) {
withContext(Dispatchers.IO) {
contactDtbDao.update(contact);
}
}
}
The working ViewModel, ContactsViewModel.kt :
package fr.dleurs.android.contactapp.viewmodel
import android.app.Application
import android.util.Log
import androidx.lifecycle.*
import fr.dleurs.android.contactapp.database.ContactDatabase
import fr.dleurs.android.contactapp.database.ContactsDatabase
import fr.dleurs.android.contactapp.model.Contact
import fr.dleurs.android.contactapp.repository.ContactRepository
import kotlinx.coroutines.launch
import java.io.IOException
class ContactsViewModel(application: Application) : AndroidViewModel(application) {
//private val contactsRepository = ContactRepository(ContactsDatabase.getDatabase(application))
private val contactsRepository = ContactRepository(ContactsDatabase.getInstance(application).contactDtbDao())
var liveContacts: LiveData<List<Contact>> = contactsRepository.contacts
public fun insertContact(contact: ContactDatabase) {
viewModelScope.launch {
contactsRepository.insertContact(contact);
}
}
/**
* Event triggered for network error. This is private to avoid exposing a
* way to set this value to observers.
*/
private var _eventNetworkError = MutableLiveData<Boolean>(false)
/**
* Event triggered for network error. Views should use this to get access
* to the data.
*/
val eventNetworkError: LiveData<Boolean>
get() = _eventNetworkError
/**
* Flag to display the error message. This is private to avoid exposing a
* way to set this value to observers.
*/
private var _isNetworkErrorShown = MutableLiveData<Boolean>(false)
/**
* Flag to display the error message. Views should use this to get access
* to the data.
*/
val isNetworkErrorShown: LiveData<Boolean>
get() = _isNetworkErrorShown
/**
* init{} is called immediately when this ViewModel is created.
*/
init {
refreshDataFromRepository()
}
/**
* Refresh data from the repository. Use a coroutine launch to run in a
* background thread.
*/
private fun refreshDataFromRepository() {
viewModelScope.launch {
try {
contactsRepository.refreshContacts()
_eventNetworkError.value = false
_isNetworkErrorShown.value = false
} catch (networkError: IOException) {
// Show a Toast error message and hide the progress bar.
Log.i("ContactViewModel", "Error on refreshContact : ${networkError.toString()}")
if (liveContacts.value.isNullOrEmpty())
_eventNetworkError.value = true
}
}
}
/**
* Resets the network error flag.
*/
fun onNetworkErrorShown() {
_isNetworkErrorShown.value = true
}
class Factory(val app: Application) : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(ContactsViewModel::class.java)) {
#Suppress("UNCHECKED_CAST")
return ContactsViewModel(app) as T
}
throw IllegalArgumentException("Unable to construct viewmodel")
}
}
}
The working activity, ContactActivity.kt
package fr.dleurs.android.contactapp.ui.main
import android.app.Activity
import android.content.Intent
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.ViewModelProvider
import androidx.viewpager.widget.ViewPager
import com.google.android.material.tabs.TabLayout
import fr.dleurs.android.contactapp.R
import fr.dleurs.android.contactapp.database.ContactDatabase
import fr.dleurs.android.contactapp.model.Contact
import fr.dleurs.android.contactapp.model.asDatabaseModel
import fr.dleurs.android.contactapp.ui.detailsContact.DetailsContactActivity
import fr.dleurs.android.contactapp.ui.newModifyContact.CreateModifyContactActivity
import fr.dleurs.android.contactapp.utils.FabButtonInterface
import fr.dleurs.android.contactapp.viewmodel.ContactsViewModel
import timber.log.Timber
public val createContactActivityRequestCode = 1
public val detailContactActivityRequestCode = 2
class ContactActivity : AppCompatActivity(), FabButtonInterface, OnClick {
private lateinit var viewModel: ContactsViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel = ViewModelProvider(
this,
ContactsViewModel.Factory(this.application)
).get(ContactsViewModel::class.java)
setContentView(R.layout.contact_activity)
val sectionsPagerAdapter =
SectionsPagerAdapter(context = this, fm = supportFragmentManager, onClick = this)
val viewPager: ViewPager = findViewById(R.id.contentFragment)
viewPager.adapter = sectionsPagerAdapter
val tabs: TabLayout = findViewById(R.id.tabs)
tabs.setupWithViewPager(viewPager)
}
override fun goToCreateContactActivity() {
Timber.i("Create a new contact started")
val intent = Intent(this, CreateModifyContactActivity::class.java)
startActivityForResult(intent, createContactActivityRequestCode)
}
fun goToDetailContactActivity(contactId: String) {
Timber.i("Details contact started")
val intent = Intent(this, DetailsContactActivity::class.java)
intent.putExtra("contactId", contactId)
startActivity(intent)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, intentData: Intent?) {
super.onActivityResult(requestCode, resultCode, intentData)
if (requestCode == createContactActivityRequestCode && resultCode == Activity.RESULT_OK) {
Timber.i("Intent received")
val response = intentData?.getParcelableExtra<ContactDatabase>("contact")
val newContact = ContactDatabase(
firstName = response!!.firstName,
lastName = response!!.lastName,
mail = response!!.mail
)
Timber.i("Intent received + " + newContact.toString())
viewModel.insertContact(newContact)
} else if (requestCode == createContactActivityRequestCode && resultCode == Activity.RESULT_CANCELED) {
} else if (requestCode == detailContactActivityRequestCode) {
Timber.i("DetailsContactActivity intent :" + intent.toString() + ", intentData: "+intentData.toString()+"resultCode :" + resultCode.toString())
if (resultCode == Activity.RESULT_CANCELED) {
Timber.i("DetailsContactActivity closed with no action")
}
} else {
Toast.makeText(this, "Error creating contact", Toast.LENGTH_LONG).show()
}
}
override fun onItemClick(contactId: String) {
Timber.i("On Item clicked + " + contactId)
goToDetailContactActivity(contactId)
}
}
Thank you for your help !
here you are passing ContactsViewModel::class.java. You have to pass ContactViewModel::class.java
class Factory(val app: Application) : ViewModelProvider.Factory {
override fun <T : ViewModel?> create(modelClass: Class<T>): T {
if (modelClass.isAssignableFrom(ContactViewModel::class.java)) {
#Suppress("UNCHECKED_CAST")
return ContactViewModel(app) as T
}
throw IllegalArgumentException("Unable to construct viewmodel")
}
}
How can I make progressbar dialog custom for kotlin
I think I should put it in setonclicklistener.
I already make custom progressbar XML
but I don't active this progressbar in kotlin
In Google
I don't know active in my code
package com.korea50k.tracer.ranking
import android.content.Context
import android.content.Intent
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.korea50k.tracer.R
import com.korea50k.tracer.dataClass.InfoData
import kotlinx.android.synthetic.main.recycler_rankfragment_item.view.*
class RankRecyclerViewAdapterMap (val mdata :ArrayList<InfoData>) : RecyclerView.Adapter<RankRecyclerViewAdapterMap.mViewHolder>() {
var context : Context? = null
//생성된 뷰 홀더에 데이터를 바인딩 해줌.
override fun onBindViewHolder(holder: mViewHolder, position: Int) {
val singleItem = mdata[position]
var ranking = position + 1
var cutted = singleItem.mapTitle!!.split("||")
//데이터 바인딩
holder.rank.text = ranking.toString()
holder.maptitle.text = cutted[0]
holder.execute.text = singleItem.execute.toString()
//ranking에 따라 트로피 색 바뀌게 하는 부분
if (ranking == 1)
holder.rank.setBackgroundResource(R.drawable.ic_1)
else if (ranking == 2)
holder.rank.setBackgroundResource(R.drawable.ic_2)
else if (ranking == 3)
holder.rank.setBackgroundResource(R.drawable.ic_3)
else
holder.rank.setBackgroundResource(R.drawable.ic_4)
//클릭하면 맵 상세보기 페이지로 이동
holder.itemView.setOnClickListener{
val nextIntent = Intent(context, RankRecyclerItemClickActivity::class.java)
nextIntent.putExtra("MapTitle", singleItem.mapTitle) //mapTitle 정보 인텐트로 넘김
context!!.startActivity(nextIntent)
}
}
//뷰 홀더 생성
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): mViewHolder {
val view = LayoutInflater.from(parent.context).inflate(R.layout.recycler_rankfragment_item, parent, false)
Log.d("rank", "onCreateViewHolder호출")
context = parent.context
return mViewHolder(view) //view 객체는 한개의 리사이클러뷰가 디자인 되어 있는 레이아웃을 의미
}
//item 사이즈, 데이터의 전체 길이 반ㅎ환
override fun getItemCount(): Int {
Log.d("rank", "데이터 크기 " + mdata.size.toString())
//return 10 //TODO 갯수 조절 여기서
return mdata.size
}
//여기서 item을 textView에 옮겨줌
inner class mViewHolder(view: View) : RecyclerView.ViewHolder(view!!) {
var rank = view.rankingFragmentCountTextView
var maptitle = view.rankingFragmentMapTitleTextView
var execute = view.rankingFragmentExecuteTextView
}
}
package com.korea50k.tracer.ranking
import android.content.Intent
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import androidx.recyclerview.widget.LinearLayoutManager
import com.bumptech.glide.Glide
import com.google.firebase.firestore.FirebaseFirestore
import com.google.firebase.firestore.Query
import com.google.firebase.storage.FirebaseStorage
import com.korea50k.tracer.R
import com.korea50k.tracer.dataClass.InfoData
import com.korea50k.tracer.dataClass.RankRecyclerItemClickItem
import com.korea50k.tracer.dataClass.RankingData
import kotlinx.android.synthetic.main.activity_rank_recycler_item_click.*
import kotlinx.android.synthetic.main.fragment_ranking.view.*
class RankRecyclerItemClickActivity : AppCompatActivity() {
lateinit var mapRankingDownloadThread: Thread
var arrRankingData: ArrayList<RankingData> = arrayListOf()
var rankingData = RankingData()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_rank_recycler_item_click)
val intent = getIntent()
//전달 받은 값으로 Title 설정
var mapTitle = intent.extras?.getString("MapTitle").toString()
var cutted = mapTitle.split("||")
rankRecyclerMapTitle.text = cutted[0]
//TODO:ImageView 에 이미지 박는 코드 (firebase)
val imageView = rankRoutePriview
val storage = FirebaseStorage.getInstance("gs://tracer-9070d.appspot.com/")
val mapImageRef = storage.reference.child("mapImage").child(mapTitle)
mapImageRef.downloadUrl.addOnCompleteListener { task ->
if (task.isSuccessful) {
// Glide 이용하여 이미지뷰에 로딩
Log.d("ssmm11", "이미지 뷰 로드 성공 : "+mapImageRef.downloadUrl)
Glide.with(this#RankRecyclerItemClickActivity)
.load(task.result)
.override(1024, 980)
.into(imageView)
} else {
Log.d("ssmm11", "이미지 뷰 로드 실패")
}
}
mapRankingDownloadThread = Thread(Runnable {
val db = FirebaseFirestore.getInstance()
db.collection("rankingMap").document(mapTitle).collection("ranking").orderBy("challengerTime", Query.Direction.ASCENDING)
.get()
.addOnSuccessListener { result ->
for (document in result) {
rankingData = document.toObject(RankingData::class.java)
arrRankingData.add(rankingData)
}
//레이아웃 매니저 추가
rankRecyclerItemClickRecyclerView.layoutManager = LinearLayoutManager(this)
//adpater 추가
Log.d("ssmm11", "받아옴 ? = "+ arrRankingData)
rankRecyclerItemClickRecyclerView.adapter = RankRecyclerViewAdapterTopPlayer(arrRankingData)
}
.addOnFailureListener { exception ->
}
})
mapRankingDownloadThread.start()
rankRecyclerMoreButton.setOnClickListener{
val nextIntent = Intent(this, RankingMapDetailActivity::class.java)
nextIntent.putExtra("MapTitle", mapTitle)
startActivity(nextIntent)
}
}
}