Tran Hoai Nam Tran Hoai Nam - 27 days ago 8
Android Question

Android - "No enclosing instance of type 'some.abstract.class.name' class is in scope" error when extended

I have an abstract adapter class from an external library:

public abstract class DragItemAdapter<T, VH extends DragItemAdapter.ViewHolder> extends RecyclerView.Adapter<VH> {
//Their other codes
public class ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(final View itemView, int handleResId) {
super(itemView);
//The rest of their codes
}
}
}


And I have my Adapter extended that adapter

public class ChecklistAdapter extends DragItemAdapter<Pair<Integer, SomeClass>, ViewHolderForChecklist> {

@Override
public ViewHolderForChecklist onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item, parent, false);
grab = R.id.grab;
return new ViewHolderForChecklist(view,grab);
}
}


If my
ViewHolderForChecklist
is an inner class of the
ChecklistAdapter
it works fine. But if I move the
ViewHolderForChecklist
to a brand new class

public class ViewHolderForChecklist extends DragItemAdapter<Pair<Long, SomeClass>, ViewHolderForChecklist>.ViewHolder { // The error is at this line

public ViewHolderForChecklist(final View itemView, int grab) {
super(itemView, grab);
}

@Override
public void onItemClicked(View view) {

}

@Override
public boolean onItemLongClicked(View view) {
return true;
}
}


There is an error in real time


No enclosing instance of type 'library.package.name.DragItemAdapter' class is in scope


and the error when compile


error: an enclosing instance that contains DragItemAdapter.ViewHolder is required


Using "move" from Refractor has the same problem. I'm still new to this kind of... 'nested-class" so I don't know what is wrong with this or what kind of info should I include more.

Thank you!

ajb ajb
Answer

ViewHolder is an inner class of DragItemAdapter (because it wasn't declared static). That means that every object of class ViewHolder must be associated with an object of class DragItemAdapter (actually, it would have to be a subclass of DragItemAdapter). You can think of ViewHolder having a hidden instance variable like

DragItemAdapter __outerObject;

The ViewHolder can directly access instance variables and methods belonging to the __outerObject.

That means that when you say new ViewHolder(...), you have to have some DragItemAdapter for the ViewHolder to be associated with.

The same applies to any subclass of ViewHolder, including ViewHolderChecklist, since the subclass inherits the hidden __outerObject variable.

In the first example, where ViewHolderChecklist is inside a ChecklistAdapter, the onCreateViewHolder method will always be called on a ChecklistAdapter instance. When that method says new ViewHolderChecklist, the new object's __outerObject will be set to the ChecklistAdapter instance. Also, if an outside class has a ChecklistAdapter adapter;, it can use that to create a new ViewHolderChecklist by saying adapter.new ViewHolderChecklist(...).

When you move ViewHolderChecklist outside the class, though, there's no way for a new instance to be created, since there's no way to use new in a way that would tell it what its __outerObject is supposed to be. The adapter.new ViewHolderChecklist(...) syntax won't work, because that syntax is only allowed for nested classes, and ViewHolderChecklist isn't a nested class. So ViewHolderChecklist has to be a nested class inside a subclass of DragItemAdapter.

Comments