Android Fragment


珍惜作者劳动成果 转载请注明出处

什么是Fragment

  1. Android在3.0系统的时候,开始为电视机提供系统,电视机的屏幕尺寸要比现在的移动设备大很多,Google的开发人员希望在开发的过程中,能够将整个屏幕划分成多个小的部分,并且每一个小部分可以单独开发,实现界面以及功能,最终这些小的部分又需要组合在一起,那么,最终设计出来一个称作Fragment的内容。
  2. Fragment 是一个能够显示界面以及有自己独立的代码逻辑的组件,Fragment可以在布局中直接引用

Fragment的作用

  1. 简化重复的开发工作,将内容与工程进行整合,最终提供功能的重用性;
  2. 提高内聚,减少耦合程度;
  3. Fragment 用于进行布局界面的切分与优化,减少布局的重复,提高开发的效率。

Fragment开发流程

  1. Activity 必须 继承 FragmentActivity
  2. 创建Fragment子类: extends Fragment
  3. !!! 创建一个 无参的构造方法
  4. 重写 onCreateView 方法,设置Fragment显示的内容
  5. 创建 res/layout 中的布局资源,onCreateView加载布局,最终显示;
  6. 在不同的界面中就可以使用Fragment了。
    使用Fragment 来组装Activity,可以像控件一样使用

Fragment事务

  1. add(int containerID, Fragment) 添加Fragment到容器
  2. replace(int containerId, Fragment) 将container中,原有的Fragment 自动 remove, 之后,再添加指定的Fragment.
  3. remove(Fragment) 删除 Fragment
  4. commit() 使事务的操作生效。

注意:
1. 一个事务,只能够进行一次 commit() 提交;
2. 类似于 “高考” 一年一次,通常都是一个方法中,开启事务,在这个方法,提交事务;就结束了,不要将事务建成成员变量的方式;

Fragment生命周期

  1. Fragment生命周期 和 Activity的生命周期相似:
  2. 因为Fragment依赖于Activity显示,那么当 Activity发生生命周期变化的时候,Fragment同样发生相同的变化。包括: onCreate, onStart, onResume, onPause, onStop, onDestroy, Fragment 还有一些生命周期。
  3. onAttach, onCreate, onCreateView, onActivityCreated, onStart, onResume, onPause, onStop, onDestroyView, onDestroy, onDetach
生命周期方法描述
onAttachActivity 加载Fragment 调用
onCreateActivity 继续调用 onCreate ,初始化一次的数据,在这里调用
onCreateViewFragment 要显示的时候, 返回显示的内容
onActivityCreated最后可以使 Fragment 进行初始化的最后一步,之后进入显示
onStart等同于 Activity onStart
onResumeActivity onResume : 加载数据,加载多次
onPauseActivity onPause
onStopActivity onStop
onDestroyViewFragment销毁界面,不再显示时调用
onDestroy销毁,等同于 Activity onDestory
onDetachActivity 将 Fragment 移除的时候,调用。

与Activity生命周期对比

这里写图片描述

Fragment的查找

每一个fragment在添加\replace的时候,都可以使用三个参数的方法,来给Fragment设置一个名称,tag;

Fragment的回退栈

Fragment的回退栈,是一种记录,记录事务的操作,如果事务被添加到回退栈,那么一般情况,当返回的时候,会对事务的操作进行一个逆转,从而恢复事务执行之前的内容。

回退栈原理

  1. 当事务被添加到回退栈的时候,FragmentManager 就会将事务的操作,添加到回退中,作为一个记录,存在;
  2. 当返回的时候,查找回退栈,如果有内容,那么对记录进行反转的操作。如 add 翻转为 remove , replace 调整为 remove 和 add;从而还原事务执行之前的状态;
  3. FragmentManager.popBackStack() 弹出回退栈,相当于后退键的操作

FragmentManager的Fragment管理

  1. findFragmentById(int id) 从XML布局中查找相应的Fragment;
  2. findFragmentByTag(String tag); 通常 xml中可以指定id, 也可以指定 tag ,根据tag去查找;tag常用场景大部分针对的是代码动态添加Fragment的情况,给Fragment一个Tag, 再后续查找的时候,可以找到了。
  3. 如果 在同一个代码中,添加Fragment并且指定Tag,这个时候事务执行可能有一定的时间,如果进行查找,可能找不到,因为还没有来得及添加到 FragmentManager中。

Fragment与Activity之间的交互

  1. Fragment 创建时接收参数;
  2. Fragment在运行的时候,Activity进行Fragment特定方法的调用;
  3. Fragment调用Activity特定的方法; onAttach(Activity) onDetach(Activity)

创建Fragment并且传参

在事务处理之前,使用Fragment.setArguments(Bundle args)

横竖屏

这里写图片描述

示例代码

普通使用

public class MainActivity extends AppCompatActivity implements RadioGroup.OnCheckedChangeListener {

    private HomeFragment mHomeFragment;
    private DmFragment mDmFragment;
    private SearchFragment mSearchFragment;
    private PersonalFragment mPersonalFragment;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Fragment的管理,检查Fragment是否已经存在

        FragmentManager manager = getSupportFragmentManager();

        Fragment f = manager.findFragmentByTag("home");



        // 主流的 底部Tab切换页面的设计方式,就是 中间一个FrameLayout,
        // 底部 RadioGroup,切换时,替换FrameLayout中的Fragment

        RadioGroup group = (RadioGroup) findViewById(R.id.main_tab_bar);
        if (group != null) {
            group.setOnCheckedChangeListener(this);
        }

        // 1. 创建所有的Fragment对象,便于切换的时候使用
        if(f == null) {
            mHomeFragment = new HomeFragment();
        }else{
            mHomeFragment = (HomeFragment) f;
        }

        f = manager.findFragmentByTag("dm");
        if(f == null) {
            mDmFragment = new DmFragment();
        }else{
            mDmFragment = (DmFragment) f;
        }


        mSearchFragment = new SearchFragment();
        mPersonalFragment = new PersonalFragment();


        // 2. 每一个Fragment可以通过两种方式来添加到Activity
        //    1) 使用<fragment> 标签直接添加到Activity;
        //    2) 使用代码来添加Fragment,使用 FragmentManager, FragmentTransaction
        System.out.println("MyLifeCycle MainActivity.onCreate start");

        //FragmentManager manager = getSupportFragmentManager();
        //
         内部添加、删除、替换Fragment,必须要使用 FragmentManager.beginTransaction() 来开启
        //FragmentTransaction tx = manager.beginTransaction();
        //
         事务每次操作之前必须重新开启,不允许使用成员变量的方式
        //tx.add(R.id.fragment_container, mHomeFragment);
        //
        //tx.commit();


        group.check(R.id.main_tab_item_home);

        System.out.println("MyLifeCycle MainActivity.onCreate end");
    }


    @Override
    public void onCheckedChanged(RadioGroup group, int checkedId) {

        FragmentManager manager = getSupportFragmentManager();
        FragmentTransaction tx = manager.beginTransaction();

        // 进行代码切换Fragment
        switch (checkedId) {
            case R.id.main_tab_item_home:
                // 关于替换操作,如果之前有Fragment,那么删除,之后在添加新的
                //             如果没有,那么直接添加
                //tx.replace(R.id.fragment_container, mHomeFragment);
                tx.replace(R.id.fragment_container, mHomeFragment, "home");
                break;
            case R.id.main_tab_item_dm:
                tx.replace(R.id.fragment_container, mDmFragment, "dm");
                break;
            case R.id.main_tab_item_search:
                tx.replace(R.id.fragment_container, mSearchFragment, "search");
                break;
            case R.id.main_tab_item_personal:
                tx.replace(R.id.fragment_container, mPersonalFragment, "personal");
                break;
        }

        tx.commit();
    }
}

Fragment

public class HomeFragment extends Fragment {


    public HomeFragment() {
        // Required empty public constructor
    }



    /**
     * 当Fragment 创建之后,交给Activity的时候,自动回调
     * 这个方法调用的时候Fragment还没有布局,还没有显示
     * 通常这个方法,用于设置Fragment接口回调;
     * @param context
     */
    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        System.out.println("MyLifeCycle HomeFragment.onAttach");
    }

    /**
     * 创建期间初始化数据
     * @param savedInstanceState
     */
    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        System.out.println("MyLifeCycle HomeFragment.onCreate");
    }

    /**
     * 当Fragment 需要向Activity添加界面,或者是需要显示的时候
     * @param inflater
     * @param container
     * @param savedInstanceState
     * @return
     */
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        System.out.println("MyLifeCycle HomeFragment.onCreateView");

        // Inflate the layout for this fragment
        View ret = inflater.inflate(R.layout.fragment_home, container, false);


        return ret;
    }

    /**
     * 1. 如果当前Fragment 通过 <fragment>添加到Activity的,
     *    当Activity onCreate方法执行完返回之后,自动调用
     * 2. 如果是代码方式添加到Activity的,那么 onCreateView 之后,会自动调用这个方法
     * @param savedInstanceState
     */
    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        System.out.println("MyLifeCycle HomeFragment.onActivityCreated");
    }


    /**
     * Fragment 和 Activity 没有任何关系了
     * 也是最后一个声明周期方法
     * ! 当使用 replace() 时,旧的Fragment会进入到 Detach, 但Activity还在;
     */
    @Override
    public void onDetach() {
        super.onDetach();
        System.out.println("MyLifeCycle HomeFragment.onDetach");
    }
}

横竖屏切换

MainActivity.java


public class MainActivity extends AppCompatActivity implements NewsListFragment.OnNewsSelectedListener{

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public void onNewsSelected(Bundle bundle) {
        Log.d("onNewsSelected", "bundle = " + bundle);

        // 监测横屏还是竖屏

        // 查找横屏特有的Fragment,来区分

        FragmentManager manager = getSupportFragmentManager();
        Fragment fragment = manager.findFragmentById(R.id.fragment_detail);

        if(fragment != null && fragment.isVisible()){
            // 横屏
            DetailFragment detailFragment = (DetailFragment) fragment;
            detailFragment.setDetailTitle(bundle.toString());
        }else{
            // 竖屏
            Intent intent = new Intent(this, DetailActivity.class);
            // 把参数传递给Activity,然后Activity再传给Fragment
            intent.putExtras(bundle);
            startActivity(intent);
        }


        //if(fragment != null){
        //    Toast.makeText(MainActivity.this, "fragment " + fragment.isVisible(), Toast.LENGTH_SHORT).show();
        //
        //    // 如果Fragment存在,并且显示的状态,代表横屏情况
        //    if(fragment.isVisible()) {
        //        DetailFragment detailFragment = (DetailFragment) fragment;
        //        detailFragment.setDetailTitle(bundle.toString());
        //    }
        //
        //}else{
        //    Toast.makeText(MainActivity.this, "fragment == null", Toast.LENGTH_SHORT).show();
        //}

    }
}

DetailActivity.java


public class DetailActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_detail);

        // 如果 savedInstanceState == null 代表第一次创建,否则代表屏幕发生过旋转

        if(savedInstanceState == null){
            // 添加Fragment

            Bundle extras = getIntent().getExtras();

            if(extras != null){

                DetailFragment detailFragment = new DetailFragment();

                // Fragment内部传递参数,使用Bundle作为参数,调用 setArguments(Bundle)
                detailFragment.setArguments(extras);

                FragmentManager manager = getSupportFragmentManager();
                FragmentTransaction tx = manager.beginTransaction();

                tx.replace(R.id.detail_fragment_container, detailFragment);

                // 在事务提交之后,会进入到 fragment的创建生命周期;
                // 不能够在这个语句执行的附近进行UI的设置;
                tx.commit();

            }

        }

    }
}

NewsListFragment.java

public class NewsListFragment extends Fragment implements AdapterView.OnItemClickListener {

    /**
     * Fragment定义的接口,用于给Activity传递一个ListView点击的事件调用
     */
    public interface OnNewsSelectedListener{
        void onNewsSelected(Bundle bundle);
    }

    private OnNewsSelectedListener mOnNewsSelectedListener;

    public NewsListFragment() {
        // Required empty public constructor
    }

    public void setOnNewsSelectedListener(OnNewsSelectedListener onNewsSelectedListener) {
        mOnNewsSelectedListener = onNewsSelectedListener;
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);

        // 内部设置 接口回调
        if(context instanceof OnNewsSelectedListener){
            mOnNewsSelectedListener = (OnNewsSelectedListener) context;
        }else{
            throw new IllegalArgumentException("Activity must implements OnNewsSelectedListener");
        }
    }

    @Override
    public void onDetach() {
        mOnNewsSelectedListener = null;
        super.onDetach();
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View ret = inflater.inflate(R.layout.fragment_news_list, container, false);

        ListView listView = (ListView) ret.findViewById(R.id.news_list);
        if (listView != null) {

            ArrayList<String> data = new ArrayList<>();

            for (int i = 0; i < 100; i++) {
                data.add("News " + i);
            }

            ArrayAdapter<String> adapter = new ArrayAdapter<String>(
                    getContext(),
                    android.R.layout.simple_list_item_1,
                    data
            );

            listView.setAdapter(adapter);
            // 设置点击
            listView.setOnItemClickListener(this);

        }

        return ret;
    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
        if(mOnNewsSelectedListener != null){
            Bundle bundle = new Bundle();
            bundle.putInt("position", position);
            bundle.putLong("id", id);
            mOnNewsSelectedListener.onNewsSelected(bundle);
        }
    }
}

DetailFragment.java

public class DetailFragment extends Fragment {

    private TextView mTextTitle;

    public DetailFragment() {
        // Required empty public constructor
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View ret = inflater.inflate(R.layout.fragment_detail, container, false);

        mTextTitle = (TextView) ret.findViewById(R.id.detail_title);

        // 可以通过 getArguments() 来获取初始化的参数
        Bundle arguments = getArguments();

        if(arguments != null){
            long id = arguments.getLong("id");
            mTextTitle.setText("id = " + id);
        }

        return ret;
    }

    public void setDetailTitle(String title){
        mTextTitle.setText(title);
    }

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值