1. 程式人生 > >Android實現Fragment與Activity之間的資料互動

Android實現Fragment與Activity之間的資料互動

1概念

1 為什麼

因為Fragment和Activity一樣是具有生命週期,不是一般的bean通過建構函式傳值,會造成異常。

2 參考連結

Activity和Fragment傳遞資料的兩種方式

【Fragment精深系列4】Fragment與Activity之間的資料互動

2 Activity把值傳遞給Fragment

2.1 第一種方式,也是最常用的方式,就是使用Bundle來傳遞引數

(1)宿主Activity/FragmentAdapter中:

Bundle bundle = new Bundle();
bundle.putString(Constant.INTENT_ID, productId);
Fragment fragment = null
; switch (position) { case 0: fragment = new ProductImageDetailFragment(); break; case 1: fragment = new ProductParamFragment(); break; case 2: fragment = new ProductCommentFragment(); break; default: break; } fragment.setArguments(bundle);
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

(2)Activity/FragmentAdapter中:

Fragment中的onCreatView/onStart()方法中,通過getArgments()方法,獲取到bundle物件,然後通過getString的key值拿到我們傳遞過來的值。

    @Override
public void onStart() { super.onStart(); if (isAdded()) {//判斷Fragment已經依附Activity productId = getArguments().getString(Constant.INTENT_ID); } }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

2.2 第二種方式,是在宿主Activity中定義方法,將要傳遞的值傳遞到Fragment中,在Fragment中的onAttach方法中,獲取到這個值。

(1)宿主activity中的getTitles()方法

public String getTitles(){
    return "hello";
}
    
  • 1
  • 2
  • 3

(2)Fragment中的onAttach方法

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    titles = ((MainActivity) activity).getTitles();//通過強轉成宿主activity,就可以獲取到傳遞過來的資料
}
    
  • 1
  • 2
  • 3
  • 4
  • 5

2.3 第三種方式,是擴充套件一下建立Fragment和傳遞數值

(1)在宿主activity中,建立Fragment

FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        fragmentTransaction.setCustomAnimations(android.R.anim.fade_in,android.R.anim.fade_out);
fragment1 = MyFragment.newInstance("這是第一個fragment");//這裡只需要直接呼叫這個方法,就建立了一個fragment
fragment2 = MyFragment.newInstance("這是第二個fragment");

    
  • 1
  • 2
  • 3
  • 4
  • 5

(2)Fragment中

//定義newInstance()例項
static MyFragment newInstance(String s){
        MyFragment myFragment = new MyFragment();
        Bundle bundle = new Bundle();
        bundle.putString("DATA",s);
        myFragment.setArguments(bundle);
        return myFragment;
    }

//同樣,在onCreatView中直接獲取這個值
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        //......
        Bundle bundle = getArguments();
        String data = bundle.getString("DATA");

    }
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

3 Fragment把值傳遞給Activity

3.1 步驟

(1)在fragment中定義一個內部回撥介面,再讓包含該fragment的activity實現該回調介面,這樣fragment即可呼叫該回調方法將資料傳給activity。其實介面回撥的原理都一樣,以前的部落格有講到,介面回撥是java不同物件之間資料互動的通用方法。

(2)activity實現完了介面怎麼傳給剛才的fragment呢?當fragment新增到activity中時,會呼叫fragment的方法onAttach(),這個方法中適合檢查activity是否實現了OnArticleSelectedListener介面,檢查方法就是對傳入的activity的例項進行型別轉換,然後賦值給我們在fragment中定義的介面。

(3)在一個fragment從activity中剝離的時候,就會呼叫onDetach方法,這個時候要把傳遞進來的activity物件釋放掉,不然會影響activity的銷燬,產生不必要的錯誤。注意看onAttach方法中的程式碼,在賦值之前要做一個判斷,看看Activity中有沒有實現了這個介面,用到了instanceof。如果沒有實現介面,我們就丟擲異常。

3.2 例子

(1)在宿主activity中,建立Fragment

public class MainActivity extends Activity implements MenuFragment.FragmentInteraction{

    private TextView textView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        textView = (TextView) findViewById(R.id.content_text);
    }

    // 3.2 +實現介面,實現回撥
    @Override
    public void process(String str) {
        if (str != null) {
            textView.setText(str);
        }
    }
}
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

(2)Fragment中

public class MenuFragment extends Fragment implements View.OnClickListener {

    // 2.1 定義用來與外部activity互動,獲取到宿主activity
    private FragmentInteraction listterner;

    // 1 定義了所有activity必須實現的介面方法
    public interface FragmentInteraction {
        void process(String str);
    }

    // 當FRagmen被載入到activity的時候會被回撥
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);

        if(activity instanceof FragmentInteraction) {
            listterner = (FragmentInteraction)activity; // 2.2 獲取到宿主activity並賦值
        } else{
            throw new IllegalArgumentException("activity must implements FragmentInteraction");
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_menu, container, false);
        View btn = view.findViewById(R.id.tv_button);
        View btn_m = view.findViewById(R.id.movie_button);
        if (btn != null||btn_m!=null) {
            btn.setOnClickListener(this);
            btn_m.setOnClickListener(this);
        }
        return view;
    }

    @Override
    public void onClick(View v) {
        int id  = v.getId();
        switch (id) {
            case R.id.tv_button:
                listterner.process("我是電視劇"); // 3.1 執行回撥
                break;
            case R.id.movie_button:
                listterner.process("我是電影");
                break;
        }
    }

    //把傳遞進來的activity物件釋放掉
    @Override
    public void onDetach() {
        super.onDetach();
        listterner = null;
    }
}
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54

4 Fragment與Fragment之間的傳值

在Activity中載入Fragment的時候、有時候要使用多個Fragment切換、並傳值到另外一個Fragment、也就是說兩個Fragment之間進行引數的傳遞,有兩個方法。

4.1 通過共同的Activity傳遞(主要方法)

在Activity裡面新增一個欄位、來臨時儲存要一些值。在Activity中定義一個欄位、然後新增set和get方法。

(1)在宿主activity中

public class DemoActivity {

    private String mTitle;

    public String getmTitle() {
        return mTitle;
    }

    public void setmTitle(String title) {
        this.mTitle = title;
    }

}
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

(2)Fragment中

// 呼叫方法、需要注意的是在設值的時候要進行強轉一下
((DemoActivity)getActivity()).getmTitle();
    
  • 1
  • 2

4.1 通過Bundle來傳遞(本質還是Activity–>Fragment)

(1)在宿主activity中

ft.hide(getActivity().getSupportFragmentManager().findFragmentByTag(""));
    DemoFragment demoFragment = new DemoFragment();  
    Bundle bundle = new Bundle();  
    bundle.putString("key", "這是方法二");  
    demoFragment.setArguments(bundle);  
    ft.add(R.id.fragmentRoot, demoFragment, SEARCHPROJECT);  
    ft.commit();  
    
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

(2)Fragment中

String string = getArguments().getString("key");  
    
  • 1

1概念

1 為什麼

因為Fragment和Activity一樣是具有生命週期,不是一般的bean通過建構函式傳值,會造成異常。

2 參考連結

Activity和Fragment傳遞資料的兩種方式

【Fragment精深系列4】Fragment與Activity之間的資料互動

2 Activity把值傳遞給Fragment

2.1 第一種方式,也是最常用的方式,就是使用Bundle來傳遞引數

(1)宿主Activity/FragmentAdapter中:

Bundle bundle = new Bundle();
bundle.putString(Constant.INTENT_ID, productId);
Fragment fragment = null;
switch (position) {
     case 0:
        fragment = new ProductImageDetailFragment();
        break;

     case 1:
        fragment = new ProductParamFragment();
        break;

     case 2:
        fragment = new ProductCommentFragment();
        break;

     default:
        break;
}
fragment.setArguments(bundle);
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

(2)Activity/FragmentAdapter中:

Fragment中的onCreatView/onStart()方法中,通過getArgments()方法,獲取到bundle物件,然後通過getString的key值拿到我們傳遞過來的值。

    @Override
    public void onStart() {
        super.onStart();
        if (isAdded()) {//判斷Fragment已經依附Activity
            productId = getArguments().getString(Constant.INTENT_ID);
        }
    }
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

2.2 第二種方式,是在宿主Activity中定義方法,將要傳遞的值傳遞到Fragment中,在Fragment中的onAttach方法中,獲取到這個值。

(1)宿主activity中的getTitles()方法

public String getTitles(){
    return "hello";
}
  
  • 1
  • 2
  • 3

(2)Fragment中的onAttach方法

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    titles = ((MainActivity) activity).getTitles();//通過強轉成宿主activity,就可以獲取到傳遞過來的資料
}
  
  • 1
  • 2
  • 3
  • 4
  • 5

2.3 第三種方式,是擴充套件一下建立Fragment和傳遞數值

(1)在宿主activity中,建立Fragment

FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        fragmentTransaction.setCustomAnimations(android.R.anim.fade_in,android.R.anim.fade_out);
fragment1 = MyFragment.newInstance("這是第一個fragment");//這裡只需要直接呼叫這個方法,就建立了一個fragment
fragment2 = MyFragment.newInstance("這是第二個fragment");

  
  • 1
  • 2
  • 3
  • 4
  • 5

(2)Fragment中

//定義newInstance()例項
static MyFragment newInstance(String s){
        MyFragment myFragment = new MyFragment();
        Bundle bundle = new Bundle();
        bundle.putString("DATA",s);
        myFragment.setArguments(bundle);
        return myFragment;
    }

//同樣,在onCreatView中直接獲取這個值
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        //......
        Bundle bundle = getArguments();
        String data = bundle.getString("DATA");

    }
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

3 Fragment把值傳遞給Activity

3.1 步驟

(1)在fragment中定義一個內部回撥介面,再讓包含該fragment的activity實現該回調介面,這樣fragment即可呼叫該回調方法將資料傳給activity。其實介面回撥的原理都一樣,以前的部落格有講到,介面回撥是java不同物件之間資料互動的通用方法。

(2)activity實現完了介面怎麼傳給剛才的fragment呢?當fragment新增到activity中時,會呼叫fragment的方法onAttach(),這個方法中適合檢查activity是否實現了OnArticleSelectedListener介面,檢查方法就是對傳入的activity的例項進行型別轉換,然後賦值給我們在fragment中定義的介面。

(3)在一個fragment從activity中剝離的時候,就會呼叫onDetach方法,這個時候要把傳遞進來的activity物件釋放掉,不然會影響activity的銷燬,產生不必要的錯誤。注意看onAttach方法中的程式碼,在賦值之前要做一個判斷,看看Activity中有沒有實現了這個介面,用到了instanceof。如果沒有實現介面,我們就丟擲異常。

3.2 例子

(1)在宿主activity中,建立Fragment

public class MainActivity extends Activity implements MenuFragment.FragmentInteraction{

    private TextView textView;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        textView = (TextView) findViewById(R.id.content_text);
    }

    // 3.2 +實現介面,實現回撥
    @Override
    public void process(String str) {
        if (str != null) {
            textView.setText(str);
        }
    }
}
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

(2)Fragment中

public class MenuFragment extends Fragment implements View.OnClickListener {

    // 2.1 定義用來與外部activity互動,獲取到宿主activity
    private FragmentInteraction listterner;

    // 1 定義了所有activity必須實現的介面方法
    public interface FragmentInteraction {
        void process(String str);
    }

    // 當FRagmen被載入到activity的時候會被回撥
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);

        if(activity instanceof FragmentInteraction) {
            listterner = (FragmentInteraction)activity; // 2.2 獲取到宿主activity並賦值
        } else{
            throw new IllegalArgumentException("activity must implements FragmentInteraction");
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.fragment_menu, container, false);
        View btn = view.findViewById(R.id.tv_button);
        View btn_m = view.findViewById(R.id.movie_button);
        if (btn != null||btn_m!=null) {
            btn.setOnClickListener(this);
            btn_m.setOnClickListener(this);
        }
        return view;
    }

    @Override
    public void onClick(View v) {
        int id  = v.getId();
        switch (id) {
            case R.id.tv_button:
                listterner.process("我是電視劇"); // 3.1 執行回撥
                break;
            case R.id.movie_button:
                listterner.process("我是電影");
                break;
        }
    }

    //把傳遞進來的activity物件釋放掉
    @Override
    public void onDetach() {
        super.onDetach();
        listterner = null;
    }
}
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54

4 Fragment與Fragment之間的傳值

在Activity中載入Fragment的時候、有時候要使用多個Fragment切換、並傳值到另外一個Fragment、也就是說兩個Fragment之間進行引數的傳遞,有兩個方法。

4.1 通過共同的Activity傳遞(主要方法)

在Activity裡面新增一個欄位、來臨時儲存要一些值。在Activity中定義一個欄位、然後新增set和get方法。

(1)在宿主activity中

public class DemoActivity {

    private String mTitle;

    public String getmTitle() {
        return mTitle;
    }

    public void setmTitle(String title) {
        this.mTitle = title;
    }

}
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

(2)Fragment中

// 呼叫方法、需要注意的是在設值的時候要進行強轉一下
((DemoActivity)getActivity()).getmTitle();
  
  • 1
  • 2

4.1 通過Bundle來傳遞(本質還是Activity–>Fragment)

(1)在宿主activity中

ft.hide(getActivity().getSupportFragmentManager().findFragmentByTag(""));
    DemoFragment demoFragment = new DemoFragment();  
    Bundle bundle = new Bundle();  
    bundle.putString("key", "這是方法二");  
    demoFragment.setArguments(bundle);  
    ft.add(R.id.fragmentRoot, demoFragment, SEARCHPROJECT);  
    ft.commit();  
  
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

(2)Fragment中

String string = getArguments().getString("key");  
  
  • 1