android fragmentargs详解

今天在看网页的时候,以外的发现了fragmentargs这个注解框架,而最近也在看相关的一些注解框架的知识,所以看起来很快,大概也知道了其中的原理。


一、fragmentargs配置


1.在project中的build.gradle中的dependencies添加这行代码:

classpath'com.neenbedankt.gradle.plugins:android-apt:1.8'。


2.在modlue中的build.gradle中添加这行代码:

applyplugin:'android-apt'


3.在modlue中的build.gradle中的dependencies添加这行代码:

compile 'com.hannesdorfmann.fragmentargs:annotation:3.0.2'
apt 'com.hannesdorfmann.fragmentargs:processor:3.0.2'

二.fragment代码编写


1.使用@FragmentWithArgs来注解你的fragment类。

2.使用@Args来注解你的变量,但是这个变量必须是公共的,也就是不能是private或者procted的;如果你需要把变量设置为私有的,也有办法,也就是为你的私有变量设置一个setXXX方法。

3.在Fragments onCreate(Bundle)方法中调用FragmentArgs.inject(this);方法,告诉Fragment去读取标注的参数然后进行设置。

4.android studio不想eclipse那样,会进行自动编译,所以当你的fagment写好后,需要先进行make下,才能使用接下来需要用到的xxxBuider类。

看一个例子:
import com.hannesdorfmann.fragmentargs.FragmentArgs;
import com.hannesdorfmann.fragmentargs.annotation.FragmentWithArgs;
import com.hannesdorfmann.fragmentargs.annotation.Arg;

@FragmentWithArgs
public class MyFragment extends Fragment {

    @Arg
    int id;

    @Arg
    String title; // private fields requires a setter method

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        FragmentArgs.inject(this); // read @Arg fields
    }

    @Override
    public View onCreateView(LayoutInflater inflater, 
            ViewGroup container, Bundle savedInstanceState) {

            Toast.makeText(getActivity(), "Hello " + title,
                    Toast.LENGTH_SHORT).show();

            return null;
    }

    // Setter method for private field
    public void setTitle(String title) {
        this.title = title;
    }

}
使用方式:
public class MyActivity extends Activity {

    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);

        int id = 123;
        String title = "test";

        // Using the generated Builder
        Fragment fragment = 
            new MyFragmentBuilder(id, title)
            .build();


        // Fragment Transaction
        getFragmentManager()
            .beginTransaction()
            .replace(R.id.container, fragment)
            .commit();

    }

}
没错,就是这么简单。其中的MyFragmentBuilder类,就是我们make时生成的,你可以看看其中的代码,就知道它是干嘛的了:
public final class MyFragmentBuilder {

  private final Bundle mArguments = new Bundle();

  public MyFragmentBuilder(int id, @NonNull String title) {

    mArguments.putInt("id", id);

    mArguments.putString("title", title);
  }

  @NonNull
  public static MyFragment newMyFragment(int id, @NonNull String title) {
    return new MyFragmentBuilder(id, title).build();
  }

  public static final void injectArguments(@NonNull MyFragment fragment) {
    Bundle args = fragment.getArguments();
    if (args == null) {
      throw new IllegalStateException("No arguments set. Have you setup this Fragment with the corresponding FragmentArgs Builder? ");
    }

    if (!args.containsKey("id")) {
      throw new IllegalStateException("required argument id is not set");
    }
    fragment.id = args.getInt("id");

    if (!args.containsKey("title")) {
      throw new IllegalStateException("required argument title is not set");
    }
    fragment.setTitle( args.getString("title") );
  }

  @NonNull
  public MyFragment build() {
    MyFragment fragment = new MyFragment();
    fragment.setArguments(mArguments);
    return fragment;
  }

  @NonNull
  public <F extends MyFragment> F build(@NonNull F fragment) {
    fragment.setArguments(mArguments);
    return fragment;
  }
}

MyFragmentBuilder类的实现只提供了两个方法:

public MyFragmentBuilder(int id, @NonNull String title) {

    mArguments.putInt("id", id);

    mArguments.putString("title", title);
  }

  @NonNull
  public static MyFragment newMyFragment(int id, @NonNull String title) {
    return new MyFragmentBuilder(id, title).build();
  }

三、高级用法


 

3.1 设置被标注为@Arg的变量为可选项(required = false)

@FragmentWithArgs
public class MyOptionalFragment extends Fragment {

    @Arg
    int id;

    @Arg
    String title;

    @Arg(required = false) 
    String additionalText;

    @Arg(required = false)
    float factor;

    @Arg(required = false)
    int mFeatureId;

    @Override
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        FragmentArgs.inject(this); // read @Arg fields
    }

}
使用:
public class MyActivity extends Activity {

    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);

        int id = 123;
        String title = "test";

        // Using the generated Builder
        Fragment fragment = 
            new MyOptionalFragmentBuilder(id, title) // required args
            .additionalText("foo")  // Optional arg
            .factor(1.2f)           // Optional arg
            .featureId(42)          // Optional arg
            .build();


        // Fragment Transaction
        getFragmentManager()
            .beginTransaction()
            .replace(R.id.container, fragment)
            .commit();
    }

}
我们看到additionalText()和factor()、featureId()方法都可写可不写,因为MyOptionalFragmentBuilder把这个参数设置成了可选:
public final class MyOptionalFragmentBuilder {

  private final Bundle mArguments = new Bundle();

  public MyOptionalFragmentBuilder(int id, @NonNull String title) {

    mArguments.putInt("id", id);

    mArguments.putString("title", title);
  }

  @NonNull
  public static MyOptionalFragment newMyOptionalFragment(int id, @NonNull String title) {
    return new MyOptionalFragmentBuilder(id, title).build();
  }

  public MyOptionalFragmentBuilder additionalText(@NonNull String additionalText) {

    mArguments.putString("additionalText", additionalText);
    return this;
  }

  public MyOptionalFragmentBuilder factor(float factor) {

    mArguments.putFloat("factor", factor);
    return this;
  }

  public MyOptionalFragmentBuilder featureId(int featureId) {

    mArguments.putInt("featureId", featureId);
    return this;
  }

  public static final void injectArguments(@NonNull MyOptionalFragment fragment) {
    Bundle args = fragment.getArguments();
    if (args == null) {
      throw new IllegalStateException("No arguments set. Have you setup this Fragment with the corresponding FragmentArgs Builder? ");
    }

    if (args != null && args.containsKey("featureId")) {
      fragment.mFeatureId = args.getInt("featureId");
    }

    if (args != null && args.containsKey("additionalText")) {
      fragment.additionalText = args.getString("additionalText");
    }

    if (!args.containsKey("id")) {
      throw new IllegalStateException("required argument id is not set");
    }
    fragment.id = args.getInt("id");

    if (!args.containsKey("title")) {
      throw new IllegalStateException("required argument title is not set");
    }
    fragment.title = args.getString("title");

    if (args != null && args.containsKey("factor")) {
      fragment.factor = args.getFloat("factor");
    }
  }

  @NonNull
  public MyOptionalFragment build() {
    MyOptionalFragment fragment = new MyOptionalFragment();
    fragment.setArguments(mArguments);
    return fragment;
  }

  @NonNull
  public <F extends MyOptionalFragment> F build(@NonNull F fragment) {
    fragment.setArguments(mArguments);
    return fragment;
  }
}

2.FragmentArgs支持继承和抽象

 
FragmentArgs.inject(this);可放在BaseFragment中,它具有可继承性,在子类中将可以不写。

public class BaseFragment extends Fragment {

    @Override
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
        FragmentArgs.inject(this); // read @Arg fields
    }
}
在将来,当你有一个Fragment中的变量没有使用@Arg标注,但是你想要在子类中使用它时,你可以使用@FragmentArgsInherited来进行标注:
public class A extends Fragment {

  @Arg int a;
  @Arg String foo;

}

@FragmentArgsInherited
public class B extends A {

  // Arguments will be taken from super class


   public View onCreateView(LayoutInflater inflater, ViewGroup container,
               Bundle savedInstanceState) {

      // Here you can simply access the inherited fields from super class
   }
}
 
当你在子类中,不想使用父类中标注的参数时,你可以使用@FragmentWithArgs(inherited = false)
 
 
@FragmentWithArgs(inherited = false)
public class C extends A {

   @Arg int c;

}

3.fragmentargs在使用bundle传参时,支持大多数的结构体数据。

当你想要支持bundle不支持的结构体传参时,需要指定你的ArgsBundler参数类型,例如:

public class DateArgsBundler implements ArgsBundler<Date>{

    @Override public void put(String key, Date value, Bundle bundle) {

        bundle.putLong(key, value.getTime());
    }

    @Override public Date get(String key, Bundle bundle) {

        long timestamp = bundle.getLong(key);
        return new Date(timestamp);
    }

}

public class MyFragment extends Fragment {

    @Arg ( bundler = DateArgsBundler.class )
    Date date;

}
// add 2016-08-25
最近在编译的时候发现老是包了一个警告,类似于:
Error:(51, 22) 警告: FragBean will be stored as Serializable。。。
原因就是:FragBean没有继承于ArgsBundler,但是实现了Serializable接口,所以程序也还是可以运行,只是这个警告一直看着不爽。
解决办法就是让FragBean继承于ArgsBundler就可以了。
public class FragmentBeanArgsBuilder implements ArgsBundler<FragmentBean> {

    @Override
    public void put(String key, FragmentBean value, Bundle bundle) {
        bundle.putSerializable(key, value);
    }

    @Override
    public FragmentBean get(String key, Bundle bundle) {
        return (FragmentBean) bundle.getSerializable(key);
    }
}
然后在使用的地方添加:
@Arg(bundler = FragmentBeanArgsBuilder.class)
public FragmentBean fragBean;
然后就搞定了!
 
好了,写了这么多,其实基本都是从官网翻译过来的,本人英语水平有限,如果有看不懂的,或者想了解更多,请参照官网的。
https://github.com/sockeqwe/fragmentargs

附上demo:http://download.csdn.net/detail/fwt336/9598941

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值