使用界面的两个活动之间的通信未按预期工作
Communication between two activities using interface not working as expected
问题: 将数据从 activity2 发送到 activity1 使用接口导致 activity1 中的发送数据未分配,即使正在分配也是如此。因此,activity1 成员变量自动设置为 null。
设置详细信息: 单击 activity1 中的按钮,启动 activity2。现在用户可以在 activity2 中执行任何工作。但是一旦用户在 activity2 中执行工作,我的自定义界面就会将数据发送到 activity1。 Activity1 应该将该发送的值分配给它的成员变量,并且当用户导航回 activity1、[=64= activity1 的 ]onRestart() 方法必须使用新值更新用户界面。
点数设置:
1- 用户单击 ACTIVITY1
上的按钮
2- 按钮打开 ACTIVITY2
3- 用户执行触发我的接口发送数据的操作
4-接口在后台向ACTIVITY1发送数据(ACTIVITY2仍然可见)
5-发送数据通过接口
赋值给ACTIVITY1成员变量(boolean)
6- 用户返回按 ACTIVITY2 并导航回 ACTIVITY1
7-ONRESTART() of ACTIVITY1 被触发
8- ONRESTART() 检查布尔值是否为真,然后更新 UI
但是我的困惑开始了。 为什么赋值后布尔值还是null? 为什么是ACTIVITY1的成员变量丢失赋值?
代码:
接口
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
}
请教我这个问题。我一直在尝试在 SO 上找到它的解决方案,但还没有回答我的问题。我知道还有其他方法可以在活动之间发送数据,但我正在尝试特别使用接口。
引用自
https://developer.android.com/reference/android/app/Activity#ActivityLifecycle
"如果一个activity被另一个activity完全遮挡,它就会停止。它仍然保留所有状态和成员信息,但是,它不再对用户可见,因此它的 window 被隐藏,并且当其他地方需要内存时,它通常会被系统杀死。"
那为什么我的activity会丢失变量数据呢?
编辑
主要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")
}
}
}
参考 ACTIVITY(ACTIVITY2)
我只包括接口将数据发送回 activity1 的部分,因为 activity2 的代码非常冗长,很可能会使读者感到困惑。
onActivityReturningStateNotify = MainActivity()
dbHandler!!.createNote(note)
//onActionPerformedBadgeUpdater!!.onActionPerformed(3)
onActivityReturningStateNotify!!.onReturnedToActivity(3)
接口
interface ActivityReturningStateNotify {
fun onReturnedToActivity(actionID: Int)
}
您的问题是您在 MainActivity 的新实例上调用 onReturnedToActivity(),而不是您开始的实例或您将 return 到达的实例。
有几种方法可以在活动之间共享数据,一种是使用startActivityForResult()。
我认为您的问题是 Activity1 将停止,因此您无法真正从 Activity2 向它发送数据。但是,您可以使用 startActivityForResult
和 return 结果启动 Activity2。
这是 documentation.
中的示例
正在启动 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)
}
}
正在获取 returned 数据。
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)
}
}
}
其他方案包括全局单例、使用 Intent 启动活动,或使用 SharedPreferences 在一个 activity 中写入数据,然后在另一个中读回。
如果您在 android share data between activities
上进行搜索,您会看到有多种选择可以实现这一目标。
通过接口将Activity1分配给Activity2是个坏主意,尝试在activity1中使用:startActivityForResult(intent, requestCode)
在activity2中制作任何你想要的然后调用:onActivityResult(requestCode, resultCode, intent);
并在activity1中覆盖功能: onActivityResult()
并从意图中获取布尔数据。
问题: 将数据从 activity2 发送到 activity1 使用接口导致 activity1 中的发送数据未分配,即使正在分配也是如此。因此,activity1 成员变量自动设置为 null。
设置详细信息: 单击 activity1 中的按钮,启动 activity2。现在用户可以在 activity2 中执行任何工作。但是一旦用户在 activity2 中执行工作,我的自定义界面就会将数据发送到 activity1。 Activity1 应该将该发送的值分配给它的成员变量,并且当用户导航回 activity1、[=64= activity1 的 ]onRestart() 方法必须使用新值更新用户界面。
点数设置:
1- 用户单击 ACTIVITY1
上的按钮2- 按钮打开 ACTIVITY2
3- 用户执行触发我的接口发送数据的操作
4-接口在后台向ACTIVITY1发送数据(ACTIVITY2仍然可见)
5-发送数据通过接口
赋值给ACTIVITY1成员变量(boolean)6- 用户返回按 ACTIVITY2 并导航回 ACTIVITY1
7-ONRESTART() of ACTIVITY1 被触发
8- ONRESTART() 检查布尔值是否为真,然后更新 UI
但是我的困惑开始了。 为什么赋值后布尔值还是null? 为什么是ACTIVITY1的成员变量丢失赋值?
代码:
接口
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
}
请教我这个问题。我一直在尝试在 SO 上找到它的解决方案,但还没有回答我的问题。我知道还有其他方法可以在活动之间发送数据,但我正在尝试特别使用接口。
引用自
https://developer.android.com/reference/android/app/Activity#ActivityLifecycle
"如果一个activity被另一个activity完全遮挡,它就会停止。它仍然保留所有状态和成员信息,但是,它不再对用户可见,因此它的 window 被隐藏,并且当其他地方需要内存时,它通常会被系统杀死。"
那为什么我的activity会丢失变量数据呢?
编辑
主要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")
}
}
}
参考 ACTIVITY(ACTIVITY2) 我只包括接口将数据发送回 activity1 的部分,因为 activity2 的代码非常冗长,很可能会使读者感到困惑。
onActivityReturningStateNotify = MainActivity()
dbHandler!!.createNote(note)
//onActionPerformedBadgeUpdater!!.onActionPerformed(3)
onActivityReturningStateNotify!!.onReturnedToActivity(3)
接口
interface ActivityReturningStateNotify {
fun onReturnedToActivity(actionID: Int)
}
您的问题是您在 MainActivity 的新实例上调用 onReturnedToActivity(),而不是您开始的实例或您将 return 到达的实例。
有几种方法可以在活动之间共享数据,一种是使用startActivityForResult()。
我认为您的问题是 Activity1 将停止,因此您无法真正从 Activity2 向它发送数据。但是,您可以使用 startActivityForResult
和 return 结果启动 Activity2。
这是 documentation.
正在启动 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)
}
}
正在获取 returned 数据。
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)
}
}
}
其他方案包括全局单例、使用 Intent 启动活动,或使用 SharedPreferences 在一个 activity 中写入数据,然后在另一个中读回。
如果您在 android share data between activities
上进行搜索,您会看到有多种选择可以实现这一目标。
通过接口将Activity1分配给Activity2是个坏主意,尝试在activity1中使用:startActivityForResult(intent, requestCode)
在activity2中制作任何你想要的然后调用:onActivityResult(requestCode, resultCode, intent);
并在activity1中覆盖功能: onActivityResult()
并从意图中获取布尔数据。