【问题标题】:How to check typed callback type inside Fragment.onAttach()如何检查 Fragment.onAttach() 中的类型化回调类型
【发布时间】:2018-03-26 12:44:44
【问题描述】:

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

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

我的抽象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;
    }
}

车辆列表片段:

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 class BusListFragment
    extends VehicleListFragment<Bus> {

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

车辆细节片段:

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 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 的每个子类创建一个自己的接口,该接口扩展 VehicleListFragment.Callback(就像在 VehicleDetailsFragment 的子类中一样),但它总是如下所示:

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

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

【问题讨论】:

    标签: java android android-fragments generics inheritance


    【解决方案1】:
    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.:对于 Inherited 类,你可以做得更通用:

    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>();
    

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

    【讨论】:

    • 哇!谢谢。我会试试这个。我只是不确定我现在完全理解你的答案。您是否注意到 BusListFragment 的 Callback 是 VehicleListFragment.Callback 而我无法获得参数化类型的 .class?
    • @user2661298 使用泛型作为具有自己类型的类型,同时用其他类型继承其他泛型,很难跟踪泛型 - 无法逐步调试。经验法则:尽可能跟踪您的实际课程,您可以随时确定实际课程类型和“转换保存”。
    • 您如何看待创建抽象方法 CallbackFragment.castCallback(Context context)、在 Callbackfragment.onAttach() 中调用它并在每个子类中实现它以获得正确的 Callback 或 ClassCastException?查看我对这个问题的编辑(在底部)stackoverflow.com/questions/46750211/…
    猜你喜欢
    • 1970-01-01
    • 2010-09-18
    • 2018-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多