今天在看网页的时候,以外的发现了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.youkuaiyun.com/detail/fwt336/9598941