基础知识

Fragment,简称碎片,是Android 3.0(API 11)提出的,为了兼容低版本,support-v4库中也开发了一套Fragment API,最低兼容Android 1.6。

过去support-v4库是一个jar包,24.2.0版本开始,将support-v4库模块化为多个jar包,包含:support-fragment, support-ui, support-media-compat等,这么做是为了减少APK包大小,你需要用哪个模块就引入哪个模块。

如果想引入整个support-v4库,则compile ‘com.android.support:support-v4:24.2.1’,如果只想引入support-fragment库,则com.android.support:support-fragment:24.2.1。

不管是v4支持包还是v7支持包都是为了将一些较为先进的app设计理念向后兼容,一般来说,v4支持包的版本和v7支持包的版本与编译sdk或者目标sdk一致,比如我的编译版本(即API level)是27,那么最好使用版本号以27开头的v4或v7包.

推荐使用支持包中的fragment,兼容性更强.

fragment的特点与优势

特点

优势

fragment核心的API

fragment的生命周期

Fragment生命周期

fragment的基本使用

设置参数和解析参数

activity可以通过fragment的setArguments()对关联的fragment设置参数,可以在onAttach()中获得参数,即getArgument()获得参数,getArgument()返回一个Bundle,解析这个Bundle即可.

It is strongly recommended that subclasses do not have other constructors with parameters, since these constructors will not be called when the fragment is re-instantiated.

如果在创建Fragment时要传入参数,必须要通过setArguments(Bundle bundle)方式添加,而不建议通过为Fragment添加带参数的构造函数,因为通过setArguments()方式添加,在由于内存紧张导致Fragment被系统杀掉并恢复(re-instantiate)时能保留这些数据

fragment的容器

Fragment有很多可以复写的方法,其中最常用的就是onCreateView(),该方法返回Fragment的UI布局,需要注意的是inflate()的第三个参数是false,因为在Fragment内部实现中,会把该布局添加到container中,如果设为true,那么就会重复做两次添加,则会抛如下异常:

Caused by: java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.

fragment有两种添加方式

运行时添加需要一个容器,这个容器一般是framelayout,至于为什么用framelayout我就不知道了.

代码

fragment

package me.tinuv.fragmenttest;

import android.content.Context;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

public class MyFragment extends Fragment {
    private MainActivity mActivity;


    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        mActivity = (MainActivity) context;
        Log.e("Tinuv", getArguments().getString("key"));
    }

    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_my, container, false);
    }

    public static MyFragment newInstance(Bundle param) {
        MyFragment fragment = new MyFragment();
        fragment.setArguments(param);
        return fragment;
    }
}

activity

package me.tinuv.fragmenttest;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Bundle args = new Bundle();
        args.putString("key", "hello");
        getSupportFragmentManager().beginTransaction()
                .add(R.id.fragment_container, MyFragment.newInstance(args), "f")
                .commit();
    }
}

FragmentManager的常用API

我也不知道为什么,总是没法获得Fragment,总是空指针

tag可以为null或者相对应的tag,flags只有0和1(POP_BACK_STACK_INCLUSIVE)两种情况 如果tag为null,flags为0时,弹出回退栈中最上层的那个fragment。 如果tag为null ,flags为1时,弹出回退栈中所有fragment。 如果tag不为null,那就会找到这个tag所对应的fragment,flags为0时,弹出该 fragment以上的Fragment,如果是1,弹出该fragment(包括该fragment)以 上的fragment。 popBackStackImmediate相关的方法与上面逻辑是一样的与上面不同的是,在调用的时候会立即执行弹出。

FragmentTransaction的常用API

add() 和 replace() 运用总结:

在项目的使用中,通常习惯使用add()加载,add方式视图不会重建,会被保存起来,而replace()每次都会remove掉前面的视图,而replace方式的回退,旧的视图每一次都会重建,在用户体验上不好。

add()和replace()的使用,不能够混合使用,在混合使用的情况下,会导致回退栈混乱,导致的原因是在回退过程中记录的角标存在问题

FragmentTransaction遇到的一个错位.

java.lang.IllegalStateException: commit already called

这个错误是将FragmentTransaction作为了一个变量
如:

    FragmenTransaction ft = getSupportFragmentManager().beginTransaction();
    ft.add(fragment)
      .commit();
      
    ft.hide(fragment)
      .commit();

就会报这个错误

只要每次commit()之前都beginTransaction()就好了

    getSupportFragmentManager().beginTransaction()
        .add(fragment)
        .commit();
      
    getSupportFragmentManager().beginTransaction()
        .hide(fragment)
        .commit();

就不会报错了

🌹💗正文结束💗🌹