1. 程式人生 > >Activity Fragment資料傳遞(物件)引用不變問題

Activity Fragment資料傳遞(物件)引用不變問題

一.背景

一天寫程式碼出了bug,Activity傳給fragment的arraylist經過fragment中的修改居然會改變activity的arrayList(之前傳給fragment的那個),當時我就震驚了生氣,顛覆了我多年對Android的認知。

一開始找到這篇部落格:http://www.cnblogs.com/duanxz/p/3566221.html  裡面說bundle是傳遞引用,但是事實不是,下面例子來證明  此處還是感謝大神微笑

顛覆的常識

1.序列化反序列化前後物件內容一樣但是肯定不是一個物件,同理ArrayList(目測Activity和Fragment之間並沒有序列化反序列化

2.直接列印ArrayList或者物件就可以看到他的儲存地址(事實證明這是扯淡!!!

3.直接列印物件或者arraylist,或者hashcode 只要列印結果一樣,那麼它們的引用肯定是指向一個地方。(詳情看看toString原始碼,居然錯了這麼多年,慚愧啊大哭

二.來個栗子

1.MainActivity傳遞資料給SecondActivity

MainActivity.java

package com.example.administrator.text0212;

import android.content.Intent;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;

import java.util.ArrayList;

public class MainActivity extends AppCompatActivity {

    private ArrayList<User> userList = new ArrayList<>();
    private ArrayList<User> userListUseBundle = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        System.out.println("xcqw onCreate");
        setContentView(R.layout.activity_main);
        for(int i = 0;i<2;i++){
            User user = new User("大熊"+i+"號","man");
            userList.add(user);
        }

        for(int i= 0;i<3;i++){
            User user = new User("bundle"+i+"號","wonman");
            userListUseBundle.add(user);
        }
        findViewById(R.id.bt_jump).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent();
                Bundle bundle = new Bundle();
                bundle.putParcelableArrayList("userListBundle",userListUseBundle);
                intent.putParcelableArrayListExtra("userList",userList);
                intent.putExtra("bundle",bundle);
                System.out.println("xcqw MainActivity userList   "+userList);
                System.out.println("xcqw MainActivity userList hashCode  "+userList.hashCode());
                System.out.println("xcqw MainActivity userListBundle   "+userListUseBundle);
                System.out.println("xcqw MainActivity userListBundle hashCode  "+userListUseBundle.hashCode());
                startActivity(intent.setClass(MainActivity.this,SecondActivity.class));
            }
        });
    }

    @Override
    protected void onResume() {
        super.onResume();
        System.out.println("xcqw userList.size()"+userList.size());
        System.out.println("xcqw userListUseBundle.size()"+userListUseBundle.size());
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        System.out.println("xcqw onDestory");
    }
}
SecondActivity.java
package com.example.administrator.text0212;

import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.Toast;

import java.util.ArrayList;

public class SecondActivity extends AppCompatActivity {
    private ArrayList<User> userList2 = new ArrayList<>();
    private ArrayList<User> userListBundle2 = new ArrayList<>();
    public ArrayList<User> userList;
    private ArrayList<User> userListBundle;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_second);
        Intent intent = getIntent();
        userList = intent.getParcelableArrayListExtra("userList");
        Bundle bundle = intent.getBundleExtra("bundle");
        userListBundle = bundle.getParcelableArrayList("userListBundle");
        System.out.println("xcqw SecondActivity userList   " + userList);
        System.out.println("xcqw SecondActivity userList hashCode  " + userList.hashCode());
        System.out.println("xcqw SecondActivity userListBundle   " + userListBundle);
        System.out.println("xcqw SecondActivity userListBundle hashCode  " + userListBundle.hashCode());

        userList2.addAll(userList);
        userListBundle2.addAll(userListBundle);

        System.out.println("xcqw SecondActivity userList2   " + userList);
        System.out.println("xcqw SecondActivity userList2 hashCode  " + userList.hashCode());
        System.out.println("xcqw SecondActivity userListBundle2   " + userListBundle);
        System.out.println("xcqw SecondActivity userListBundle2 hashCode  " + userListBundle.hashCode());

        if (userList2 == userList) {
            System.out.println("xcqw  前後一致1");
        } else {
            System.out.println("xcqw userList2 != userList");
            System.out.println("xcqw userList.getClass()" + userList.getClass());
            System.out.println("xcqw userList2.getClass()" + userList2.getClass());
            System.out.println("xcqw SecondActivity userList   " + userList);
            System.out.println("xcqw SecondActivity userList hashCode  " + userList.hashCode());
            System.out.println("xcqw SecondActivity userList2   " + userList);
            System.out.println("xcqw SecondActivity userList2 hashCode  " + userList.hashCode());
        }

        if (userListBundle2 == userListBundle) {
            System.out.println("xcqw 前後一致2");
        } else {
            System.out.println("xcqw userListBundle2 != userListBundle");
            System.out.println("xcqw SecondActivity userListBundle   " + userListBundle);
            System.out.println("xcqw SecondActivity userListBundle hashCode  " + userListBundle.hashCode());
            System.out.println("xcqw SecondActivity userListBundle2   " + userListBundle);
            System.out.println("xcqw SecondActivity userListBundle2 hashCode  " + userListBundle.hashCode());
        }

        if (userList.equals(userList2)) {
            System.out.println("xcqw userList.equals(userList2)");
        } else {
            System.out.println("xcqw userList不equals(userList2)");
        }

        if (userListBundle.equals(userListBundle2)) {
            System.out.println("xcqw userListBundle.equals(userListBundle2)");
        } else {
            System.out.println("xcqw userListBundle不equals(userListBundle2)");
        }

        findViewById(R.id.bt_add_fragment).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ContentFragment contentFragment = new ContentFragment();
                Bundle bundle2 = new Bundle();
                bundle2.putParcelableArrayList("userListActivity", userList);
                bundle2.putString("succ", "成功了");
                contentFragment.setArguments(bundle2);
                FragmentManager fragmentManager = getSupportFragmentManager();
                FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
                fragmentTransaction.replace(R.id.fl_container, contentFragment);
                fragmentTransaction.commitAllowingStateLoss();
            }
        });

        findViewById(R.id.bt_get_userlist).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(SecondActivity.this, "userList"+userList.size(), Toast.LENGTH_SHORT).show();
            }
        });
    }

}



(1)沒有覆寫User equals和hashCode

package com.example.administrator.drawlayout;

import android.os.Parcel;
import android.os.Parcelable;

/**
 * Created by Administrator on 2017/2/12 0012.
 */
public class User implements Parcelable{

    private String name;
    private String sex;

    protected User(Parcel in) {
        name = in.readString();
        sex = in.readString();
    }

    public static final Creator<User> CREATOR = new Creator<User>() {
        @Override
        public User createFromParcel(Parcel in) {
            return new User(in);
        }

        @Override
        public User[] newArray(int size) {
            return new User[size];
        }
    };

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public User() {
    }

    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel parcel, int i) {
        parcel.writeString(name);
        parcel.writeString(sex);
    }

//    @Override
//    public boolean equals(Object o) {
//        if (this == o) return true;
//        if (!(o instanceof User)) return false;
//
//        User user = (User) o;
//
//        if (name != null ? !name.equals(user.name) : user.name != null) return false;
//        return sex != null ? sex.equals(user.sex) : user.sex == null;
//
//    }
//
//    @Override
//    public int hashCode() {
//        int result = name != null ? name.hashCode() : 0;
//        result = 31 * result + (sex != null ? sex.hashCode() : 0);
//        return result;
//    }

}

列印結果:看起來很符合之前的“嘗試” hashcode不一樣,當然UserList2 != userList

MainActivity userList   [[email protected], [email protected]]
MainActivity userList hashCode  186635194
MainActivity userListBundle   [[email protected], [email protected], [email protected]]
MainActivity userListBundle hashCode  -766434790


//收到Activity傳進來的資料
SecondActivity userList   [[email protected], [email protected]]
SecondActivity userList hashCode  -839526990
SecondActivity userListBundle   [[email protected], [email protected], [email protected]]
SecondActivity userListBundle hashCode  -51512212
//Activity中 new 出來的 userList ,userListBundle2
SecondActivity userList2   [[email protected], [email protected]]
SecondActivity userList2 hashCode  -839526990
SecondActivity userListBundle2   [[email protected], [email protected], [email protected]]
SecondActivity userListBundle2 hashCode  -51512212


userList2 != userList
userList.getClass()class java.util.ArrayList
userList2.getClass()class java.util.ArrayList
SecondActivity userList   [[email protected], [email protected]]
SecondActivity userList hashCode  -839526990
SecondActivity userList2   [[email protected], [email protected]]
SecondActivity userList2 hashCode  -839526990


userListBundle2 != userListBundle
SecondActivity userListBundle   [[email protected], [email protected], [email protected]]
SecondActivity userListBundle hashCode  -51512212
SecondActivity userListBundle2   [[email protected], [email protected], [email protected]]
SecondActivity userListBundle2 hashCode  -51512212


userList.equals(userList2)
userListBundle.equals(userListBundle2)

(2)重寫equals

列印和之前一樣

(3)重寫equals和hashCode

MainActivity userList   [[email protected], [email protected]]
MainActivity userList hashCode  2136183170
MainActivity userListBundle   [[email protected], [email protected], [email protected]]
MainActivity userListBundle hashCode  928096571


SecondActivity userList   [[email protected], [email protected]]
SecondActivity userList hashCode  2136183170
SecondActivity userListBundle   [[email protected], [email protected], [email protected]]
SecondActivity userListBundle hashCode  928096571


SecondActivity userList2   [[email protected], [email protected]]
SecondActivity userList2 hashCode  2136183170
SecondActivity userListBundle2   [[email protected], [email protected], [email protected]]
SecondActivity userListBundle2 hashCode  928096571


userList2 != userList
userList.getClass()class java.util.ArrayList
userList2.getClass()class java.util.ArrayList
SecondActivity userList   [[email protected], [email protected]]
SecondActivity userList hashCode  2136183170
SecondActivity userList2   [[email protected], [email protected]]
SecondActivity userList2 hashCode  2136183170


userListBundle2 != userListBundle
SecondActivity userListBundle   [[email protected], [email protected], [email protected]]
SecondActivity userListBundle hashCode  928096571
SecondActivity userListBundle2   [[email protected], [email protected], [email protected]]
SecondActivity userListBundle2 hashCode  928096571


userList.equals(userList2)
userListBundle.equals(userListBundle2)

這個再一次證明記憶體地址是否一樣跟hashcode沒有任何關係,也跟直接列印物件得到的值沒關係,即使兩者相等也不會一樣

第一個例子說明:

1.hashcode和直接列印物件跟記憶體地址(也就是引用)沒有任何關係

2.Bundle傳遞也是傳資料不是傳引用!!!

2.Activity傳遞資料到Fragment

(1)沒有覆寫equals和hashCode

Content成功了
contentFragment userArrayList   [[email protected], [email protected]]
contentFragment userArrayList hashcode  -839526990
contentFragment userArrayList.toString [[email protected], [email protected]]


((SecondActivity)getActivity()).userList == userArrayList


contentFragment otherUserList    [[email protected], [email protected]]
contentFragment otherUserList hashcode    -839526990
contentFragment otherUserList.toString    [[email protected], [email protected]]


((SecondActivity)getActivity()).userList != otherUserList
userArrayListSize2
 clear userArrayList userArrayListSize0


另外點選另外一個按鈕獲取Activity中的userList 的size發現也是0

可以看到otherUserList和userArrayList雖然列印直接列印的值和hascode的值一樣,但是並沒有什麼軟用,他們還是 != 

還有就是證明了一點就是Activity傳遞資料給fragment傳的是引用

(2)覆寫equals

所有結果和上面一樣

(3)覆寫equals和hashcode

只是列印的hashcode值變了,結果沒有變

三.總結

1.hashCode和直接列印物件的值與記憶體地址沒有任何關係

2.Activity與Fragment資料傳遞會保持物件的引用,不管是parcelable還是Serizable(但是不知道為什麼???待研究)

3.判斷物件引用是否相同目前發現有且只有一個  obj1 == obj2

相關推薦

Activity Fragment資料傳遞物件引用問題

一.背景 一天寫程式碼出了bug,Activity傳給fragment的arraylist經過fragment中的修改居然會改變activity的arrayList(之前傳給fragment的那個),當時我就震驚了,顛覆了我多年對Android的認知。 一開始找到這篇部落格

Vue基礎知識之元件及元件之間的資料傳遞

vue中的元件是自定的標籤,可以擴充套件的原生html元素,封裝可複用的程式碼 note: 1、在標籤命中不要使用大寫,標籤名字必須用短橫線隔開 2、模板中只能有一個根元素,不能使用並列標籤。 定義元件 全域性定義,在所有例項中都可以使用這個元件 <t

PyQt訊號與槽之多視窗資料傳遞

前言 在pyqt程式設計過程中,經常會遇到輸入或選擇多個引數的問題,把多個引數寫到一個視窗中,主視窗會顯得很臃腫,所以,一般是新增一個按鈕,呼叫對話方塊,在對話方塊中進行引數的選擇,關閉對話方塊將引數返回給主視窗 pyqt提供了一些標準的對話方塊類,用於輸入

Redis 的底層資料結構物件

目前為止,我們介紹了 redis 中非常典型的五種資料結構,從 SDS 到 壓縮列表,這都是 redis 最底層、最常用的資料結構,相信你也掌握的不錯。 但 redis 實際儲存鍵值對的時候,是基於物件這個基本單位的,並且往往一個物件下面對對應不同的底層資料結構實現以便於在不同的場景下切換底層實現提升效率。例

Picasso原始碼分析模式、建造者模式和Request的預處理

Request的不變模式(Immutable Pattern)   不變模式可增強物件的強壯型,允許多個物件共享某一個物件,降低了對該物件進行併發訪問時的同步化開銷。如果需要修改一個不變物件的狀態,那麼就需要建立一個新的同類型物件,並在建立時將這個新的狀態

兩個Activity之間的資料傳遞使用簡單的intent方法

android程式設計學習中,最近在編寫一個簡單的android專案,實現在TwoActivity(書籍列表)中點選LisView的任意item傳遞書名,給ThreeAvtivity(章節列表),通過接收到的資料(書名)確定顯示書的章節目錄,使用的是intent方法。其中T

深入理解JAVA虛擬機器——JVM的資料型別以及按引用傳遞法則

Java虛擬機器是通過某些資料型別來執行計算的,資料型別可以分為兩種:基本型別和引用型別,基本型別的變數持有原始值,而引用型別的變數持有引用值。    Java語言中的所有基本型別同樣也都是Java虛擬

傳遞地址引用傳遞

out swa 改變 nbsp 調用 oid cout div value #include <iostream> #include <string> using namespace std; //值傳遞:(傳值調用) //效果上:方法內的改變不

Android 基於Netty的訊息推送方案之物件傳遞

在上一篇文章中《Android 基於Netty的訊息推送方案之字串的接收和傳送(三)》我們介紹了Netty的字串傳遞,我們知道了Netty的訊息傳遞都是基於流,通過ChannelBuffer傳遞的,那麼自然,Object也需要轉換成ChannelBuffer來傳遞。好在Netty本身已經給我們寫好了

JAVA學習筆記-----第六天引用資料型別

●引用資料型別(類)     ■ 類的型別有兩種:         ◆第一種,JAVA為我們提供好的類,如Scanner類,Math類,這些已存在的類中包含了很多的方法和屬性,可供我們使用。   &

物件轉型instanceof關鍵字物件引用與所指物件的型別之間各種關係

1、物件之間的轉換並非是隨意進行的轉換,在基本型別的轉換中,有自動型別轉換,還有一種強制型別轉換,但是物件型別的轉換不能強制地隨意地進行轉換,而是有一種約束,是一種上下繼承層次關係的轉換。 2、instanceof關鍵字: (1)使用方法:引用空格instanceof空格

基本型別和引用型別作為引數傳遞重要

基本型別和引用型別作為引數傳遞 引用型別資料和基本型別資料作為引數傳遞有沒有差別呢?我們用如下程式碼進行說明,並配合圖解讓大家更加清晰 1.基本資料型別傳遞 基本型別作為引數傳遞時,其實就是將基本型別變數x空間中的值複製了一份傳遞給呼叫的方法show(),當在show()方法中

[10]基本型別和引用型別的引數傳遞

前言:主要為個人筆記 基本型別 程式碼: class Demo{ public static void main(String[] args){ int x=4;

Android進階2之Activity之間資料交流onActivityResult的用法

                主要功能:在一個主介面(主Activity)上能連線往許多不同子功能模組(子Activity上去),當子模組的事情做完之後就回到主介面,或許還同時返回一些子模組完成的資料交給主Activity處理。這樣的資料交流就要用到回撥函式onActivityResult。<1>

ActivityFragment資料傳遞FragmentActivity獲取資料

整理Fragment與Activity之間的資料交換,大體上包括三種: 1、Fragment從Activity獲取資料 2、Activity從Fragment獲取資料 3、Fragment之間獲取資料

react學習之路2.2-----資料傳遞props(子傳父級),context

react學習之路,資料傳遞(props,context); 再講props子父級之前,先學習一下context這個非常NB的資料接收容器,如何正確的使用,接下來為大家介紹, 用它之前,我們必須要知道有個叫prop-types的東西,從英文我們就知道意思就是叫我們定義資料型

java web開中WebRoot下的jsp和WebRoot資料夾下的jsphtml引用css樣式

這是專案的檔案忘了怎麼說了,反正就是這樣子的。 首先WebRoot下有一個資料夾admin主要存放管理員相關的頁面。 頁面使用的是frameset框架,具體頁面如下: 話說回來資料夾下面的html和jsp頁面怎麼訪問WebRoot下的css裡面的styles.css樣式

java中的值傳遞引用傳遞隨筆

       這裡複習一下Java的值傳遞與引用傳遞。        值傳遞(形式引數型別是基本資料型別):方法呼叫時,實際引數把它的值傳遞給對應的形式引數,形式引數只是用實際引數的值初始化自己的儲存單元內容,是

Android程式設計學習筆記 之 FragmentActivity資料傳遞

傳遞方向的不同: ①Activity----->Fragment: 在Activity中建立Bundle資料包,並呼叫Fragment的setArguments(Bundle bundle)方法 ②Fragment----->Activity: 需要在Frag

資料結構java---物件的記憶體表示

物件在記憶體主要分為二種組成,一個是儲存非靜態的類的屬性物件區,另一個是儲存方法的方法區(包括靜態方法和非靜態方法),如果有靜態常量的話,靜態常量將儲存在靜態常量區中。 因為一個物件例項的屬性是變化的,但是方法和靜態常量是不變,這樣儲存可以更加程度的利用記憶體。 cla