传递引用到Activity Intent

4
相当长一段时间以来,我一直有从一个 Activity 传递变量到另一个 Activity 的麻烦,通常我不得不采用一些相当丑陋的静态类 hack 来使其工作。一般来说,我会调用一个带有 Activity 类型的静态方法,以及 Activity 需要的变量。这些被存储在静态变量中,并在该 Activity 的构造函数中检索出来。就像我所说的,非常丑陋。而且没有 "myActivity.StartActivity(new Activity);" 这样的东西。所有 StartActivity 的重载都需要一个 Intent 或 typeof(MyOtherActivity)。
所以我的问题是,我是否完全误解了 Activity 的概念,还是我仅仅错过了一种完全明显的方式来传递参数?
@编辑:我想传递一个对象的实际引用,而不仅仅是对象的副本,原因是我正在尝试将 ViewModel 从上层 Activity 传递到新的 Activity。当然,对此 ViewModel 所做的任何更改,都应该反映在父 Activity 上,这只有在两个 Activity 的 ViewModel 指向同一实例时才可能实现。
我使用 Xamarin.Android 编写应用程序,但是 C# 和 Java 之间的代码几乎相同,因此这些语言中的答案都可以。

2
可能是 https://dev59.com/_nI95IYBdhLWcg3w7CjL 的重复问题。 - dsharew
部分正确。您提供的链接中的答案解释了如何将基本值类型(例如int和string)移动到单独的Activity,但未解释如何传递实际引用对象,例如我自己定义的自定义类型的对象。 - Falgantil
我为你谷歌了一下。https://dev59.com/RHE85IYBdhLWcg3whD7k - dsharew
正确,但所有这些结果都建议将其序列化。这意味着我将失去对对象的引用。而这正是我想要保留的。换句话说,我想要给它的不是一个对象,而是一个对象的引用。 - Falgantil
为什么你想这样做?请更新你的问题并说明原因。 - dsharew
使用“Fragments”怎么样? - Milen
2个回答

7
问题在于Android可能随时杀死托管您应用程序的进程(如果应用程序在后台)。当用户返回到您的应用程序时,Android会创建一个新的进程来托管您的应用程序,并重新创建堆栈顶部的Activity。为了做到这一点,Android保留了Intent的“序列化”版本,以便能够重新创建Intent并传递给Activity。这就是为什么Intent中的所有“extras”都需要是ParcelableSerializable的原因。
另一个需要考虑的问题是,不同的活动可能在不同的进程中运行。即使是来自同一个应用程序的活动也可能处于不同的进程中(如果清单指定)。由于对象引用不能跨进程边界工作,这是不能在Intent中传递对象引用的另一个原因。

从你所说的来看,这似乎是一个极其不稳定的环境,难以为其开发应用程序,因为你永远不知道你的应用程序的哪一部分正在运行,因此很难创建一个导航流程,在稍后退出和重新进入应用程序时不会出现问题。这是真的吗? - Falgantil
是的,这是真的。这意味着你需要考虑到这一点来设计你的应用程序。你不是第一个在这方面遇到困难的Android开发者,也不会是最后一个。 - David Wasser
这似乎是一个非常难以测试的场景。Android是否提供了一些强制操作系统杀死托管您的应用程序进程并重新创建该进程的方式,以便您可以测试您的移动应用在这种极不稳定的情况下是否正常运行? - deltamind106
不,但你可以自己做。你可以使用adb命令或Android Studio在应用程序后台运行时杀死其操作系统进程,然后在设备上导航回它。 - David Wasser

0

你也可以使用Application类来全局存储和检索对象:

using Android.Runtime;

namespace SomeName
{
[Application]
public class App : Application
{
public string Name { get; set;}

public App (IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
{
}

public override void OnCreate ()
{
    base.OnCreate ();

    Name = "";
}
}
}

你可以使用以下方式访问数据:

App application = (App)Application.Context;
application.Name = "something";

我选择在 Application 类中执行此操作,因为此类在应用程序启动时被调用,所以您不必手动初始化它。
请记住,作用域限定于 Application 的变量也会通过扩展其生命周期来限定应用程序的生命周期。
如果 Android 觉得有必要,这个类将被垃圾回收,因此您必须修改代码以包括此情况。
您可以使用 SharedPreferencesDatabase 来保存变量,以防它们被删除,并从应用程序类中检索它们,以获得更快的结果。

但是,在使用此方法时不要浪费过多资源,因为在此类上附加太多信息可能会导致性能下降。只添加您知道应用程序的不同部分需要的信息,并且其中检索该信息的成本超过将其存储为应用程序变量的成本。

调查您需要保持为应用程序范围的状态的信息以及什么信息可以直接从数据库中检索。两者都有成本影响,您需要确保找到平衡点。

别忘了在 OnStopOnDestroy 中根据需要释放资源。
我很少使用意图,我认为这种方法更好。


这就是 OP 在谈论使用“静态变量”时所指的内容。你不需要一个 Application 类来实现,只需使用静态变量即可。OP 正在寻找一种更“优雅”的解决方案;-) - David Wasser
谁是 OP?:) 有了 Application 类,您可以做一些工作,并确保从应用程序开始到结束都会完成。为什么这个解决方案不够优雅?什么样的解决方案可能更加优雅?Android 对全局变量的集成支持? - CDrosos
在正确的轨道上,只是一些背景信息,为什么这有点不稳定... 您的进程可能随时被操作系统杀死(例如:活动已经在后台运行了一段时间,其他应用程序对内存施加了很大的压力等),Application 类可以在您甚至没有注意到的情况下被撤销并重新创建。在这种情况下,Name 属性将被重置;更好的解决方案是通过 getter 和 setter 将其持久化到共享首选项中,或通过数据库恢复“对象”。 - matthewrdev
1
@matthewrdev 你说得对,我没有提及到那种可能性,我已经编辑了答案并加入了更多的信息。现在我相信这是一个更好的答案了。 - CDrosos

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接