Activity Can not close while call from Fragment - android

I have created a Sales Order menu, the menu uses the Activity and Fragment files,
The problem is when I display the Customer List page to find customer data that will be used on the SalesOrder page (Create Data tab (use Fragment))
CustomerList page not closed,
Here's my code
First run show
enter image description here
Then I clik Sales Order show like this, its file SalesOrderActivity.kt
Page SalesOrder use TabLayout and Fragment , ie (fragment for Create Data and Fragment List Data)
enter image description here
File SalesOrderActivity.kt
class SalesOrderActivity : AppCompatActivity() {
lateinit var viewPager : ViewPager
lateinit var tabs : TabLayout
private var appContext: Context? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_sales_order)
CommonCtx.setViewXml2(contentView)
setSupportActionBar(findViewById(R.id.my_toolbar))
supportActionBar!!.title = "Sales Order"
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
viewPager = findViewById(R.id.viewPager)
tabs = findViewById(R.id.tabs)
tabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener {
override fun onTabSelected(tab: TabLayout.Tab?) {
val position = tab?.position
if (position == 1) {
println("get selected")
}
}
override fun onTabUnselected(tab: TabLayout.Tab?) {
}
override fun onTabReselected(tab: TabLayout.Tab?) {
}
})
appContext = this
CommonCtx.setActivity(this)
setUpTabs()
}
//SHOW FRAGMENT CREATE DATA AND LIST DATA
private fun setUpTabs(){
val adapter = com.myapp.sfa.adapter.ViewPagerAdapter(supportFragmentManager)
adapter.addFragment(SalesOrderCreateDataFragment(), "Create Data")
adapter.addFragment(CustomerListDataFragment(), "List Data")
viewPager.adapter = adapter
tabs.setupWithViewPager(viewPager)
setupTabIcons()
}
private fun setupTabIcons() {
tabs.getTabAt(0)!!.setIcon(tabIcons.get(0))
tabs.getTabAt(1)!!.setIcon(tabIcons.get(1))
}
private val tabIcons = intArrayOf(
R.drawable.add_sign,
R.drawable.list_48
)
override fun onSupportNavigateUp(): Boolean {
finish()
return true
}
}
in page Sales Order I used fragment for show tab Create Data and List Data
this
file SalesOderCreateDataFragment.kt
class SalesOrderCreateDataFragment : Fragment() {
private var appContext: Context? = null
private lateinit var txtvCustId : TextView
public lateinit var edtCustCode : EditText
private lateinit var btnCustomer : Button
lateinit var DBHelper : DBHelper
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
appContext = this.getActivity()
DBHelper = DBHelper(appContext!!))
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
val view = inflater.inflate(R.layout.fragment_sales_order_create_data,container,false)
txtvCustId = view.findViewById<TextView>(R.id.txtvCustId)
edtCustCode = view.findViewById<EditText>(R.id.edtCustCode)
btnCustomer = view.findViewById(R.id.btnCustomer)
btnCustomer.setOnClickListener {
showCustomer()
}
appContext = this.getActivity()
return view
}
//SHOW LIST CUSTOMER event clik Cust. Code
fun showCustomer() {
val intent = Intent(this.getActivity(), CustomerListActivity::class.java)
//intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP)
intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
CommonCtx.getContext().startActivity(intent)
CustomerListActivity().finish()
}
fun getCustomer(idCustomer: String){
var customerPojo = CustomerPojo()
customerPojo= SQLCustomer().getCustomerById(idCustomer)
}
}
while I click button Cust Code
enter image description here
Will show page CustomerListActivity, like this picture
Code in Cust code event
enter image description here
File CustomerListActivity.kt
class CustomerListActivity : AppCompatActivity() {
private lateinit var recyclerView : RecyclerView
lateinit var DBHelper : DBHelper
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_customer_list)
setSupportActionBar(findViewById(R.id.my_toolbar))
supportActionBar!!.title = "Customer List"
supportActionBar!!.setDisplayHomeAsUpEnabled(true)
recyclerView =findViewById(R.id.recyclerView)
DBHelper = DBHelper(applicationContext)//this)
//get data customer in database local
var listCustomerPojo : MutableList<CustomerPojo> = ArrayList()
listCustomerPojo = SQLCustomer().getCustomerList()
//show data customer in Recycle Card View
showListDataToRecycleCardView(listCustomerPojo);
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.main, menu)
val searchItem = menu.findItem(R.id.menu_search)
if(searchItem != null){
val searchView = searchItem.actionView as SearchView
val editext = searchView.findViewById<EditText>
(androidx.appcompat.R.id.search_src_text)
editext.hint = "Search here..."
searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(query: String?): Boolean {
return true
}
override fun onQueryTextChange(newText: String?): Boolean {
var listCustomerPojo: ArrayList<CustomerPojo> = ArrayList()
if (newText!!.isNotEmpty()) {
val search = newText.toLowerCase()
listCustomerPojo = SQLCustomer().getCustomerByName(newText)
}
showListDataToRecycleCardView(listCustomerPojo);
return true
}
})
}
return super.onCreateOptionsMenu(menu)
}
fun showListDataToRecycleCardView(listCustomerPojo: MutableList<CustomerPojo>){
var customerListDC = arrayListOf<CustomerDataModel>()
for (i in 0 until listCustomerPojo.size) {
var custPojo: CustomerPojo = listCustomerPojo[i]
val cdm = CustomerDataModel(R.drawable.shop_on_ballon_36,
custPojo.custId.toString(),
custPojo.custCode.toString(),
custPojo.custName.toString(),
custPojo.address.toString())
customerListDC.add(cdm)
}
val recyclerAdapter = CustomerListRecyclerAdapter(customerListDC)
recyclerView.apply {
adapter = recyclerAdapter
addItemDecoration(DividerItemDecoration(CommonCtx.getContext(),
DividerItemDecoration.VERTICAL))
setHasFixedSize(true)
}
}
override fun onSupportNavigateUp(): Boolean {
finish()
return true
}
}
file CustomerListRecyclerAdapter.kt
class CustomerListRecyclerAdapter(private var customerListData: ArrayList<CustomerDataModel>)
: RecyclerView.Adapter<CustomerListRecyclerAdapter.ViewHolder>(){
var appContext: Context? = null
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
val view = layoutInflater.inflate(R.layout.recycler_customer_list, parent, false)
appContext = parent.context
return ViewHolder(view)
}
override fun getItemCount(): Int = customerListData.size
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
val movie = customerListData[position]
holder.bind(movie)
}
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
val intent: Intent? = null
init {
itemView.setOnClickListener {
var textvCustId = itemView.findViewById<TextView>(R.id.textvCustId)
var textvCustName = itemView.findViewById<TextView>(R.id.textvCustName)
}
}
fun bind(model: CustomerDataModel) {
var imgViewIcon = itemView.findViewById<ImageView>(R.id.imgViewIcon)
var textvCustId = itemView.findViewById<TextView>(R.id.textvCustId)
var textvCustCode = itemView.findViewById<TextView>(R.id.textvCustCode)
var textvCustName = itemView.findViewById<TextView>(R.id.textvCustName)
var textvAddress = itemView.findViewById<TextView>(R.id.textvAddress)
var btnCreateSO = itemView.findViewById<Button>(R.id.btnCreateSO)
var btnCreateSR = itemView.findViewById<Button>(R.id.btnCreateSR)
imgViewIcon.setImageResource(model.iconPict)
textvCustId.text = model.custId
textvCustCode.text = model.custCode
textvCustName.text = model.custName
textvAddress.text = model.address
textvCustId.setVisibility(View.INVISIBLE)
btnCreateSO.setOnClickListener {
SalesOrderCreateDataFragment().getCustomer(textvCustId.text.toString())
}
}
}//end class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
}
File CommonCtx.kt
#SuppressLint("StaticFieldLeak")
abstract class CommonCtx {
companion object {
#Volatile
private lateinit var appContext : Context
private lateinit var mainActivity : Activity
private lateinit var myActivity : Activity
private lateinit var myView : View
private lateinit var myView2 : View
private lateinit var myView3 : View
private lateinit var myContainer: ViewGroup
fun setContext(context: Context) {
appContext = context
}
fun getFilesDir():String {
return appContext.filesDir.absolutePath
}
fun getOpenFileInput(fileName : String): FileInputStream {
return appContext.openFileInput(fileName)
}
fun getOpenFileOutput(fileName : String): FileOutputStream {
return appContext.openFileOutput(fileName, MODE_PRIVATE)
}
fun getContext():Context{
return appContext
}
fun getContext2():Context{
return appContext.applicationContext
}
fun setMainActivity(activity: Activity) {
mainActivity = activity
}
fun getMainActivity():Activity{
return mainActivity
}
fun setActivity(activity: Activity) {
myActivity = activity
}
fun getActivity():Activity{
return myActivity
}
fun setViewXml(view : View) {
myView = view
}
fun getViewXml():View{
return myView
}
fun setViewXml2(view: View?) {
if (view != null) {
myView2 = view
}
}
fun getViewXml2():View{
return myView2
}
fun setViewXml3(view: View?) {
if (view != null) {
myView3 = view
}
}
fun getViewXml3():View{
return myView3
}
fun setContainer(container : ViewGroup) {
myContainer = container
}
fun getContainer():ViewGroup{
return myContainer
}
}
}
File AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.myapp.sfa">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_MEDIA_LOCATION" />
<uses-permission android:name="android.permission.WRITE_INTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_INTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:networkSecurityConfig="#xml/network_security_config"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/Theme.MyAppSFA">
<activity android:name=".view.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".ui.view.NetworkSettingActivity"
android:screenOrientation="portrait" />
<activity android:name=".ui.view.salesman.SalesmanProfileActivity"
android:screenOrientation="portrait" />
<activity android:name=".ui.view.sales.SalesOrderActivity"
android:launchMode="singleTop"/>
<activity android:name=".ui.view.sales.SalesReturnActivity"/>
<activity android:name=".view.ui.customer.CustomerActivity" />
<activity android:name=".view.ui.list.CustomerListActivity"
android:noHistory="true"/>
<activity android:name=".view.ui.list.ProductItemListActivity" />
</application>
</manifest>
Problem , while I click button Create SO in page CustomerListActivity
Page CustomerListActivity is not Closed and back to Page SalesOrderActivity
Thanks
enter image description here

in this code, file CustomerListRecyclerAdapter.kt
is not working, CustomerListActivity.kt not close
btnCreateSO.setOnClickListener {
SalesOrderCreateDataFragment().getCustomer(textvCustId.text.toString())
}

this is my file build.gradle(:app)
plugins {
id 'com.android.application'
id 'kotlin-android'
id 'kotlin-kapt'
}
android {
compileSdkVersion 30
buildToolsVersion "30.0.3"
defaultConfig {
applicationId "com.myapp.sfa"
minSdkVersion 16
targetSdkVersion 30
versionCode 1
versionName "1.0"
multiDexEnabled true
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
buildFeatures {
viewBinding true
}
dataBinding {
enabled = true
}
sourceSets {
main {
res.srcDirs = [
'src/main/res',
'src/main/res/layout',
'src/main/res/layout/fragments',
'src/main/res/layout/salesaction',
'src/main/res/layout/salesman',
'src/main/res/layout/setting',
'src\\main\\res', 'src\\main\\res\\layout\\itemrecycler', 'src\\main\\res\\layout\\product', 'src\\main\\res\\layout\\customer'
]
}
//debug {
// res.srcDirs = ['resources/debug']
//}
}
}
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation "org.jetbrains.anko:anko:0.10.8"
implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.9'
implementation 'com.squareup.retrofit2:retrofit:2.9.0'
implementation 'com.squareup.retrofit2:converter-gson:2.6.1'
implementation "com.squareup.retrofit2:converter-moshi:2.4.0"
implementation 'com.squareup.okhttp3:logging-interceptor:4.4.0'
implementation 'com.squareup.okhttp3:okhttp:4.9.0'
implementation 'com.jakewharton.picasso:picasso2-okhttp3-downloader:1.1.0'
implementation 'com.google.code.gson:gson:2.8.6'
implementation 'androidx.lifecycle:lifecycle-common:2.2.0'
implementation 'androidx.lifecycle:lifecycle-runtime:2.2.0'
implementation 'android.arch.lifecycle:extensions:2.2.0'
implementation 'androidx.lifecycle:lifecycle-livedata-ktx:2.2.0'
implementation "androidx.viewpager:viewpager:1.0.0"
implementation 'com.google.android.material:material:1.3.0'
implementation 'androidx.appcompat:appcompat:1.3.0-rc01'
implementation 'androidx.legacy:legacy-support-v4:1.0.0'
implementation 'androidx.cardview:cardview:1.0.0'
implementation "androidx.recyclerview:recyclerview:1.1.0"
implementation 'com.github.bumptech.glide:glide:4.9.0'
implementation 'androidx.multidex:multidex:2.0.1'
implementation 'androidx.swiperefreshlayout:swiperefreshlayout:1.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
androidTestImplementation "org.jetbrains.kotlin:kotlin-test-
junit:$kotlin_version"
}
any other ideas, should i change the way to display the Customer list?
Thanks

i have add code (itemView.context as Activity).finish() in CustomerListRecycleAdapter.kt
btnCreateSO.setOnClickListener {
SalesOrderActivity().selectedTabForUpdate(textvCustId.text.toString())
(itemView.context as Activity).finish()
}
and this work, Customer List close
Thanks all

Related

Data isn't updating in Firestore database

My first time asking questions here I think I'm going insane. Working on a school project, I am creating an app like Goodreads, I have recyclerView which lists all the books from database(reading data works fine) and a different fragment where you can write a review for each book. So I have 3 layouts(main_activity layout,review layout and a layout that designs an item for recyclerView).
The problem is when I click save button which is supposed to save a review ni database it does nothing. I have a collection called "books" which has 8 documents and fields such as title,author,rating,image,review. All fields are string types. My rules allow writing and reading data. I have no idea what to do if anyone has better insight I will be really thankful
Main activity:
class MainActivity : AppCompatActivity(),BookRecyclerAdapter.ContentListener {
private lateinit var recyclerAdapter: BookRecyclerAdapter
private val db = Firebase.firestore
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(layout.activity_main)
val recyclerView = findViewById<RecyclerView>(id.booksList)
db.collection("books")
.get() //da dohvati sve dokumente
.addOnSuccessListener { //unutar ovoga pristup svim podadcima koji su se ucitali
val items: ArrayList<Book> = ArrayList()
for (data in it.documents) { //stvori novu data varijablu za svaki dohvaceni dokument(element?)
val book =
data.toObject(Book::class.java) //sve podatke pretvaramo u model preko toObject u Person
if (book != null) {
book.id = data.id //postavljanje ida
items.add(book) //dodavanje gotovog eprsona u listu
}
}
recyclerAdapter = BookRecyclerAdapter(items, this#MainActivity)
recyclerView.apply {
layoutManager = LinearLayoutManager(this#MainActivity)
adapter = recyclerAdapter
}
}.addOnFailureListener { exception ->
Log.w("MainActivity", "Error getting documents", exception)
}
}
override fun onItemButtonClick(index: Int, item: Book, clickType: ItemClickType) {
if (clickType == ItemClickType.SAVE) {
db.collection("books").document(item.id)
.set(item)
.addOnSuccessListener { Log.d(TAG, "DocumentSnapshot successfully written!") }
.addOnFailureListener { e -> Log.w(TAG, "Error writing document", e) }
}
else if (clickType == ItemClickType.REVIEW) {
val newFragment: Fragment = ReviewFragment()
val transaction: FragmentTransaction? = supportFragmentManager.beginTransaction()
transaction?.replace(R.id.container, newFragment);
transaction?.addToBackStack(null);
transaction?.commit();
}
}
}
BookRecyclerAdapter
package hr.ferit.enasalaj.zavrsni
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Button
import android.widget.EditText
import android.widget.ImageView
import android.widget.Toast
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
enum class ItemClickType {
SAVE,
REVIEW
}
class BookRecyclerAdapter(
val items:ArrayList<Book>,
val listener: ContentListener,
): RecyclerView.Adapter<RecyclerView.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val mainView = LayoutInflater.from(parent.context).inflate(R.layout.recycler_view_books, parent, false)
val reviewView = LayoutInflater.from(parent.context).inflate(R.layout.review, parent, false)
return BookViewHolder(mainView, reviewView)
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is BookViewHolder -> {
holder.bind(position, listener, items[position])
}
}
}
override fun getItemCount(): Int {
return items.size
}
class BookViewHolder(val view: View,val review: View): RecyclerView.ViewHolder(view) {
private val bookImage =
view.findViewById<ImageView>(R.id.image)
private val bookAuthor =
view.findViewById<EditText>(R.id.bookAuthor)
private val bookTitle =
view.findViewById<EditText>(R.id.bookTitle)
private val bookRating =
view.findViewById<EditText>(R.id.bookRating)
private val reviewButton =
view.findViewById<Button>(R.id.writeReviewButton)
public val saveButton =
review.findViewById<Button>(R.id.saveButton)
public val bookReview =
review.findViewById<EditText>(R.id.saveReview)
fun bind(
index: Int,
listener: ContentListener,
item: Book,
) {
Glide.with(view.context).load(item.image).into(bookImage)
bookAuthor.setText(item.author)
bookTitle.setText(item.title)
bookRating.setText(item.rating)
bookReview.setText(item.review)
reviewButton.setOnClickListener {
listener.onItemButtonClick(index,item,ItemClickType.REVIEW)
}
saveButton.setOnClickListener{
listener.onItemButtonClick(index,item,ItemClickType.SAVE)
}
}
}
interface ContentListener {
fun onItemButtonClick(index: Int, item: Book, clickType: ItemClickType)
}
}
And here is my gradle file:
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'com.google.gms.google-services'
}
android {
namespace 'hr.ferit.enasalaj.zavrsni'
compileSdk 32
defaultConfig {
applicationId "hr.ferit.enasalaj.zavrsni"
minSdk 21
targetSdk 32
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
dependencies {
implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.appcompat:appcompat:1.5.1'
implementation 'com.google.android.material:material:1.7.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation 'com.google.firebase:firebase-firestore-ktx:24.4.1'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.4'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0'
implementation 'com.github.bumptech.glide:glide:4.14.2'
implementation "com.google.firebase:firebase-auth:9.6.1"
implementation 'com.google.firebase:firebase-database:9.6.1'
annotationProcessor 'com.github.bumptech.glide:compiler:4.14.2'
apply plugin: 'com.google.gms.google-services'
}

Showing this error - Getting Unresolved reference

i'll Check id's and Everything Was Right!! but I don't know what is the problem.
errors :
Unresolved reference: synthetic
Unresolved reference: btnLogin
Unresolved reference: btnSignUp
Unresolved reference: etEmailAddress
Unresolved reference: etPassword
My LoginActivity
class LoginActivity : AppCompatActivity() {
lateinit var firebaseAuth: FirebaseAuth
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login)
firebaseAuth = FirebaseAuth.getInstance()
btnLogin.setOnClickListener {
login()
}
btnSignUp.setOnClickListener {
val intent = Intent(this, SignupActivity::class.java)
startActivity(intent)
finish()
}
}
private fun login(){
val email = etEmailAddress.text.toString()
val password = etPassword.text.toString()
if (email.isBlank() || password.isBlank()) {
Toast.makeText(this, "Email/password cannot be empty", Toast.LENGTH_SHORT).show()
return
}
firebaseAuth.signInWithEmailAndPassword(email, password).addOnCompleteListener(this){
if(it.isSuccessful){
Toast.makeText(this, "Success", Toast.LENGTH_SHORT).show()
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
finish()
}
else{
Toast.makeText(this, "Authentication Failed", Toast.LENGTH_SHORT).show()
}
}
}
}
My AndroidManifest
<uses-permission android:name="android.permission.INTERNET" />
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppThemeNoActionBar">
<activity android:name=".activities.ProfileActivity"/>
<activity android:name=".activities.ResultActivity" />
<activity
android:name=".activities.QuestionActivity"
android:theme="#style/AppTheme" />
<activity android:name=".activities.LoginActivity" />
<activity android:name=".activities.SignupActivity" />
<activity android:name=".activities.LoginIntro" />
<activity android:name=".activities.MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
my Build.Gradle
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'com.google.gms.google-services'
android {
compileSdkVersion 32
defaultConfig {
applicationId "com.cheezycode.quizzed"
minSdkVersion 21
targetSdkVersion 32
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildFeatures {
viewBinding = true
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
namespace 'com.cheezycode.quizzed'
}
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'com.google.firebase:firebase-auth:19.3.2'
implementation 'com.google.firebase:firebase-firestore:22.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
implementation 'com.google.android.material:material:1.1.0'
implementation 'com.google.code.gson:gson:2.8.6'
}
Try this once-
You missed the initialization.
Suppose you don't want to do initialization use View binding
USING VIEW BINDING AS PER your gradle use
class LoginActivity : AppCompatActivity() {
lateinit var firebaseAuth: FirebaseAuth
private var _binding: ActivityLoginBinding? = null
private val binding get() = _binding!!
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
_binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
firebaseAuth = FirebaseAuth.getInstance()
binding.btnLogin.setOnClickListener {
login()
}
binding.btnSignUp.setOnClickListener {
val intent = Intent(this, SignupActivity::class.java)
startActivity(intent)
finish()
}
}
private fun login(){
val email = binding.etEmailAddress.text.toString()
val password = binding.etPassword.text.toString()
if (email.isBlank() || password.isBlank()) {
Toast.makeText(this, "Email/password cannot be empty", Toast.LENGTH_SHORT).show()
return
}
override fun onDestroy() {
super.onDestroy()
_binding = null
}
Option 2-
class LoginActivity : AppCompatActivity() {
lateinit var firebaseAuth: FirebaseAuth
private var btnLogin: Button? = null
private var btnSignUp: Button? = null
private var etEmailAddress: EditText? = null
private var etPassword: EditText? = null
lateinit var firebaseAuth: FirebaseAuth
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login)
firebaseAuth = FirebaseAuth.getInstance()
btnLogin = findViewById(R.id.btnLogin)
btnSignUp = findViewById(R.id.btnSignUp)
etEmailAddress = findViewById(R.id.etEmailAddress)
etPassword = findViewById(R.id.etPassword)
btnLogin?.setOnClickListener {
login()
}
btnSignUp?.setOnClickListener {
val intent = Intent(this, SignupActivity::class.java)
startActivity(intent)
finish()
}
}
private fun login() {
val email = etEmailAddress?.text.toString()
val password = etPassword?.text.toString()
if (email.isBlank() || password.isBlank()) {
Toast.makeText(this, "Email/password cannot be empty", Toast.LENGTH_SHORT).show()
return
}
firebaseAuth.signInWithEmailAndPassword(email, password).addOnCompleteListener(this) {
if (it.isSuccessful) {
Toast.makeText(this, "Success", Toast.LENGTH_SHORT).show()
val intent = Intent(this, MainActivity::class.java)
startActivity(intent)
finish()
} else {
Toast.makeText(this, "Authentication Failed", Toast.LENGTH_SHORT).show()
}
}
}

Configuration Changes Not Save App State MVVM

I am building a movie app. There is a recyclerview matching parent size,and 1 search action button(SearchView).
When I search for a movie,everything is working fine,but when I change orientation,the activity just lose it's state. the recyclerview turns empty and I need to search for the movie again.
I am using MVVM and I know its not suppose to happen..
Thank you!
This is the Repository:
class MainRepository {
private val searchAfterMutableLiveData = MutableLiveData<List<Movie>>()
private val apiService : GetFromApi = APIService.retrofitClientRequest
private val apiKey = "censored"
fun searchAfter(searchAfter : String) : MutableLiveData<List<Movie>>{
apiService.searchAfter(apiKey,searchAfter)?.enqueue(object : Callback<MovieListResult?> {
override fun onResponse(
call: Call<MovieListResult?>,
response: Response<MovieListResult?>
) {
if (response.isSuccessful){
searchAfterMutableLiveData.value = response.body()?.moviesResults
Log.e("SearchMovieListResults","Result: ${searchAfterMutableLiveData.value}")
}
}
override fun onFailure(call: Call<MovieListResult?>, t: Throwable) {
Log.e("SearchMovieListResults","Failed: ${t.message}")
}
})
return searchAfterMutableLiveData
}
}
This is the ViewModel:
class MainViewModel : ViewModel(){
fun getMovieBySearch(searchAfter : String) : LiveData<List<Movie>>{
return mainRepository.searchAfter(searchAfter)
}
}
This is the MainActivity:
class MainActivity : AppCompatActivity() {
private val mainViewModel : MainViewModel by viewModels()
private lateinit var mainRecyclerView : RecyclerView
private lateinit var mainAdapter : MainRecyclerViewAdapter
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
initRecyclerView()
}
private fun initRecyclerView() {
mainRecyclerView = findViewById(R.id.mainRecyclerView)
mainRecyclerView.setHasFixedSize(true)
mainRecyclerView.layoutManager = GridLayoutManager(this,1)
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.main_menu,menu)
val searchView = menu.findItem(R.id.menu_search_movie).actionView as androidx.appcompat.widget.SearchView
searchView.queryHint = "Search By Name,Actor .."
searchView.setOnQueryTextListener(object : androidx.appcompat.widget.SearchView.OnQueryTextListener {
override fun onQueryTextSubmit(whileTextChange: String?): Boolean {
//Clear SearchView
searchView.isIconified = true
searchView.setQuery("", false)
searchView.onActionViewCollapsed()
mainViewModel.getMovieBySearch(whileTextChange.toString()).observe(this#MainActivity,object : Observer<List<Movie>?> {
override fun onChanged(newList: List<Movie>?) {
if (newList != null) {
mainAdapter = MainRecyclerViewAdapter(newList)
mainRecyclerView.adapter = mainAdapter
//mainAdapter.changeCurrentList(newList)
}
}
})
return false
}
override fun onQueryTextChange(whileTextChange: String?): Boolean {
Log.e("onQueryTextChange","Text: $whileTextChange")
return false
}
})
return true
}
}
You need to save the desired state in the viewmodel. For example,
var persistedMovies = arrayListOf<Movie>()
and when the search returns a valid response,
mainViewModel.persistedMovies = newList
Now the list is scoped to the viewmodel and persists through orientation changes.

Issues Implementing Material Design in Bundle

I am trying to make a bottom sheet; the code seems correct but I am having issues with the build.gradle. I am having trouble when I try to add in implementation "com.google.android.material:material:$material_version". I receive the error
"Could not get unknown property 'material_version' for object of type org.gradle.api.internal.artifacts.dsl.dependencies.DefaultDependencyHandler."
Any assistance would be appreciated
build.gradle:
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
android {
compileSdkVersion 29
buildToolsVersion "29.0.2"
defaultConfig {
applicationId "com.example.bottom_sheet"
minSdkVersion 21
targetSdkVersion 29
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.core:core-ktx:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
implementation "com.google.android.material:material:$material_version"
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
}
BottomSheetActivity.kt
class BottomSheetActivity : AppCompatActivity() {
private lateinit var standardBottomSheetBehavior: BottomSheetBehavior<View>
private val startColor = Color.parseColor("#00FFFFFF")
private val endColor = Color.parseColor("#FFFFFFFF")
private val textColor = Color.parseColor("#FF000000")
private var modalDismissWithAnimation = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_bottom_sheet)
setupButtons()
setupStandardBottomSheet()
//animateStandardBottomSheetStates()
}
private fun setupButtons() {
standardBottomSheetButton.setOnClickListener {
standardBottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
}
}
private fun setupStandardBottomSheet() {
standardBottomSheetBehavior = BottomSheetBehavior.from(standardBottomSheet)
val bottomSheetCallback = object : BottomSheetBehavior.BottomSheetCallback() {
override fun onStateChanged(bottomSheet: View, newState: Int) {
textView.text = when (newState) {
BottomSheetBehavior.STATE_EXPANDED -> "STATE_EXPANDED"
BottomSheetBehavior.STATE_COLLAPSED -> "STATE_COLLAPSED"
BottomSheetBehavior.STATE_DRAGGING -> "STATE_DRAGGING"
BottomSheetBehavior.STATE_HALF_EXPANDED -> "STATE_HALF_EXPANDED"
BottomSheetBehavior.STATE_HIDDEN -> "STATE_HIDDEN"
BottomSheetBehavior.STATE_SETTLING -> "STATE_SETTLING"
else -> null
}
}
override fun onSlide(bottomSheet: View, slideOffset: Float) {
val fraction = (slideOffset + 1f) / 2f
val color = ArgbEvaluatorCompat.getInstance().evaluate(fraction, startColor, endColor)
slideView.setBackgroundColor(color)
}
}
standardBottomSheetBehavior.addBottomSheetCallback(bottomSheetCallback)
standardBottomSheetBehavior.saveFlags = BottomSheetBehavior.SAVE_ALL
textView.setTextColor(textColor)
}
private fun showModalBottomSheet() {
val modalBottomSheet = ModalBottomSheet.newInstance(modalDismissWithAnimation)
modalBottomSheet.show(supportFragmentManager, ModalBottomSheet.TAG)
}
private fun animateStandardBottomSheetStates() {
standardBottomSheet.postDelayed({
standardBottomSheetBehavior.state = BottomSheetBehavior.STATE_HIDDEN
}, 1000L)
standardBottomSheet.postDelayed({
standardBottomSheetBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
}, 2000L)
standardBottomSheet.postDelayed({
standardBottomSheetBehavior.state = BottomSheetBehavior.STATE_HALF_EXPANDED
}, 3000L)
standardBottomSheet.postDelayed({
standardBottomSheetBehavior.state = BottomSheetBehavior.STATE_EXPANDED
}, 4000L)
standardBottomSheet.postDelayed({
standardBottomSheetBehavior.state = BottomSheetBehavior.STATE_HIDDEN
}, 5000L)
}
}
ModalBottomSheet.kt
class ModalBottomSheet : BottomSheetDialogFragment() {
private var dismissWithAnimation = false
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? = inflater.inflate(R.layout.modal_bottom_sheet, container, false)
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
dismissWithAnimation = arguments?.getBoolean(ARG_DISMISS_WITH_ANIMATION) ?: false
(requireDialog() as BottomSheetDialog).dismissWithAnimation = dismissWithAnimation
}
companion object {
const val TAG = "ModalBottomSheet"
private const val ARG_DISMISS_WITH_ANIMATION = "dismiss_with_animation"
fun newInstance(dismissWithAnimation: Boolean): ModalBottomSheet {
val modalBottomSheet = ModalBottomSheet()
modalBottomSheet.arguments = bundleOf(ARG_DISMISS_WITH_ANIMATION to dismissWithAnimation)
return modalBottomSheet
}
}
}
You need to change this line:
implementation "com.google.android.material:material:$material_version"
to this:
implementation 'com.google.android.material:material:1.2.0-alpha03'
or add $material_version parameter to your build.gradle file

Databinding not observe LiveData in ViewModel

I am trying to use Data binding with LiveData in ViewModel. But when using Transformations.map functions not trigged without adding observers explicitly. Data binding in XML not generate observers for LiveData in ViewModel.
LoginFragment.kt
class LoginFragment : Fragment() {
var homeViewModel: HomeViewModel? = null
companion object {
val TAG : String = "LoginFragment"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
homeViewModel = ViewModelProviders.of(this).get(HomeViewModel::class.java)
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
val binding = DataBindingUtil.inflate<FragmentLoginBinding>(inflater, R.layout.fragment_login, container, false)
.apply {
setLifecycleOwner(this#LoginFragment)
loginButton.setOnClickListener {
signInWithEmail()
}
}
return binding.root
}
/*private fun observeHomeFragmentUIDataLiveData() {
homeViewModel?.homeFragmentUIDataLiveData?.observe(this, Observer {
val email = it.email
Toast.makeText(activity,email, Toast.LENGTH_SHORT).show()
})
}
private fun observeLoginErrorEventLiveData() {
homeViewModel?.loginErrorEventLiveData?.observe(this, Observer {
Toast.makeText(activity,it, Toast.LENGTH_SHORT).show()
})
}*/
/**
* Sign In via Email
*/
fun signInWithEmail(){
val email = email_text_input_layout.editText?.text.toString()
val password = password_text_input_layout.editText?.text.toString()
var cancel : Boolean? = false
var focusView : View? = null
if(password.isEmpty()){
password_text_input_layout.error = getString(R.string.this_field_is_required)
focusView = password_text_input_layout
cancel = true
}
if(email.isEmpty()){
email_text_input_layout.error = getString(R.string.this_field_is_required)
focusView = email_text_input_layout
cancel = true
}
if(cancel!!){
focusView?.requestFocus()
}
else{
homeViewModel?.signInWithEmail(email,password)
/*homeViewModel?.signInWithEmail(email,password)?.observe(this, Observer {
val email = it
Toast.makeText(activity,""+email, Toast.LENGTH_SHORT).show()
})*/
}
}
}
fragment_login.xml
<layout 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">
<data>
<variable name="homeViewModel" type="com.rramprasad.adminapp.HomeViewModel"/>
</data>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="LoginFragment">
<!-- Skipped some code for clarity -->
<androidx.appcompat.widget.AppCompatTextView
android:id="#+id/error_textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#{homeViewModel.loginErrorEventLiveData.value}"
app:isGone="#{homeViewModel.isLoginSuccess}"
android:textColor="#android:color/holo_orange_dark"
android:textSize="16sp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#id/password_text_input_layout"
app:layout_constraintBottom_toBottomOf="#id/login_button"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
HomeViewModel.kt
class HomeViewModel(application: Application) : AndroidViewModel(application) {
val homeRepository: HomeRepository?
init {
homeRepository = HomeRepository()
}
// UI Data for HomeFragment
val homeFragmentUIDataLiveData : MutableLiveData<HomeFragmentUIData> = MutableLiveData()
// UI Data for LoginFragment
val loginErrorEventLiveData : MutableLiveData<String> = MutableLiveData()
var isLoginSuccess: LiveData<Boolean>? = null
fun signInWithEmail(email: String, password: String) : LiveData<Boolean>? {
val signInResponseMutableLiveData : MutableLiveData<Any> = homeRepository?.signInWithEmail(email, password)!!
isLoginSuccess = Transformations.map(signInResponseMutableLiveData) { signInResponse ->
when (signInResponse) {
(signInResponse is FirebaseUser) -> {
val firebaseUserEmail = (signInResponse as FirebaseUser).email
homeFragmentUIDataLiveData.value = HomeFragmentUIData(firebaseUserEmail ?: "")
return#map true
}
else -> {
loginErrorEventLiveData.value = signInResponse.toString()
return#map false
}
}
}
return isLoginSuccess
}
}
BindingAdapters.kt
#BindingAdapter("isGone")
fun bindIsGone(view: View, isGone: Boolean) {
view.visibility = if (isGone) {
View.GONE
} else {
View.VISIBLE
}
}
Android studio version:
Android Studio 3.2 RC 3
Build #AI-181.5540.7.32.4987877, built on August 31, 2018
JRE: 1.8.0_152-release-1136-b06 x86_64
JVM: OpenJDK 64-Bit Server VM by JetBrains s.r.o
macOS 10.13.4
build.gradle:
android {
compileSdkVersion 28
defaultConfig {
minSdkVersion 21
targetSdkVersion 28
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
dataBinding {
enabled = true
}
}

Categories

Resources