一起来聊聊Android基础之Fragment
一起来聊聊Android基础之Fragment
Fragment的使用非常广泛,是Android中最基础,最重要的概念之一,甚至被称为第五大组件。所以这篇文章就来聊聊Fragment,基本概念和背景什么的都先PASS了,关键是会灵活使用不是吗?
加载Fragment
静态加载Fragment
首先,定义一下Fragment文件:FooFragment.java
import android.support.v4.app.Fragment; public class FooFragment extends Fragment { // The onCreateView method is called when Fragment should create its View object hierarchy, // either dynamically or via XML layout inflation. @Override public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) { // Defines the xml file for the fragment return inflater.inflate(R.layout.fragment_foo, parent, false); } // This event is triggered soon after onCreateView(). // Any view setup should occur here. E.g., view lookups and attaching view listeners. @Override public void onViewCreated(View view, Bundle savedInstanceState) { // Setup any handles to view objects here // EditText etFoo = (EditText) view.findViewById(R.id.etFoo); } }
然后在要加载Fragment的Activity的布局文件中添加fragment标签:
动态加载Fragment
动态加载方式需要修改Activity布局文件:
<framelayout android:id="@+id/your_placeholder" android:layout_height="match_parent" android:layout_width="match_parent"> </framelayout>
然后通过如下代码进行添加:
// Begin the transaction FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); // Replace the contents of the container with the new fragment ft.replace(R.id.your_placeholder, new FooFragment()); // or ft.add(R.id.your_placeholder, new FooFragment()); // Complete the changes added above ft.commit();
注:replace方法就是remove()然后add()的合体。
还有hide方法用来隐藏fragment
添加Fragment的操作还是很简单的,一般动态加载使用的更多一些。
Fragment的生命周期
接下来讲重点,Fragment的生命周期。
Fragment具有自己的生命周期,但Fragment是依赖Activity而存在的,所以需要和Activity的生命周期一起来讨论。
先看一张Activity和Fragment生命周期的对比图:
Fragment的生命周期和Activity的生命周期基本是匹配的,但是有自己独特的回调方法:包括onAttach(),onCreatView(),onDestroyView()等。
下面以实际场景来看一下Fragment的生命周期。
场景一:采用静态加载Fragment,首次加载。依次回调如下方法:
Activity.onCreate->Fragment.onAttach->Fragment.onCreate->Fragment.onCreateView->Fragment.onViewCreated->Fragment.onActivityCreated->Fragment.onStart->Activity.onStart->Activity.onResume->Fragment.onResume
场景二:按HOME键,依次回调如下方法:
Fragment.onPause->Activity.onPause->Fragment.onStop->Activity.onStop
场景三:场景二之后,再次进入Activity,依次回调如下方法:
Activity.onRestart->Fragment.onStart->Activity.onStart->Activity.onResume->Fragment.onResume
场景四:退出Activity。依次回调如下方法:
Fragment.onPause->Activity.onPause->Fragment.onStop->Activity.onStop->Fragment.onDestroyView->Fragment.onDestroy->Fragment.onDetach->Activity->onDestroy
下面摘录一段来自codepath上的fragment示例代码:
public class SomeFragment extends Fragment { ThingsAdapter adapter; FragmentActivity listener; // This event fires 1st, before creation of fragment or any views // The onAttach method is called when the Fragment instance is associated with an Activity. // This does not mean the Activity is fully initialized. @Override public void onAttach(Context context) { super.onAttach(context); if (context instanceof Activity){ this.listener = (FragmentActivity) context; } } // This event fires 2nd, before views are created for the fragment // The onCreate method is called when the Fragment instance is being created, or re-created. // Use onCreate for any standard setup that does not require the activity to be fully created @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ArrayList things = new ArrayList(); adapter = new ThingsAdapter(getActivity(), things); } // The onCreateView method is called when Fragment should create its View object hierarchy, // either dynamically or via XML layout inflation. @Override public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_some, parent, false); } // This event is triggered soon after onCreateView(). // onViewCreated() is only called if the view returned from onCreateView() is non-null. // Any view setup should occur here. E.g., view lookups and attaching view listeners. @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); ListView lv = (ListView) view.findViewById(R.id.lvSome); lv.setAdapter(adapter); } // This method is called when the fragment is no longer connected to the Activity // Any references saved in onAttach should be nulled out here to prevent memory leaks. @Override public void onDetach() { super.onDetach(); this.listener = null; } // This method is called after the parent Activity's onCreate() method has completed. // Accessing the view hierarchy of the parent activity must be done in the onActivityCreated. // At this point, it is safe to search for activity View objects by their ID, for example. @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); } }
查询Fragment实例
查询Fragment实例有三种
- ID - FragmentManager.findFragmentById
public class MainActivity extends AppCompatActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState == null) { DemoFragment fragmentDemo = (DemoFragment) getSupportFragmentManager().findFragmentById(R.id.fragmentDemo); } } }Tag - FragmentManager.findFragmentByTag
public class MainActivity extends AppCompatActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState == null) { // Let's first dynamically add a fragment into a frame container getSupportFragmentManager().beginTransaction(). replace(R.id.flContainer, new DemoFragment(), "SOMETAG"). commit(); // Now later we can lookup the fragment by tag DemoFragment fragmentDemo = (DemoFragment) getSupportFragmentManager().findFragmentByTag("SOMETAG"); } } }Pager - PagerAdapter中的getRegisteredFragment
// TODO 待熟悉PagerAdapter再补充
Fragment通信
Fragment进行通信的方式主要有三种:
1.Bundle
首先通过构造fragment实例时将待传输的数据保存在Bundle中,然后调用Fragment的setArguments方法进行传递。
然后在Fragment的onCreate方法取出Bundle数据。具体实现看代码:
public class DemoFragment extends Fragment { // Creates a new fragment given an int and title // DemoFragment.newInstance(5, "Hello"); public static DemoFragment newInstance(int someInt, String someTitle) { DemoFragment fragmentDemo = new DemoFragment(); Bundle args = new Bundle(); args.putInt("someInt", someInt); args.putString("someTitle", someTitle); fragmentDemo.setArguments(args); return fragmentDemo; } } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // Get back arguments int SomeInt = getArguments().getInt("someInt", 0); String someTitle = getArguments().getString("someTitle", ""); } // Within the activity FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); DemoFragment fragmentDemo = DemoFragment.newInstance(5, "my title"); ft.replace(R.id.your_placeholder, fragmentDemo); ft.commit();
2.Fragment Methods
这个就比较直接了,先在Fragment中新建一个方法,然后在Activity中获取到该Fragment实例,最后直接调用方法即可。
public class DemoFragment extends Fragment { public void doSomething(String param) { // do something in fragment } } public class MainActivity extends AppCompatActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); DemoFragment fragmentDemo = (DemoFragment) getSupportFragmentManager().findFragmentById(R.id.fragmentDemo); fragmentDemo.doSomething("some param"); } }
3.Fragment Listener
设置一个listener接口,在Activity中实现该接口的方法,然后在Fragment中调用该方法,就可以实现方法回调,这也是程序开发中各个组件相互通信的常用方法。
public class MyListFragment extends Fragment { // ... // Define the listener of the interface type // listener will the activity instance containing fragment private OnItemSelectedListener listener; // Define the events that the fragment will use to communicate public interface OnItemSelectedListener { // This can be any number of events to be sent to the activity public void onRssItemSelected(String link); } // Store the listener (activity) that will have events fired once the fragment is attached @Override public void onAttach(Context context) { super.onAttach(context); if (context instanceof OnItemSelectedListener) { listener = (OnItemSelectedListener) context; } else { throw new ClassCastException(context.toString() + " must implement MyListFragment.OnItemSelectedListener"); } } // Now we can fire the event when the user selects something in the fragment public void onSomeClick(View v) { listener.onRssItemSelected("some link"); } } // Activity implements the fragment listener to handle events public class RssfeedActivity extends AppCompatActivity implements MyListFragment.OnItemSelectedListener { // Can be any fragment, `DetailFragment` is just an example DetailFragment fragment; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_rssfeed); // Get access to the detail view fragment by id fragment = (DetailFragment) getSupportFragmentManager() .findFragmentById(R.id.detailFragment); } // Now we can define the action to take in the activity when the fragment event fires // This is implementing the `OnItemSelectedListener` interface methods @Override public void onRssItemSelected(String link) { if (fragment != null && fragment.isInLayout()) { fragment.setText(link); } } }
管理Fragment的返回栈
通过FragmentManager可以对Fragment transaction进行管理,调用addToBackStack方法可以将fragment transaction进栈,从而按返回键时将销毁添加的fragment,而不是销毁activity。
与之相对应的是popBackStack方法,它会将栈中的fragment transaction出栈。
addToBackStack() popBackStack()
Fragment切换
Fragment之间的切换常和TabLayout,Fragment Navigation Drawer,ViewPager等控件进行搭配实现。
直接参照这两个实例练习一遍,就可以熟悉Fragment的基本使用了。
推荐阅读
-
Android基础之使用Fragment控制切换多个页面
-
Android基础之使用Fragment适应不同屏幕和分辨率(分享)
-
Android基础之Fragment与Activity交互详解
-
一起学Android之Fragment
-
Android基础之Fragment与Activity交互详解
-
Android基础之使用Fragment适应不同屏幕和分辨率(分享)
-
一起来聊聊Android基础之Fragment
-
android使用Navigation实现Fragment之间的跳转之一:基础使用
-
Python基础:一起来面向对象 (二) 之搜索引擎
-
Android温故知新之Fragment篇(一) Fragment生命周期