Android Fragment 使用技巧


1. Fragment 使用时要有一个无参构造函数

如果没有无参构造函数,而是像按照普通类来使用,只创建有参构造函数,则会出现 android.support.v4.app.Fragment$InstantiationException 错误。

原因:Fragment 和 Activity 都是生命周期的组件,不能看做一般的类。如果非要使用有参构造函数,可能在使用的时候第一次传参没有问题,但是大概率在后面使用的时候出现问题。因为Fragment的什么周期依附在Activity中,如果Activity为null,那么Fragment肯定不能够正常使用了,比如手机屏幕的横竖屏切换导致Activity重建了。

至于为什么是这样的呢?看下Fragment初始化的源码,有这么一段:

/** * Create a new instance of a Fragment with the given class name. This is * the same as calling its empty constructor. * * @param context The calling context being used to instantiate the fragment. * This is currently just used to get its ClassLoader. * @param fname The class name of the fragment to instantiate. * @param args Bundle of arguments to supply to the fragment, which it * can retrieve with {@link #getArguments()}. May be null. * @return Returns a new fragment instance. * @throws InstantiationException If there is a failure in instantiating * the given fragment class. This is a runtime exception; it is not * normally expected to happen. */
public static Fragment instantiate(Context context, String fname, @Nullable Bundle args) { try { Class<?> clazz = sClassMap.get(fname); if (clazz == null) { // Class not found in the cache, see if it's real, and try to add it
            clazz = context.getClassLoader().loadClass(fname); sClassMap.put(fname, clazz); } Fragment f = (Fragment)clazz.newInstance(); if (args != null) { args.setClassLoader(f.getClass().getClassLoader()); f.mArguments = args; } return f; } catch (ClassNotFoundException e) { throw new InstantiationException("Unable to instantiate fragment " + fname + ": make sure class name exists, is public, and has an"
                + " empty constructor that is public", e); } catch (java.lang.InstantiationException e) { throw new InstantiationException("Unable to instantiate fragment " + fname + ": make sure class name exists, is public, and has an"
                + " empty constructor that is public", e); } catch (IllegalAccessException e) { throw new InstantiationException("Unable to instantiate fragment " + fname + ": make sure class name exists, is public, and has an"
                + " empty constructor that is public", e); } }

整个过程中,Fragment的创建其实也是利用了无参数的构造方法去实例化.但关键的是,它将Bundle传类新建的Fragment,这样旧的Fragment和新的Fragment就能拥有一样的Bundle,从而达到利用Bundle传递参数的目的. Android的SDK文档也给出来相关的说法:

2. 给 Fragment 传递参数

一定要使用 Bundle 方式传递参数,而不是通过重载构造函数传递参数。

public static VechileFrag newInstance(Vehicle vehicle, String userId, boolean isAdd) { VechileFrag mf = new VechileFrag(); Bundle args = new Bundle(); args.putString("userId", userId); args.putBoolean("isAdd", isAdd); args.putParcelable("vehicle", vehicle); mf.setArguments(args); return mf; } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Bundle args = getArguments(); if (args != null) { userId = args.getString("userId"); isAdd = args.getBoolean("isAdd"); vehicle = args.getParcelable("vehicle"); if (vehicle == null) { vehicle = new Vehicle(); } } } 

3. Fragment 与 Activity 通信

在 Fragment 中定义一个接口和要回调的方法, Activity实现Fragment接口,需要时回调 Fragment 方法。

public IVechile mIVechile;   public interface IVechile {   public void submitCarSuccess(String carId, String plateNo);   }   @Override   public void onAttach(Activity activity) {     fueltypes = FuelType.getList(activity);     try {       mIVechile = (IVechile) activity;     }     catch (Exception e) {     // TODO: handle exception
     }   } }

 

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM