java - 如何检查 Fragment.onAttach() 内的类型化回调类型

标签 java android android-fragments generics inheritance

我正在尝试使用类型化回调实现抽象 fragment ,以便在多个子类中使用它。

如何检查 Context 是否是适当类的实例?

我的abstact CallbackFragment代码:

public abstract class CallbackFragment<C> extends Fragment {

    protected C mCallback;

    public CallbackFragment() {
    }

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

        //just in case
        if(context == null)
            throw new NullPointerException();

        try {
            mCallback = (C) context; //this line not seems to throw any exception
        } catch (ClassCastException exception) {
            throw new RuntimeException(context.toString() + " must implement Callbacks");
        }
    }

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

车辆列表 fragment :

public abstract class VehicleListFragment<T extends Vehicle>
        extends CallbackFragment<VehicleListFragment.Callback<T>> {

    //callback for any list of any vehicle
    public interface Callback<T extends Vehicle> {
        void onListItemSelected(T selectedItem);
    }

    //common code for list of any vehicle
    public VehicleListFragment() {
    }
}

公共(public)汽车、卡车、船、自行车,无论什么列表 fragment :

public class BusListFragment
    extends VehicleListFragment<Bus> {

    //code specific for list of bus
    public BusListFragment() {
    }
}

车辆详细信息 fragment :

public abstract class VehicleDetailsFragment<T extends Vehicle, C extends VehicleDetailsFragment.Callback<T>>
        extends CallbackFragment<C> {

    //common methods of callback for any vehicle
    public interface Callback<T> {
        void onVehicleEdited(T editeItem);
    }

    //common code for any vehicle
    public VehicleDetailsFragment() {
    }
}

公共(public)汽车、卡车、船、自行车,无论细节 fragment :

public class BusDetailsFragment
        extends VehicleDetailsFragment<Bus, BusDetailsFragment.Callback> {

    //specific for Bus methods
    public interface Callback
            extends VehicleDetailsFragment.Callback<Bus> {
        void onSomethingSpecificForBusHappened(Bus bus);
    }

    //code specific for Bus
    public BusDetailsFragment() {
    }
}
<小时/>

我尝试为 CallbackFragment 添加一个抽象方法来获取回调类:

public abstract class CallbackFragment<C> extends Fragment {

    ...

    @NonNull
    protected abstract Class<C> getCallbackClass();

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

        //now checking instanceof like this
        if(!getCallbackClass().isAssignableFrom(context.getClass())){
            throw new RuntimeException(context.toString() + " must implement Callbacks");
        }
    }
}

使用 BusDetailsFragment 一切看起来都正常:

public class BusDetailsFragment
        extends VehicleDetailsFragment<Bus, BusDetailsFragment.Callback> {

    @NonNull
    @Override
    protected Class<Callback> getCallbackClass() {
        return Callback.class;
    }

    ...
}

但不适用于 BusListFragment:

public class BusListFragment
        extends VehicleListFragment<Bus> {

    @NonNull
    @Override
    protected Class<Callback<Bus>> getCallbackClass() {
        /**
         * I'm not seeing any option here
         *
         * mCallback - is null yet. So, there is no way to use mCallback.getClass()
         *
         * Callback<Bus>.class - Cannot select from parameterized type
         */
        //return mCallback.getClass();
        //return Callback<Bus>.class;
    }

    ...
}
<小时/>

当然,我可以为扩展 VehicleListFragment.Callback 的 VehicleListFragment 的每个子类创建一个自己的接口(interface)(就像在 VehicleDetailsFragment 的子类中一样),但它始终如下所示:

public interface Callback
        extends VehicleListFragment.Callback<Bus> {
    //nothing more here
}

这对我来说似乎不是最好的选择。 也许还有其他解决方案吗?请分享您的想法。任何帮助将不胜感激。

最佳答案

mCallback = (C) context; //this line not seems to throw any exception

这个调用永远不会抛出异常。在运行时期间,您的 C 被替换为 Object(称为类型删除) - 并且一切都是 Object。因此,此时您可以分配任何内容。

要在需要的地方出现异常(或至少确定错误),可以使用:

public abstract class CallbackFragment<C> extends Fragment {

    protected C mCallback;
    protected Class<C> callbackClass;

    public CallbackFragment(Class<C> clazz) {
       this.callbackClass = clazz;
    }

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

        //just in case
        if(context == null)
            throw new NullPointerException();

        if (clazz.isAssignableFrom(context.getClass()){
            mCallback = (C) context;  
        }else{
           //oops
        }
    }
}

ofc。那么你的 FragmentCreation 将从

 CallbackFragment<Something> fragment = new CallbackFragment<Something>();

CallbackFragment<Something> fragment = new CallbackFragment<Something>(Something.class);

它有点不同,但允许您随时跟踪实际类型,绕过类型删除。

ps.:对于继承类,您可以做得更通用:

public abstract class CallbackFragment<C> extends Fragment {
    protected Class<C> callbackClass;

    public CallbackFragment() {
          this.callbackClass = (Class<C>) ((ParameterizedType) getClass()
                        .getGenericSuperclass()).getActualTypeArguments()[0];;
     }
}

public class CallbackFragmentOfSomething extends <CallbackFragment<Something>>{

}

如果您的实际类不是由于继承而定义的,而是“动态”定义的,则此操作只会失败:

CallbackFragment<Something> fragment = new CallbackFragment<Something>();

(一切未经测试/没有复制粘贴,但应该有点准确)

关于java - 如何检查 Fragment.onAttach() 内的类型化回调类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46745858/

相关文章:

堆内存超过阈值后的 Java 垃圾收集

java - HashMap 错误 : javax. el.PropertyNotFoundException

java - 尝试在将文档接受到集合 Cloud Firestore 之前添加检查

android - 如何检查此人在哪里使用 gps。安卓

java - Android fragment 和 baseadapter 之间的通信

android - 验证在哪个 Activity 中附加了 fragment

java - Spring API Gateway 中的 Swagger Api 文档

用于在 Windows 上获取当前打开/正在执行的应用程序的 Java 程序

android - 适用于 SDK 平台 26 的 AppCompat 和支持库版本

android - 在 Android 中使用 Fragments 而不是 Views 有什么好处?