AndroidTreeView icon indicating copy to clipboard operation
AndroidTreeView copied to clipboard

reusing TreeNode structure

Open disovi opened this issue 10 years ago • 14 comments

I've created TreeNode structure and used it with AndroidTreeView. When I'm trying to reuse this structure with new AndroidTreeView I receive error

Caused by: java.lang.IllegalStateException: The specified child already has a parent. You must call removeView() on the child's parent first.
            at android.view.ViewGroup.addViewInner(ViewGroup.java:3936)
            at android.view.ViewGroup.addView(ViewGroup.java:3786)
            at android.view.ViewGroup.addView(ViewGroup.java:3727)
            at android.view.ViewGroup.addView(ViewGroup.java:3700)
            at com.unnamed.b.atv.view.AndroidTreeView.addNode(AndroidTreeView.java:228)
            at com.unnamed.b.atv.view.AndroidTreeView.expandNode(AndroidTreeView.java:210)
            at com.unnamed.b.atv.view.AndroidTreeView.getView(AndroidTreeView.java:106)
            at com.unnamed.b.atv.view.AndroidTreeView.getView(AndroidTreeView.java:111)

The problem is in ViewHolder. Before reusing ViewHolder we should set mView to null, but it is impossible now.

For now I have to use such hack

void cleanTreeNodes(List<TreeNode> treeNodes) {
        for (TreeNode treeNode : treeNodes) {
            TreeNode.BaseNodeViewHolder viewHolder = treeNode.getViewHolder();
            try {
                TreeNode.BaseNodeViewHolder viewHolder2 = viewHolder.getClass().getDeclaredConstructor(Context.class).newInstance(this);
                treeNode.setViewHolder(viewHolder2);
                viewHolder2.setContainerStyle(viewHolder.getContainerStyle());
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
            cleanTreeNodes(treeNode.getChildren());
        }
    }

disovi avatar Jul 16 '15 14:07 disovi

You can not reuse TreeNode structure, is it possible for you to re-create that structure?

bmelnychuk avatar Jul 18 '15 18:07 bmelnychuk

yes it is possible, but why can't we just add a method for cleaning views?

disovi avatar Jul 20 '15 08:07 disovi

Can you explain this bug a little more? I have the same problem and I do not think I understand the issue. I am trying to fix the issue with something like

((ViewGroup) treeView.getParent()).removeView(treeView);

dogauzun avatar Jul 24 '15 12:07 dogauzun

@dogauzun, my idea was to force viewHolder generate new view for each node. Your way is simpler. If you want to reuse views, which have been generated already, you can remove views of first level nodes from parent layout, something like this:

((ViewGroup)mRoot.getChildren().get(0).getViewHolder().getView().getParent()).removeAllViews();

disovi avatar Jul 24 '15 13:07 disovi

I solved this with the following code:

    //Used this treeView previously
    if (treeView != null)
        containerView.removeAllViews();

    treeView = AndroidTreeView(getActivity(), root);
    //...etc...
    containerView.addView(treeView.getView());

works just fine

Odaym avatar Aug 10 '15 13:08 Odaym

None of the above solutions are working for me. I am using a fragment and I initialize the treeview when i fetch some data from the network. It works fine for the first time but getView method throws an IllegalState exception on the second time. I am recreating Treenodes and viewholders from scratch each time.

dogauzun avatar Aug 25 '15 14:08 dogauzun

I solved this with the following code: if(tView == null) { Log.d("aaa","tView is null"); tView = new AndroidTreeView(getActivity(), root); tView.setDefaultAnimation(true); tView.setDefaultContainerStyle(R.style.TreeNodeStyleCustom); tView.setDefaultViewHolder(IconTreeItemHolder.class); tView.setDefaultNodeClickListener(nodeClickListener); tView.setDefaultNodeLongClickListener(nodeLongClickListener); root=TreeNode.root();

        // ((ViewGroup) containerView.getParent()).removeView(tView.getView());

        containerView.addView(tView.getView());
    }else{
        Log.d("aaa", "tView is not null");

        containerView.removeAllViews();
        tView = new AndroidTreeView(getActivity(), root);
        tView.setDefaultAnimation(true);
        tView.setDefaultContainerStyle(R.style.TreeNodeStyleCustom);
        tView.setDefaultViewHolder(IconTreeItemHolder.class);
        tView.setDefaultNodeClickListener(nodeClickListener);
        tView.setDefaultNodeLongClickListener(nodeLongClickListener);
        root=TreeNode.root();

        containerView.addView(tView.getView());
    }

nmorteza avatar Mar 06 '16 11:03 nmorteza

@dogauzun I have the same issue with you. Have you fixed it now?

stay4cold avatar May 04 '16 09:05 stay4cold

I solved my problem with moving my tree initialization method from onCreateView to onStart method in my fragment. I was trying to avoid initializing my tree everytime my fragment becomes visible but in my use case the tree structure is actually not that big so I stopped trying to do that.

dogauzun avatar May 04 '16 10:05 dogauzun

None of the above solutions are working for me. Has anybody found the right solution ?

sanjutagra avatar Jul 07 '16 05:07 sanjutagra

ok

On Wed, May 4, 2016 at 2:19 PM, ministorm [email protected] wrote:

@dogauzun https://github.com/dogauzun I have the same issue with you. Have you fixed it now?

— You are receiving this because you commented. Reply to this email directly or view it on GitHub https://github.com/bmelnychuk/AndroidTreeView/issues/25#issuecomment-216815089

nmorteza avatar Jul 10 '16 03:07 nmorteza

private void clearViewHolders(List<TreeNode> treeNodes) {
    for (TreeNode node : treeNodes) {
        if (node.getViewHolder() instanceof TreeStepViewHolder) {
            node.setViewHolder(null);
            TreeStepViewHolder treeStepViewHolder = new TreeStepViewHolder(getContext());
            treeStepViewHolder.setContainerStyle(R.style.TreeNodeStyleCustom);
            node.setViewHolder(treeStepViewHolder);
        } else if (node.getViewHolder() instanceof TreeFailureViewHolder) {
            node.setViewHolder(null);
            TreeFailureViewHolder treeFailureViewHolder = new TreeFailureViewHolder(getContext());
            treeFailureViewHolder.setContainerStyle(R.style.TreeNodeStyleCustom);
            node.setViewHolder(treeFailureViewHolder);
        }
        clearViewHolders(node.getChildren());
    }
}

This works for me.

simkis avatar Mar 09 '17 13:03 simkis

Thank you all of above, help me solving the problem of refresh tree node with data changed. here is my code , if anyone need:

if (layout != null) {//layout is the view you inflated in method createView,keep a reference to class field
            layout.removeAllViews();
            TreeNode newroot = TreeNode.root();
            fillTreeData(newroot, contextEvents);
            AndroidTreeView newTree = new AndroidTreeView(getActivity(), newroot);
            newTree.setDefaultAnimation(true);
            newTree.setDefaultViewHolder(MyTreeViewHolder.class);
            newTree.setDefaultContainerStyle(R.style.TreeNodeStyle);
            layout.addView(newTree.getView());
        }

these code can be called outside of method createView in fragment.

gyqsophila avatar Mar 20 '17 02:03 gyqsophila

I have same question, I solved my problem with fixing IconTreeItemHolder.java

TTLZZU avatar Apr 14 '19 03:04 TTLZZU