proninyaroslav proninyaroslav - 6 months ago 25
Android Question

Android: How to fix accidental uncheck the checkbox of the parent node in the tree

I wrote the class to represent a tree file hierarchy. The main task - the ability to mark files and folders (using the checkbox). Has faced with such a problem: disappears check mark of the parent directory with the following sequence of actions:

0) Go to the root directory, check file (leave one directory unchecked)

1) Go to the unchecked directory and check any file (or more)

2) Return to a higher level and uncheck the directory,in which was carried out operation (1)

Return to a higher level and you'll see that check mark of the parent directory is unchecked (although there is at least one checked file in a root directory).

For many days I am in search of a problem. Maybe someone will notice the error. Thank you in advance.

Screenshots:

Bug

Normal state

The class:

public class FileTree {
/* The name for pointer to the parent node */
public static final String PARENT_DIR = "..";

private String mName;
private boolean mIsLeaf;
private boolean mIsChecked = false;
private long mSize;
/* Number of checked children */
private int childrenCheckNum = 0;
private FileTree mParent;
private Map<String, FileTree> mChildren = new LinkedHashMap<String, FileTree>();

public FileTree(String name, long size, int type)
{
this(name, size, type, null);
}

public FileTree(String name, long size, int type, FileTree parent)
{
mName = name;
mIsLeaf = type == FileNode.Type.FILE;
mParent = parent;
mSize = size;
}

public void addChild(FileTree node)
{
if (!mChildren.containsKey(node.getName())) {
mChildren.put(node.getName(), node);
mSize += node.size();
if (mParent != null) {
mParent.onChildAdd(node.size());
}
}
}

/*
* Sending new child size up the tree.
*/

private void onChildAdd(long size)
{
mSize += size;
if (mParent != null) {
mParent.onChildAdd(size);
}
}

public boolean findChild(String name)
{
if (mChildren.containsKey(name)) {
return true;
}

return false;
}

...

public boolean isChecked()
{
return mIsChecked;
}

public void setCheck(boolean check)
{
mIsChecked = check;

/* Sending check change event up the parent */
if (mParent != null && mParent.isChecked() != check) {
mParent.onChildCheckChange(check);
}

/* Sending check change event down the tree */
if (getChildrenCount() != 0) {
childrenCheckNum = check ? getChildrenCount() : 0;

for (FileTree node : mChildren.values()) {
if (node.isChecked() != check) {
node.setCheck(check);
}
}
}
}

/*
* Sending check change events up the tree.
*/

private void onChildCheckChange(boolean check)
{
if (check) {
++childrenCheckNum;
mIsChecked = true;
} else {
if (childrenCheckNum > 0) {
--childrenCheckNum;
}

/* Uncheck parent only if don't left selected children nodes */
if (childrenCheckNum == 0) {
mIsChecked = false;
}
}

/* Sending check change event up the parent */
if (mParent != null && mParent.isChecked() != check) {
mParent.onChildCheckChange(check);
}
}
...
}

Answer

I have simplified onChildCheckChanged and now it is working properly

private synchronized void onChildCheckChange()
    {
        if (getChildrenCount() == 0) {
            return;
        }

        long childrenCheckNum = 0;
        for (FileTree child : children.values()) {
            if (child.isChecked) {
                ++childrenCheckNum;
            }
        }

        /* Uncheck parent only if don't left selected children nodes */
        isChecked = childrenCheckNum > 0;

        /* Sending check change event up the parent */
        if (parent != null && parent.isChecked() != isChecked) {
            parent.onChildCheckChange();
        }
    }
Comments