To perform a transaction such as add or remove a fragment, you must use the FragmentManager
to create aFragmentTransaction
, which provides APIs to add, remove, replace, and perform other fragment transactions.
1.when the activity's onPause()
method is called, any fragments in the activity also receive a call toonPause()
.
2.创建Fragment
继承Fragment创建Fragment,其中 onCreateView()
方法用来确定Fragment加载哪个layout布局
To create a fragment, extend the Fragment
class, then override key lifecycle methods to insert your app logic, similar to the way you would with an Activity
class.
One difference when creating a Fragment
is that you must use the onCreateView()
callback to define the layout. In fact, this is the only callback you need in order to get a fragment running. For example, here's a simple fragment that specifies its own layout:
import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.ViewGroup; public class ArticleFragment extends Fragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // Inflate the layout for this fragment return inflater.inflate(R.layout.article_view, container, false); } }
3. FragmentActivity
is a special activity provided in the Support Library to handle fragments on system versions older than API level 11. If the lowest system version you support is API level 11 or higher, then you can use a regular Activity
Fragment在Activity中被使用时.:那个Activity
如果app运行的系统版本可能低于11时,需继承
FragmentActivity
,并需导入支持包
如果app运行的系统版本只高于等于11时,可直接继承Activity
4.If you're using the v7 appcompat library, your activity should instead extend ActionBarActivity
, which is a subclass of FragmentActivity
5.静态添加Fragment的一种使用方式
res/layout-large/news_articles.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:layout_width="fill_parent" android:layout_height="fill_parent"> <fragment android:name="com.example.android.fragments.HeadlinesFragment" android:id="@+id/headlines_fragment" android:layout_weight="1" android:layout_width="0dp" android:layout_height="match_parent" /> <fragment android:name="com.example.android.fragments.ArticleFragment" android:id="@+id/article_fragment" android:layout_weight="2" android:layout_width="0dp" android:layout_height="match_parent" /> </LinearLayout>
import android.os.Bundle; import android.support.v4.app.FragmentActivity; public class MainActivity extends FragmentActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.news_articles); } }Note: When you add a fragment to an activity layout by defining the fragment in the layout XML file, you cannot remove the fragment at runtime.
通过layout xml 这种布局方式定义添加的Fragment在Activity运行时不能被动态删除
6.动态添加Fragment的一种使用方式
you can add a fragment to the activity during the activity runtime. This is necessary if you plan to change fragments during the life of the activity.
在这里使用FrameLayout布局作为容器放置Fragment
res/layout/news_articles.xml:
<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" />
Inside your activity, call getSupportFragmentManager()
to get a FragmentManager
using the Support Library APIs. Then call beginTransaction()
to create a FragmentTransaction
and call add()
to add a fragment.
You can perform multiple fragment transaction for the activity using the same FragmentTransaction
. When you're ready to make the changes, you must call commit()
.
For example, here's how to add a fragment to the previous layout:
import android.os.Bundle; import android.support.v4.app.FragmentActivity; public class MainActivity extends FragmentActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.news_articles); // Check that the activity is using the layout version with // the fragment_container FrameLayout if (findViewById(R.id.fragment_container) != null) { // However, if we're being restored from a previous state, // then we don't need to do anything and should return or else // we could end up with overlapping fragments. if (savedInstanceState != null) { return; } // Create a new Fragment to be placed in the activity layout HeadlinesFragment firstFragment = new HeadlinesFragment(); // In case this activity was started with special instructions from an // Intent, pass the Intent's extras to the fragment as arguments firstFragment.setArguments(getIntent().getExtras()); // Add the fragment to the 'fragment_container' FrameLayout getSupportFragmentManager().beginTransaction() .add(R.id.fragment_container, firstFragment).commit(); } } }
Because the fragment has been added to the FrameLayout
container at runtime—instead of defining it in the activity's layout with a <fragment>
element—the activity can remove the fragment and replace it with a different one.
7.动态替换Fragment
The procedure to replace a fragment is similar to adding one, but requires the replace()
method instead ofadd()
.
Keep in mind that when you perform fragment transactions, such as replace or remove one, it's often appropriate to allow the user to navigate backward and "undo" the change. To allow the user to navigate backward through the fragment transactions, you must call addToBackStack()
before you commit theFragmentTransaction
.
Note: When you remove or replace a fragment and add the transaction to the back stack, the fragment that is removed is stopped (not destroyed). If the user navigates back to restore the fragment, it restarts. If you do not add the transaction to the back stack, then the fragment is destroyed when removed or replaced.
Example of replacing one fragment with another:
// Create fragment and give it an argument specifying the article it should show ArticleFragment newFragment = new ArticleFragment(); Bundle args = new Bundle(); args.putInt(ArticleFragment.ARG_POSITION, position); newFragment.setArguments(args); FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); // Replace whatever is in the fragment_container view with this fragment, // and add the transaction to the back stack so the user can navigate back transaction.replace(R.id.fragment_container, newFragment); transaction.addToBackStack(null); // Commit the transaction transaction.commit();
The addToBackStack()
method takes an optional string parameter that specifies a unique name for the transaction. The name isn't needed unless you plan to perform advanced fragment operations using theFragmentManager.BackStackEntry
APIs.
对于是否要加transaction.addToBackStack(null);也就是将Fragment加入到回退栈。官方的说法是取决于你是否要在回退的时候显示上一个Fragment。
8.不同Fragment间交互数据,Fragment与Activity交互数据
All Fragment-to-Fragment communication is done through the associated Activity. Two Fragments should never communicate directly.
所有的Fragment应该通过将他们连接在一起的Activity交互数据,而不应该直接交互
Fragment传递数据到Activity--------
通过在Fragment内设计一个Interface,在要绑定的Activity内实现这个接口,然后在Fragment的onAttach(Activity activity)方法内通过多态特性获取到Activity实现的这个接口中的方法,然后调用这个方法回调给绑定的Activity数据
)
To allow a Fragment to communicate up to its Activity, you can define an interface in the Fragment class and implement it within the Activity. The Fragment captures the interface implementation during its onAttach() lifecycle method and can then call the Interface methods in order to communicate with the Activity.
Here is an example of Fragment to Activity communication:
public class HeadlinesFragment extends ListFragment { OnHeadlineSelectedListener mCallback; // Container Activity must implement this interface public interface OnHeadlineSelectedListener { public void onArticleSelected(int position); } @Override public void onAttach(Activity activity) { super.onAttach(activity); // This makes sure that the container activity 1827 has implemented // the callback interface. If not, it throws an exception try { mCallback = (OnHeadlineSelectedListener) activity; } catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement OnHeadlineSelectedListener"); } } ... }
Now the fragment can deliver messages to the activity by calling the onArticleSelected()
method (or other methods in the interface) using the mCallback
instance of the OnHeadlineSelectedListener
interface.
In order to receive event callbacks from the fragment, the activity that hosts it must implement the interface defined in the fragment class.
For example, the following activity implements the interface from the above example.
public static class MainActivity extends Activity implements HeadlinesFragment.OnHeadlineSelectedListener{ ... public void onArticleSelected(int position) { // The user selected the headline of an article from the HeadlinesFragment // Do something here to display that article } }
For example, the following method in the fragment is called when the user clicks on a list item. The fragment uses the callback interface to deliver the event to the parent activity.
@Override public void onListItemClick(ListView l, View v, int position, long id) { // Send the event to the host activity mCallback.onArticleSelected(position); }
Activity传递数据到Fragment--------
The host activity can deliver messages to a fragment by capturing the Fragment
instance withfindFragmentById()
, then directly call the fragment's public methods.
通过Fragment的id号找到该Fragment,然后调用其中的方法传入参数
public static class MainActivity extends Activity implements HeadlinesFragment.OnHeadlineSelectedListener{ ... public void onArticleSelected(int position) { // The user selected the headline of an article from the HeadlinesFragment // Do something here to display that article ArticleFragment articleFrag = (ArticleFragment) getSupportFragmentManager().findFragmentById(R.id.article_fragment); if (articleFrag != null) { // If article frag is available, we're in two-pane layout... // Call a method in the ArticleFragment to update its content articleFrag.updateArticleView(position); } else { // Otherwise, we're in the one-pane layout and must swap frags... // Create fragment and give it an argument for the selected article ArticleFragment newFragment = new ArticleFragment(); Bundle args = new Bundle(); args.putInt(ArticleFragment.ARG_POSITION, position); newFragment.setArguments(args); FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); // Replace whatever is in the fragment_container view with this fragment, // and add the transaction to the back stack so the user can navigate back transaction.replace(R.id.fragment_container, newFragment); transaction.addToBackStack(null); // Commit the transaction transaction.commit(); } } }
Bundle args = new Bundle(); args.putString(ArticleFragment.ARG_POSITION, position+"");传递数据 newFragment.setArguments(args);在Fragment中,测试发现在transaction.commit()提交后,即Fragment显示后Fragment才执行onCreateView()函数,tv.setText(getArguments().getString(ArticleFragment.ARG_POSITION)); 使用传递的数据
而不是在ArticleFragment newFragment = new ArticleFragment()即Fragment被创建时执行onCreateView()函数
Fragment中的onCreate()函数也一样,但先执行onCreate()再执行onCreateView()
我们可以知道Activity重新创建时(比如横竖屏切换),会重新构建它所管理的Fragment,原先的Fragment的字段值将会全部丢失,但是通过Fragment.setArguments(Bundle bundle)方法设置的bundle会保留下来。所以尽量使用Fragment.setArguments(Bundle bundle)方式来传递参数