【问题标题】:How to send objects through bundle如何通过捆绑发送对象
【发布时间】:2011-05-14 02:08:03
【问题描述】:

我需要通过一个包传递对完成我大部分处理的类的引用。

问题在于它与意图或上下文无关,并且有大量的非原始对象。如何将类打包成可打包/可序列化并将其传递给startActivityForResult

【问题讨论】:

  • “我需要通过一个包传递对我进行大部分处理的类的引用”——为什么?
  • 我有一个对象(DataManager),它处理服务器并为某些 GUI 运行一些后端。每当建立新连接时,我希望用户能够启动一个新活动,该活动在 ListView 中列出所有活动连接并让用户选择一个。然后,生成的数据将绑定到新的 GUI。这实际上只是后端的皮肤选择器。
  • 如果您在多个活动中处理同一对象实例,您可能需要考虑singleton pattern。有一个很好的教程here

标签: android serialization android-activity bundle parcelable


【解决方案1】:

您还可以使用 Gson 将对象转换为 JSONObject 并将其传递给 bundle。对我来说,这是我发现的最优雅的方式。我还没有测试过它对性能的影响。

在初始活动中

Intent activity = new Intent(MyActivity.this,NextActivity.class);
activity.putExtra("myObject", new Gson().toJson(myobject));
startActivity(activity);

在下一个活动中

String jsonMyObject;
Bundle extras = getIntent().getExtras();
if (extras != null) {
   jsonMyObject = extras.getString("myObject");
}
MyObject myObject = new Gson().fromJson(jsonMyObject, MyObject.class);

【讨论】:

  • 由于这是在活动之间传递内容的问题,它不会经常发生,不足以对应用程序的整体性能产生重大影响。话虽如此,我怀疑它是否可以序列化原始帖子的 DataManager,因为它听起来像它具有套接字连接和其他类似的类。
  • Google 也建议使用此解决方案而不是序列化:查看this doc page 的最后一部分“推荐替代方案”
  • 作为警告,我使用了这种技术一段时间,但是你可以作为字符串传递的内存有限制,所以请确保你的数据不要太大。
  • 查看blog.madadipouya.com/2015/09/21/… 了解如何为您的项目添加 Gson 支持。
  • 智能解决方案,向你致敬!
【解决方案2】:

弄清楚要走哪条路不仅需要回答 CommonsWare 的“为什么”这一关键问题,还需要回答“走向什么?”的问题。你通过了吗?

现实情况是,唯一可以通过捆绑的东西是纯数据 - 其他一切都基于对数据含义或指向的解释。您不能从字面上传递一个对象,但您可以做以下三件事之一:

1) 你可以把对象分解成它的构成数据,如果另一端知道同一种对象,它可以从序列化的数据中组装一个克隆。这就是大多数常见类型通过捆绑包的方式。

2) 你可以传递一个不透明的句柄。如果您在相同的上下文中传递它(尽管有人可能会问为什么要麻烦),那将是一个您可以调用或取消引用的句柄。但是如果你通过 Binder 将它传递给不同的上下文,它的文字值将是一个任意数字(实际上,这些任意数字从启动开始按顺序计数)。除了跟踪它,你什么也做不了,直到你将它传递回原始上下文,这将导致 Binder 将其转换回原始句柄,使其再次有用。

3) 你可以传递一个魔术句柄,例如文件描述符或对某些操作系统/平台对象的引用,如果你设置正确的标志,Binder 将为接收者创建一个指向相同资源的克隆,这实际上可以用于另一端。但这仅适用于极少数类型的对象。

最有可能的是,您要么传递您的类,以便另一端可以跟踪它并稍后将其返回给您,要么您将它传递给可以从序列化的组成数据创建克隆的上下文。 . 否则您正在尝试做一些行不通的事情,您需要重新考虑整个方法。

【讨论】:

  • 感谢旅游回复。你的权利,我需要做的只是将对象列表的引用传递给我的新活动。新活动将从列表中获取一些数据并显示一个可选择的 ListView。 onSelect,活动将返回一个结果(一些与点击对象有关的数据)给宿主活动。如果我理解正确,我相信您的选项 2 最恰当地处理了这个问题;我如何获得这个不透明的句柄?
  • 您的其他活动无法从不透明对象中提取任何数据以进行显示。您可能想要做的是创建并传递一些受支持类型的代理对象,其中包含将要显示的信息的副本。
【解决方案3】:

Parcelable 接口是通过 Intent 传递对象的好方法。

How can I make my custom objects Parcelable? 是关于如何使用 Parcelable

的一个很好的答案

官方google docs也附上一个例子

【讨论】:

  • 或者它们也可以是可序列化的。
  • 但是性能大大降低了 10 倍!!查看此基准:developerphil.com/parcelable-vs-serializable
  • +1 @Mati 的评论,但是当应用于单个对象时将其放入上下文 10 倍相当于 1 毫秒。所以也许没有听起来那么糟糕。
  • 同意。问题是当您处理集合时,如果您从 Rest API 获取资源,这是一个非常常见的用例。但是对于一个单一的对象,不应该是臭名昭著的东西。无论如何,如果所有样板代码都妨碍了你,你可以试试这个为你生成所有这些的库:github.com/johncarl81/parceler。一个非常好的方法!
  • 断开的链接:404(未找到)
【解决方案4】:

您可以使用全局 application 状态。

更新:

自定义,然后将其添加到您的 AndroidManifest.xml 中:

<application android:label="@string/app_name" android:debuggable="true" android:name=".CustomApplication"

然后在你的项目中有一个这样的类:

package com.example;

import android.app.Application;

public class CustomApplication extends Application {
    public int someVariable = -1;
}

因为“It can be accessed via getApplication() from any Activity or Service”,所以你可以这样使用它:

CustomApplication application = (CustomApplication)getApplication();
application.someVariable = 123; 

希望对您有所帮助。

【讨论】:

  • 感谢您的回复,但是如何?
  • 我相信你只是应用程序的子类,然后可以存储任何你喜欢的东西。上面的链接中提到了您需要的 xml 更改。
  • 作为一般设计原则,除非您真的需要全局变量,否则最好避免使用它们。在这种情况下,有很好的选择。
  • 好的,我想我明白你在说什么。只需扩展 Application 并放入一个保存需要传递的对象的变量;我查看了参考页面,没有看到必要的 xml 更改。
  • 我也想写这个作为答案。这绝对是做到这一点的方法之一。但请记住,除非您取消对它们的引用(或 App 上下文被破坏),否则这些对象将保留在内存中,并且在您不需要它们时可能会占用空间。
【解决方案5】:

您还可以将对象设为Serializable 并使用Bundle 的getSerializableputSerializable 方法。

【讨论】:

  • 我试过了,很快意识到这是不切实际的。我不认为存储在传递的类(线程)中的大多数对象都是可序列化的。 :) 不过谢谢。
【解决方案6】:

可能的解决方案:

Bundle bundle = new Bundle();
bundle.putSerializable("key", new CustomObject());

自定义对象类:

class CustomObject implements Serializable{
 private SubCustomObject1 sc1;
 private SubCustomObject2 sc2;
}

子自定义对象:

class SubCustomObject1 implements Serializable{ }

class SubCustomObject2  implements Serializable{ }

【讨论】:

    【解决方案7】:

    通过捆绑发送对象的另一种方法是使用bundle.putByteArray
    示例代码

    public class DataBean implements Serializable {
    private Date currentTime;
    
    public setDate() {
        currentTime = Calendar.getInstance().getTime();
     }
    
    public Date getCurrentTime() {
        return currentTime;
     }
    }
    

    将DataBean的Object放入Bundle:

    class FirstClass{
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //Your code...
    
    //When you want to start new Activity...
    Intent dataIntent =new Intent(FirstClass.this, SecondClass.class);
                Bundle dataBundle=new Bundle();
                DataBean dataObj=new DataBean();
                dataObj.setDate();
                try {
                    dataBundle.putByteArray("Obj_byte_array", object2Bytes(dataObj));
    
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
    
                }
    
                dataIntent.putExtras(dataBundle);
    
                startActivity(dataIntent);
    }
    

    将对象转换为字节数组

    /**
     * Converting objects to byte arrays
     */
    static public byte[] object2Bytes( Object o ) throws IOException {
          ByteArrayOutputStream baos = new ByteArrayOutputStream();
          ObjectOutputStream oos = new ObjectOutputStream( baos );
          oos.writeObject( o );
          return baos.toByteArray();
        }
    

    从Bundle中取回对象:

    class SecondClass{
    DataBean dataBean;
    public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    //Your code...
    
    //Get Info from Bundle...
        Bundle infoBundle=getIntent().getExtras();
        try {
            dataBean = (DataBean)bytes2Object(infoBundle.getByteArray("Obj_byte_array"));
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    

    从字节数组中获取对象的方法:

    /**
     * Converting byte arrays to objects
     */
    static public Object bytes2Object( byte raw[] )
            throws IOException, ClassNotFoundException {
          ByteArrayInputStream bais = new ByteArrayInputStream( raw );
          ObjectInputStream ois = new ObjectInputStream( bais );
          Object o = ois.readObject();
          return o;
        }
    

    希望对其他朋友有所帮助。

    【讨论】:

    • 这看起来很流畅且易于查看代码。但我觉得还有更多关于为什么 SDK 不提供这样的东西来传递对象的原因。你能告诉我更多关于这个解决方案的信息吗?
    • 完全不需要所有代码!使用 bundle.putSerializable(objectImplementingSerializable) - 这在你在这里重新实现的内容之下......
    【解决方案8】:

    1.一个非常直接好用的例子,让要传递的对象实现Serializable。

    class Object implements Serializable{
        String firstName;
       String lastName;
    }
    

    2.通过包中的对象

    Bundle bundle = new Bundle();
    Object Object = new Object();
    bundle.putSerializable("object", object);
    

    3.从bundle中获取传递的对象作为Serializable然后转换为Object。

    Object object = (Object) getArguments().getSerializable("object");
    

    【讨论】:

      【解决方案9】:

      我在寻找传递 Date 对象的方法时遇到了这个问题。就我而言,正如答案中所建议的那样,我使用了 Bundle.putSerializable() 但这不适用于原始帖子中描述的 DataManager 的复杂事物。

      我的建议是使用依赖注入并将 DataManager 绑定到 Singleton 范围并在需要的地方注入 DataManager,这与将所述 DataManager 放入应用程序或使其成为 Singleton 的结果非常相似。您不仅可以从增加的可测试性中受益,而且还可以获得更简洁的代码,而无需使用所有样板“在类和活动之间传递依赖关系”代码。 (Robo)Guice 非常易于使用,新的 Dagger 框架看起来也很有前途。

      【讨论】:

      • 好吧,使用 Date 之类的东西,您可以只传递 long 值。但是,其余的听起来不错。谢谢。
      【解决方案10】:

      这是对我自己的问题的一个非常迟的答案,但它一直受到关注,所以我觉得我必须解决它。这些答案中的大多数都是正确的,并且可以完美地处理这项工作。但是,这取决于应用程序的需要。此答案将用于描述此问题的两种解决方案。

      应用

      第一个是Application,因为它是这里讨论最多的答案。应用程序是放置需要引用上下文的实体的好对象。 `ServerSocket` 无疑需要一个上下文(用于文件 I/o 或简单的 `ListAdapter` 更新)。我个人更喜欢这条路线。我喜欢应用程序,它们对于上下文检索很有用(因为它们可以设为静态并且不太可能导致内存泄漏)并且具有简单的生命周期。

      服务

      Service` 排在第二位。对于我的问题,“服务”实际上是更好的选择,因为这就是服务的设计目的: 服务是一个应用程序组件,可以在 背景并且不提供用户界面。 服务很简洁,因为它们具有更明确的生命周期,更容易控制。此外,如果需要,服务可以在应用程序外部运行(即在启动时)。这对于某些应用程序或只是一个简洁的功能可能是必需的。

      这不是对两者的完整描述,但我为那些想要进行更多调查的人留下了文档的链接。总的来说,Service 更适合我需要的实例 - 将 ServerSocket 运行到我的 SPP 设备。

      【讨论】:

        【解决方案11】:

        另一种使用包传递对象的简单方法:

        • 在类对象中,使用键创建静态列表或其他数据结构
        • 创建对象时,将其放入带有键的列表/数据结构中(例如创建对象时的长时间戳)
        • 创建方法 static getObject(long key) 从列表中获取对象
        • 在捆绑包中传递密钥,以便您稍后可以从代码中的另一个点获取对象

        【讨论】:

          猜你喜欢
          • 2013-04-15
          • 2017-05-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多