PROBLEM: On sending data from activity2 to activity1 using interface results in non-assignment of send data in activity1 even if it is being assigned. Consequently, activity1 members variables are automatically set to null.
SETUP DETAIL: On clicking a button in activity1, launches activity2. Now a user can perform whatever work in activity2. But as soon as a user performs work in activity2, my custom interface sends a data to activity1. Activity1 is supposed to assign that sent value to its member variable and when the user navigates back to activity1, onRestart() method of activity1 is bound to update user-interface with a new value.
SETUP IN POINTS:
1- User clicks a button on ACTIVITY1
2- Button opens ACTIVITY2
3- User performs an action that triggers my interface to send a data
4- Interface sends data to ACTIVITY1 in the background(ACTIVITY2 is still visible)
5- Sent data is assigned to ACTIVITY1 member variable(boolean) via interface
6- User back presses on ACTIVITY2 and navigates back to ACTIVITY1
7- ONRESTART() of ACTIVITY1 gets triggered
8- ONRESTART() checks if the boolean is true, then update UI
But here my confusion starts. Why is the assigned boolean value still null even after being assigned? Why is ACTIVITY1`s member variables losing assigned values?
CODE:
Interface
override fun onReturnedToActivity(actionID: Int) {
when(actionID)
{
3 ->
{
newNoteCreated = true
}
}
}
ONRESTART()
override fun onRestart() {
super.onRestart()
if(newNoteCreated) //variable is null not true.
{
Toast.makeText(this,"TRUE",Toast.LENGTH_SHORT).show()
mDrawer!!.updateBadge(3, StringHolder(dbHandler.totalNotes().toString() ))
newNoteCreated = false
}
Please educate me on this problem. I have been trying to find its solution on SO but nothing yet answers my question. I know there are other ways to send data between activities but I am trying to particularly use interfaces.
Quoting from
https://developer.android.com/reference/android/app/Activity#ActivityLifecycle
"If an activity is completely obscured by another activity, it is stopped. It still retains all state and member information, however, it is no longer visible to the user so its window is hidden and it will often be killed by the system when memory is needed elsewhere."
Then why does my activity loses its variable data?
EDIT
Main Activity(ACTIVITY1)
class MainActivity : AppCompatActivity(), ContextBarVisibilityListener, OnActionPerformedBadgeUpdater, ActivityReturningStateNotify {
private val dbHandler: PediaDatabase = PediaDatabase(this)
private var mDrawer: Drawer? = null
private var filePath: String? = null
private var backupFileName: String? = null
private var listBt: MenuItem? = null
private var gridBt: MenuItem? = null
private var frontAppName: TextView? = null
private var buttonStatePref: SharedPreferences? = null
private var speedDialView: SpeedDialView? = null
private var trashNotesCount: String? = null
private var archiveNotesCount: String? = null
private var onLayoutChange: LayoutChangeListener? = null
private var newNoteCreated: Boolean = false //THIS IS THE BOOL
private lateinit var mAdView: AdView
companion object
{
private const val LAYOUT_USER_PREF = "layout_preference"
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
onLayoutChange = NotesFrag()
if(savedInstanceState == null) //prevents reloading fragment
{
val transaction = supportFragmentManager.beginTransaction()
transaction.add(R.id.innerFrameLayout,NotesFrag()).commit()
}
trashNotesCount = dbHandler.trashedNotesCount().toString()
archiveNotesCount = dbHandler.archivedNoteCount().toString()
val drawerTrashBt: PrimaryDrawerItem = PrimaryDrawerItem().withIdentifier(1).withName("Trash Bin")
.withIcon(R.drawable.delete_note_image)
.withBadge(trashNotesCount)
.withSelectedIcon(R.drawable.delete_drawer_selected)
val drawerArchiveBt: PrimaryDrawerItem = PrimaryDrawerItem().withIdentifier(2).withName("Archive")
.withIcon(R.drawable.archive_note_img)
.withBadge(archiveNotesCount)
.withSelectedIcon(R.drawable.archive_drawer_selected)
val drawerNotesBt: PrimaryDrawerItem = PrimaryDrawerItem().withIdentifier(3).withName("Notes")
.withIcon(R.drawable.notes_img)
.withBadge(dbHandler.totalNotes().toString())
.withSelectedIcon(R.drawable.notes_drawer_selected)
val drawerLockedNotesBt: PrimaryDrawerItem = PrimaryDrawerItem().withIdentifier(4).withName("Locked Notes")
.withIcon(R.drawable.lock_button)
.withBadge("1")
.withSelectedIcon(R.drawable.locked_drawer_selected)
val drawerReminderNotesBt: PrimaryDrawerItem = PrimaryDrawerItem().withIdentifier(5).withName("Reminder Notes")
.withIcon(R.drawable.reminder_notes)
.withBadge("1")
.withSelectedIcon(R.drawable.reminder_drawer_selected)
val drawerFavouriteNotesBt: PrimaryDrawerItem = PrimaryDrawerItem().withIdentifier(6).withName("Favourite Notes")
.withIcon(R.drawable.rate_app_star_img)
.withBadge("1")
.withSelectedIcon(R.drawable.favourite_drawer_selected)
val drawerSettingsBt: PrimaryDrawerItem = PrimaryDrawerItem().withIdentifier(7).withName("Settings")
.withIcon(R.drawable.settings_drawer)
mDrawer = DrawerBuilder().withActivity(this)
.withHeader(R.layout.navbar_header)
.addDrawerItems(drawerNotesBt,drawerArchiveBt,drawerTrashBt,
drawerLockedNotesBt,drawerReminderNotesBt,
drawerFavouriteNotesBt,DividerDrawerItem(), drawerSettingsBt)
.withOnDrawerItemClickListener(object: Drawer.OnDrawerItemClickListener{
override fun onItemClick(view: View?, position: Int, drawerItem: IDrawerItem<*, *>?): Boolean {
when(position)
{
1 ->
{
frontAppName!!.text = "Wonder Notes"
speedDialView!!.show() //show again because traversing to other fragments hides it
val transaction = supportFragmentManager.beginTransaction()
transaction.replace(R.id.innerFrameLayout, NotesFrag())
transaction.addToBackStack(null)
transaction.commit()
}
2 ->
{
speedDialView!!.hide()
supportFragmentManager.beginTransaction().replace(R.id.innerFrameLayout,ArchiveFragment()).commit()
}
3 ->
{
frontAppName!!.text = "Trash"
speedDialView!!.hide()
fabLayoutBehaviourSetter(false)
supportFragmentManager.beginTransaction().replace(R.id.innerFrameLayout, TrashFragment()).commit()
}
4 -> Log.d("locked notes","1")
5 -> Log.d("reminder","1")
6 -> Log.d("favourite","1")
}
return false // false closes drawer on click
}
}).build()
/*Below code handles swipe tabs adapter setting and displaying
* and implements fragments to viewpager programitically */
// mainActivityViewPagerID.adapter = ViewPagerAdapter(supportFragmentManager)
// attachNotesFrag()
//mainTabsID.setupWithViewPager(mainActivityViewPagerID)
//mainTabsID.setTabTextColors(Color.DKGRAY, Color.parseColor("white"))
val drawerOpener = findViewById<ImageButton>(R.id.drawerOpenImgBt)
val noteCounterAsBt = findViewById<TextView>(R.id.showNotesCountID)
drawerOpener.setOnClickListener { mDrawer!!.openDrawer() }
noteCounterAsBt.setOnClickListener { mDrawer!!.openDrawer() }
//navigationView.setNavigationItemSelectedListener(this)
val customToolbar: Toolbar = findViewById(R.id.toolbarID)
setSupportActionBar(customToolbar)
supportActionBar!!.setDisplayShowTitleEnabled(false) //set main title off
val toolbarTxtView = findViewById<TextView>(R.id.toolbar_title)
toolbarTxtView.visibility = View.GONE
checkForStoragePermission()
}//on create
override fun onContextBarVisibilityChange(isVisible: Boolean) { //custom interface
if(isVisible)
{
speedDialView!!.hide()
fabLayoutBehaviourSetter(false) //remove scrolling behaviour
}
else
{
speedDialView!!.show()
fabLayoutBehaviourSetter(true) //set scrolling behaviour
}
}
override fun onReturnedToActivity(actionID: Int) { ///it just recieves value from ACTIVITY2 and assign its value to ACTIVTY1`s "newNoteCreated" varaible
when(actionID)
{
3 ->
{
Log.d("INTERFACE","CALLED $actionID")
newNoteCreated = true
Log.d("INTERFACE","CALLED $newNoteCreated")
}
}
}
REFERENCE ACTIVITY(ACTIVITY2) I am only including the part where interface sends data back to activity1 because the code of activity2 is very lengthy and will most likely confuse readers.
onActivityReturningStateNotify = MainActivity()
dbHandler!!.createNote(note)
//onActionPerformedBadgeUpdater!!.onActionPerformed(3)
onActivityReturningStateNotify!!.onReturnedToActivity(3)
INTERFACE
interface ActivityReturningStateNotify {
fun onReturnedToActivity(actionID: Int)
}
Your problem is that you are calling onReturnedToActivity() on a new instance of MainActivity, not the one you started from or the one that you will return to.
There are several ways to share data between activities, one is to use startActivityForResult().
I think your problem however is that Activity1 will be stopped, so you can't really send it data from Activity2. You can however start Activity2 with startActivityForResult
and return a result.
Here is the example from the documentation.
Starting the activity.
const val PICK_CONTACT_REQUEST = 1 // The request code
...
private fun pickContact() {
Intent(Intent.ACTION_PICK, Uri.parse("content://contacts")).also { pickContactIntent ->
pickContactIntent.type = Phone.CONTENT_TYPE // Show user only contacts w/ phone numbers
startActivityForResult(pickContactIntent, PICK_CONTACT_REQUEST)
}
}
Getting the returned data.
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
// Check which request we're responding to
if (requestCode == PICK_CONTACT_REQUEST) {
// Make sure the request was successful
if (resultCode == Activity.RESULT_OK) {
// The user picked a contact.
// The Intent's data Uri identifies which contact was selected.
// Do something with the contact here (bigger example below)
}
}
}
Other schemes include a Global Singleton, launching activities with Intents, or using SharedPreferences writting data in one activity and then reading it back in another.
If you do a search on android share data between activities
You will see there are various options on the best way to accomplish this.