2010-11-22 176 views
100

我需要將引用傳遞給通過包執行我大部分處理的類。如何通過包發送對象

問題是它與意圖或上下文無關,並有大量的非原始對象。我如何將這個類打包成一個parcelable/serializable並將它傳遞給startActivityForResult

+2

「我需要將引用傳遞給通過綁定執行大部分處理的類」 - 爲什麼? – CommonsWare 2010-11-22 20:27:24

+1

我有一個對象(DataManager),它處理一個服務器併爲一些GUI運行幾個後端。當建立新的連接時,我希望用戶能夠啓動一個新的活動,該活動在ListView中列出所有活動連接並讓用戶選擇一個。結果數據然後將綁定到新的GUI。這真的只是後端的皮膚選擇器。 – AedonEtLIRA 2010-11-23 18:11:25

+3

如果您通過多個活動處理同一個對象實例,您可能需要考慮[singleton pattern](http://en.wikipedia.org/wiki/Singleton_pattern)。有一個很好的教程[這裏](http://www.javaworld.com/article/2073352/core-java/simply-singleton.html)。 – sotrh 2014-07-22 21:31:51

回答

51

找出需要採取的措施不僅需要回答CommonsWare關於「爲什麼」的關鍵問題,還需要回答「到什麼」的問題。你通過它嗎?

現實情況是,唯一可以通過捆綁的東西是明文數據 - 其他所有內容都基於對數據意味着什麼或指向什麼的解釋。你不能從字面上傳遞一個對象,但你可以做的是以下三件事之一:

1)你可以將對象分解爲它的構成數據,如果另一端的知識具有相同的類型它可以從序列化的數據中組裝一個克隆。這就是大多數常見類型通過捆綁的方式。

2)你可以通過一個不透明的手柄。如果你在相同的上下文中傳遞它(儘管有人可能會問爲什麼會這麼麻煩),這將成爲你可以調用或取消引用的句柄。但是,如果您通過Binder將其傳遞到不同的上下文,它的文字值將是任意數字(實際上,這些任意數字從啓動順序計數)。你不能做任何事情,除非跟蹤它,直到你將它傳遞迴原始上下文,這將導致Binder將其轉換回原始句柄,使其再次有用。

3)你可以傳遞一個神奇的句柄,比如文件描述符或者對某些os /平臺對象的引用,如果你設置了正確的標誌符,Binder將創建一個指向收件人相同資源的克隆,實際上被用在另一端。但是,這僅適用於極少數類型的對象。

最有可能的情況是,您要麼傳遞您的類,以便另一端可以跟蹤它並稍後將其提供給您,或者您將它傳遞到可以從序列化組分數據創建克隆的上下文中。 ..否則你正在試圖做一些不會起作用的事情,你需要重新思考整個方法。

13

您可以使用全局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; 

希望有所幫助。

+0

感謝您的回覆,但是如何? – AedonEtLIRA 2010-11-22 20:54:18

+0

我相信你只是應用子類,然後可以存儲任何你喜歡的東西。您需要的xml更改在上面的鏈接中提到。 – 2010-11-22 21:58:55

+9

作爲一般的設計主體,除非你確實需要它們,否則避免使用全局變量是個好主意。在這種情況下,有很好的選擇。 – dhaag23 2010-11-22 22:31:08

0

對於我自己的問題,這是一個很遲來的答案,但它一直引起注意,所以我覺得我必須解決它。這些答案中的大部分都是正確的,並且完美地處理這項工作但是,這取決於應用程序的需求。這個答案將被用來描述這個問題的兩個解決方案。

應用

首先是 Application,因爲它一直是最談到這裏的答案。該應用程序是一個很好的對象,用於放置需要對Context進行引用的實體。一個`ServerSocket`毫無疑問需要一個上下文(用於文件I/O或簡單的`ListAdapter`更新)。我個人更喜歡這條路線。我喜歡應用程序,它們對於上下文檢索很有用(因爲它們可以變成靜態的並且不可能導致內存泄漏)並且具有簡單的生命週期。

服務的 是 Service`第二。對於我的問題,「服務」實際上是更好的選擇,因爲這是服務設計的目的:
 
A Service is an application component that can perform long-running operations in 
the background and does not provide a user interface. 
服務很整潔,因爲它們具有更易於控制的更明確的生命週期。此外,如果需要,服務可以在應用程序的外部運行(即在啓動時)。這對於某些應用程序或簡單的功能來說可能是必需的。

這不是一個完整的描述,但我留下了鏈接到那些誰想要調查更多的文檔。總的來說,Service對我所需的實例來說更好 - 運行ServerSocket到我的SPP設備。

7

再來通過束髮送對象的方法是使用
示例代碼

public class DataBean implements Serializable { 
private Date currentTime; 

public setDate() { 
    currentTime = Calendar.getInstance().getTime(); 
} 

public Date getCurrentTime() { 
    return currentTime; 
} 
} 

公司Databean的PUT物件在捆綁:

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(); 
    } 

得到包對象回:

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; 
    } 

希望這將有助於其他好友。

139

您也可以使用Gson將對象轉換爲JSONObject並在捆綁上傳遞它。對我而言,我發現這是最優雅的方式。我沒有測試它如何影響性能。

在初始活性

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); 
0

我碰到這個問題來了,當我正在尋找一種方式來傳遞一個Date對象。在我的情況中,正如在答案中提出的那樣,我使用了Bundle.putSerializable(),但這不適用於原始文章中描述的DataManager這樣複雜的事情。

我的建議將會給出一個非常類似的結果,將DataManager放入應用程序或使其成爲Singleton,就是使用依賴注入並將DataManager綁定到Singleton範圍,並在需要時將DataManager注入。您不僅可以獲得提高可測試性的好處,而且還可以獲得更清晰的代碼,而不需要所有的「傳遞類和活動之間的依賴關係」代碼。 (Robo)Guice非常容易使用,並且新的Dagger框架也看起來很有希望。

1

我也想推薦這個優秀的Blog郵報,比較各種不同的選項,其性能的影響

4

可能的解決方案:

Bundle bundle = new Bundle(); 
bundle.putSerializable(new CustomObject()); 

類CustomObject:

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

Subcustom對象:

class SubCustomObject1 implements Serializable{ } 

class SubCustomObject2 implements Serializable{ } 
0

另一種簡單的方法使用束傳遞對象:

  • 的類對象,創建一個靜態列表或與其他數據結構的關鍵
  • 當您創建對象,把它放在列表/數據結構與密鑰(如。創建對象時的長時間戳)
  • 創建方法static getObject(long key)從列表中獲取對象
  • 在包中傳遞密鑰,因此您可以稍後從另一個點獲取對象代碼