Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use ViewHolder as InnerClass of a Adapter #20

Closed
zhexian opened this issue Jan 13, 2016 · 8 comments
Closed

Use ViewHolder as InnerClass of a Adapter #20

zhexian opened this issue Jan 13, 2016 · 8 comments

Comments

@zhexian
Copy link

zhexian commented Jan 13, 2016

some time,we need the ViewHolder to be a innerClass of a Adapter ,incase to share the variable of it。
so here is the code we modified to support this feature。it both support single ViewHolder class or as innerClass in Adapter。

AdapterHelper.class

<T extends EfficientViewHolder> EfficientViewHolder generateViewHolder(View v,
                                                                       Class<T> viewHolderClass, EfficientRecyclerAdapter adapter) {
    Constructor<?>[] constructors = viewHolderClass.getDeclaredConstructors();

    if (constructors == null)
        return null;

    for (Constructor<?> constructor : constructors) {
        Class<?>[] parameterTypes = constructor.getParameterTypes();
        if (parameterTypes == null)
            continue;

        try {
            if (parameterTypes.length == 1 && parameterTypes[0].isAssignableFrom(View.class)) {
                Object viewHolder = constructor.newInstance(v);
                return (EfficientViewHolder) viewHolder;
            }

            if (parameterTypes.length == 2 && parameterTypes[1].isAssignableFrom(View.class)) {
                Object viewHolder = constructor.newInstance(adapter, v);
                return (EfficientViewHolder) viewHolder;
            }
        } catch (Exception e) {
            Log.e("ViewHolder init error", e.getMessage());
            throw new RuntimeException(
                    "Impossible to instantiate "
                            + viewHolderClass.getSimpleName(), e);
        }
    }

    return null;
}

EfficientRecyclerAdapter.class

@Override
public EfficientViewHolder generateViewHolder(View v, int viewType) {
    Class<? extends EfficientViewHolder> viewHolderClass = getViewHolderClass(viewType);
    if (viewHolderClass == null) {
        mBaseAdapter.throwMissingViewHolder(viewType);
        return null;
    }
    return mBaseAdapter.generateViewHolder(v, viewHolderClass, this);
}
@StanKocken
Copy link
Owner

I'm not sure how this code can help you to have an ViewHolder inner of an adapter.
If your call is just to have access to the adapter within your EfficientViewHolder, why don't override the method "generateViewHolder" and call a method "setAdapter" into?

@zhexian
Copy link
Author

zhexian commented Jan 13, 2016

example ViewHolder

public class StudentHomeWorkBaseViewHolder extends EfficientViewHolder<M_StudentInfos> {

protected LikeTextView mLikeTextView;

public StudentHomeWorkBaseViewHolder(View itemView) {
    super(itemView);
    mLikeTextView = findViewByIdEfficient(R.id.teacherStudentHomeWork_like);
}

@Override
protected void updateView(Context context, final M_StudentInfos object) {
 }
 }

if you put ViewHolder inside a Adapter ,the constructor is auto modified by the Adapter privately like this,the first paramater is the outter Adapter self

public StudentHomeWorkBaseViewHolder(Adapter adapter,View itemView) {
    super(itemView);
    mLikeTextView = findViewByIdEfficient(R.id.teacherStudentHomeWork_like);
}

so that's is why we add the code below to make it work。the parameterTypes[0] is the adpater,

  if (parameterTypes.length == 2 && parameterTypes[1].isAssignableFrom(View.class)) {
            Object viewHolder = constructor.newInstance(adapter, v);
            return (EfficientViewHolder) viewHolder;
        }

@zhexian
Copy link
Author

zhexian commented Jan 13, 2016

If your call is just to have access to the adapter within your EfficientViewHolder, why don't override the method "generateViewHolder" and call a method "setAdapter" into?

good question. we have consider this method,two reason not use it

1: we want easy to write viewHolder,just like a inner class can share outter class;frameWork should do this work.

2: add this feature to improve the range of ViewHolder exist type is fine

@StanKocken
Copy link
Owner

Ok I got your point, thanks. Make sense.

Any reason you're using an inner class over a static-nested class? You need an access to the adapter within your ViewHolder?

@zhexian
Copy link
Author

zhexian commented Jan 13, 2016

because in our project, some time the information is not satisfy by the model provided;so we need a link to adapter

@StanKocken
Copy link
Owner

Ok, I would avoid using an inner class for that but I got your point and agree that many developers would love to have this fix.

I will work on that (or you can still open a PR, so you will be an official contributor of the project ;) ) but will change few stuffs:

  • Into "AdapterHelper" I don't want any reference to EfficientRecyclerAdapter, I prefer the generic EfficientAdapter (so it will work with EfficientPagerAdapter as well)
  • Add the test for the first parameter to be sure it is EfficientAdapter instance into "(parameterTypes.length == 2 && parameterTypes[1].isAssignableFrom(View.class))"
  • Add an exception instead of the "return null" to be sure the developer understand why we were not able to generate the ViewHolder.

Thanks again for your contribution

@xiaobaDev
Copy link
Contributor

i am zheXian,thanks for inviting and this good project, i have used it for the recyclerView's adapter in my project and feel good

i also change the sequence of isAssignableFrom() ,because this method is used to check whether the paramater can be cast to the caller's class.,so the class of paramater should be the caller's class or it's subClass

String.class.isAssignableFrom(Object.class)  ----> false
Object.class.isAssignableFrom(String.class)  ----> true
Object.class.isAssignableFrom(Object.class)  ----> true

here's the code

<T extends EfficientViewHolder> EfficientViewHolder generateViewHolder(View v,
                                                                       Class<T> viewHolderClass, EfficientAdapter adapter) {
    Constructor<?>[] constructors = viewHolderClass.getDeclaredConstructors();

    if (constructors == null)
        return null;

    for (Constructor<?> constructor : constructors) {
        Class<?>[] parameterTypes = constructor.getParameterTypes();
        if (parameterTypes == null)
            continue;

        try {
            if (parameterTypes.length == 1 && parameterTypes[0].isAssignableFrom(View.class)) {
                Object viewHolder = constructor.newInstance(v);
                return (EfficientViewHolder) viewHolder;
            }

            if (parameterTypes.length == 2 && EfficientAdapter.class.isAssignableFrom(parameterTypes[0]) && View.class.isAssignableFrom(parameterTypes[1])) {
                Object viewHolder = constructor.newInstance(adapter, v);
                return (EfficientViewHolder) viewHolder;
            }
        } catch (Exception e) {
            Log.e("ViewHolder init error", e.getMessage());
            throw new RuntimeException(
                    "Impossible to instantiate "
                            + viewHolderClass.getSimpleName(), e);
        }
    }

    throw new IllegalArgumentException(
            "Impossible to found a constructor with a view for "
                    + viewHolderClass.getSimpleName());
}

@zhexian
Copy link
Author

zhexian commented Jan 16, 2016

support for viewHolder in adapter is added in pr #22

@zhexian zhexian closed this as completed Jan 16, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants