Android Fragment之間的數(shù)據(jù)交流

Android Fragment Argument

眾所周知,多用Fragment能打造更靈活的程序。
本文通過一個淺顯的例子,來闡釋fragment之間基于Argument的數(shù)據(jù)交流。

簡單說一下要實現(xiàn)的目標(biāo):
本項目包含兩個活動和分別依附于這兩個活動的兩個Fragment。
簡單起見,這里分別為他們起名為:FirstActivityFirstFragment、SecondActivity、SecondFragment。
他們之間的關(guān)系是:
兩個活動只負(fù)責(zé)容納(或者說托管)其對應(yīng)的兩個Fragment。而具體的顯示和與用戶交互則由Fragment負(fù)責(zé)。

為了突出重點,這里只實現(xiàn)最簡單的功能:

  • FirstFragment中顯示一個ListView,這個ListView顯示一串編程語言的名稱。
  • 當(dāng)用戶點擊其中的item時,會跳轉(zhuǎn)到SecondActivity
  • 這時SecondActivityonCreate()方法啟動,在其中加載SecondFragment。
  • 最后SecondFragmentTextView控件根據(jù)傳過來的信息顯示相應(yīng)的編程語言的名字。

如圖:


就是這個意思

在代碼中實現(xiàn)時,FirstActivitySecondActivity甚至都不需要對應(yīng)的Layout資源文件。因為它們唯一的作用只是為Fragment提供容器,所以這里只需要在java代碼中為兩個Activity設(shè)置contentView即可:

setContentView(R.layout.common_fragment_container);

這個名為common_fragment_container的布局文件提供了一個FrameLayout來作為Fragment的容器:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/fragment_container"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

根據(jù)我們的構(gòu)想,當(dāng)用戶點擊FirstFragment中的ListView的item時,應(yīng)該跳轉(zhuǎn)到SecondActivity
為此,我們在SecondActivity中定義靜態(tài)方法:


    private final static String 
    EXTRA_LANGUAGE_PICKED = "language_picked"; //鍵

    
//靜態(tài)方法,提供從別的活動跳轉(zhuǎn)到SecondActivity
public static Intent newIntent(Context packageContext, String languagePicked) {
        Intent intent = new Intent(packageContext, SecondActivity.class);
        intent.putExtra(EXTRA_LANGUAGE_PICKED, languagePicked);
        return intent;
    }

FirstFragment中ListView item的點擊回調(diào):

public class FirstFragment extends Fragment {

    ListView mList;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.fragment_first, container, false);
        mList = v.findViewById(R.id.list);
//點擊回調(diào)
        mList.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Resources resources = getResources();
//得到資源文件中定義的字符串?dāng)?shù)組
                String[] languages = 
resources.getStringArray(R.array.languages);
                String str = languages[position];
                Intent intent = SecondActivity.newIntent(
getActivity(), str);
//啟動SecondActivity
                startActivity(intent);
            }
        });
        return v;

    }
}

當(dāng)FirstFragment通過startActivity(intent)啟動SecondActivity之后。
SecondActivity并不直接與用戶交互。

它要做的是:

  • 將傳入的intent中的用戶點擊的編程語言名稱取出來;
  • 然后傳給SecondFragment。由SecondFragment將它顯示出來。

SecondFragment想從SecondActivity那兒取到數(shù)據(jù)有兩種方式:

第一種比較直接:

SecondFragment簡單粗暴地通過getActivity()方法得到托管自己的SecondActivity;
然后通過getIntent()方法得到從FirstFragment中傳過來的Intent對象;
最后得到其中的extra信息。

這種方式雖然簡單,但也有代價。那就是破壞了封裝。使得SecondFragment不能被復(fù)用。因為此時它還承擔(dān)了的工作。

第二種方式比較復(fù)雜,但也更靈活:附加argument給Fragment:

要附加argument給Fragment,需要調(diào)用Fragment.setArguments(Bundle)方法。而且必須是在fragment創(chuàng)建后,添加給Activity之前。
因此,一般的慣用做法是在Fragment類中添加newInstance()靜態(tài)方法。
通過這個方法完成fragment實例以及Bundle對象的創(chuàng)建,
最后再把a(bǔ)rgument放入bundle對象中,并附加給fragment:

//SecondFragment
public class SecondFragment extends Fragment {

private static final String 
ARG_LANGUAGE_PICKED = "arg_language_picked";

    TextView mText;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        
        View v = inflater.inflate(R.layout.fragment_second, container, false);
        mText = v.findViewById(R.id.language_picked);
        String languagePicked 
= getArguments().getString(ARG_LANGUAGE_PICKED);
        mText.setText(languagePicked);
        return v;
    }

//newInstance()方法
    public static Fragment newInstance(String languagePicked) {
        Bundle bundle = new Bundle();
        bundle.putSerializable(ARG_LANGUAGE_PICKED, languagePicked);

        Fragment SecondFragmentInstance = new SecondFragment();
        SecondFragmentInstance.setArguments(bundle);
        return SecondFragmentInstance;
    }

}

現(xiàn)在我們有了這個方法,又得到了FirstFragment傳入的Intent對象中的extra信息languagePicked;
我們只需要在SecondActivityonCreate()方法中,將languagePicked作為參數(shù)傳入SecondFragment.newInstance()方法;
即可實現(xiàn),在SecondFragment創(chuàng)建之后,被添加給SecondActivity之前;
SecondFragment裝載argument

//SecondActivity
public class SecondActivity extends AppCompatActivity {

private final static String 
EXTRA_LANGUAGE_PICKED = "language_picked";

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
//使用通用的Fragment容器,
setContentView(R.layout.common_fragment_container);
//因為目前兩個Activity的布局中
//其實都只需要一個用于容納Fragment的frameLayout
       
        //要想在Activity中創(chuàng)建Fragment,先要得到FragmentManager
        FragmentManager fragmentManager = getSupportFragmentManager();
        Fragment fragment = fragmentManager.findFragmentById(R.id.fragment_container);

        if (fragment == null) {
            //在firstActivity中通過Intent跳轉(zhuǎn)到secondActivity,
            //SecondActivity創(chuàng)建之后,從傳入的Intent中得到extra信息,
            //然后根據(jù)這個信息來創(chuàng)建secondFragment實例,
            //得到的信息將用來作為參數(shù),傳入secondFragment的newInstance()方法
            String languagePicked = 
getIntent().getStringExtra(EXTRA_LANGUAGE_PICKED);
//SecondFragment.newInstance()方法
            fragment = SecondFragment.newInstance(languagePicked);

            fragmentManager.beginTransaction()
                    .add(R.id.fragment_container, fragment)
                    .commit();
        }


    }

    //靜態(tài)方法,提供從別的活動跳轉(zhuǎn)到自身的Intent
    public static Intent newIntent(Context packageContext, String languagePicked) {
        Intent intent = new Intent(packageContext, SecondActivity.class);
        intent.putExtra(EXTRA_LANGUAGE_PICKED, languagePicked);
        return intent;
    }
}

這一做法的靈活之處就在于:
SecondFragment雖然需要得到數(shù)據(jù),但是它不再親自去,
而是由托管它的Activity(此處是SecondActivity)來負(fù)責(zé)提供數(shù)據(jù)。
如此一來,就實現(xiàn)了SecondActivity的復(fù)用。
倘若現(xiàn)在有一個ThirdActivity也想要托管SecondFragment,那它只要能提供數(shù)據(jù)(類似于SecondActivity提供的languagePicked),那它就一樣可以其onCreate()方法中作出類似的實現(xiàn)。
-- end --

水平有限,難免紕漏,如有錯誤,歡迎指正。
諸君共勉:)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容