-2

I have a View object and I try to set it. However, it always remains null outside the function . Here I try to set it while being passed as a parameter, I also tried with return-statement but to no avail. Most probably, because the problem is somewhere else and I just can't see it. Strangely, enough it gets set inside the function, but outside remains null. Code:

private EditText mView = null;

public void findViewByTag(ViewGroup vg, Object obj, View v) {

    if (vg == null)
        return;

    for (int i = 0; i < vg.getChildCount(); i++) {
        if (vg.getChildAt(i).getTag() != null) {
            if (vg.getChildAt(i).getTag().toString().equals(obj)) {
                Log.d("Found", "Yes." + obj.toString());//here it does get found
                v = vg.getChildAt(i);
                //tested, it is not null HERE
                return;
            }
        }
    }
    for (int i = 0; i < vg.getChildCount(); i++) {
        if (vg.getChildAt(i) instanceof ViewGroup) {
            findViewByTag((ViewGroup) vg.getChildAt(i), obj, v);
        }
    }
}

Then I call it like findViewbyTag(mViewGroup, "_MyTag", mView). Here I find out that mView == null.

As a side question, how can I stop the recursion from iterating all my views after having found the one? Is there a way to stop it iterating the other view branches? Probably not, but still.

EDIT: This also doesn't work out as said in the beginning above.

public View findViewByTag(ViewGroup vg, Object obj) {

    if (vg == null)
        return null;

    for (int i = 0; i < vg.getChildCount(); i++) {
        //because some are not set and we don't like NullPtrs
        if (vg.getChildAt(i).getTag() != null) {
            if (vg.getChildAt(i).getTag().toString().equals(obj)) {
                Log.d("Found", "Yes." + obj.toString());

                return vg.getChildAt(i);
            }
        }
    }
    for (int i = 0; i < vg.getChildCount(); i++) {
        if (vg.getChildAt(i) instanceof ViewGroup) {
            findViewByTag((ViewGroup) vg.getChildAt(i), obj);
        }
    }
    return null;
}
Dimitar
  • 4,402
  • 4
  • 31
  • 47
  • What is the third param `View v` for? – Adil Soomro Jun 27 '16 at 22:29
  • 1
    That's how OP is trying to return the found value. – Prune Jun 27 '16 at 22:29
  • 1
    You might want to look at the java's pass-by-value and pass-by-reference http://stackoverflow.com/a/24546764/593709 discussion. In short, you can't return value in java like that. – Adil Soomro Jun 27 '16 at 22:36
  • @AdilSoomro I said in the beginning that I also tried with View instead of void and returning the found value and then otherwise return null. BUT it didnt change. – Dimitar Jun 27 '16 at 22:38
  • Returning the view is correct approach, but you might have a problem in your logic as well. – Adil Soomro Jun 27 '16 at 22:39
  • 1
    The ultimate problem is that the OP thinks the variable passed as the last argument to the method call is changed by `v = vg.getChildAt(i);`, but the fact is that only the method's version of the variable is changed. – SamTebbs33 Jun 27 '16 at 22:41
  • @SamTebbs33 I thought of it, but still the edited version also didn't work. I was puzzled and then decided to ask here for opinion. – Dimitar Jun 27 '16 at 22:44
  • Because you are returning the wrong value in the edited method. Take a look at how values are returned in recursive methods. If your method goes into recursion you will always get null because that is what you are returning. – Apoorv Jun 27 '16 at 22:51
  • Yes, it dawned on me right now. But what should I return at the end if its type is `View`. Prob need to get my logic right – Dimitar Jun 27 '16 at 23:01

1 Answers1

1

I think your two issues are the same problem: the ultimate value of v is from the last call only, not the successful one. The only time you get the desired value is when it's in the last branch of your search.

The main problem is that you don't stop when you find it. Rewrite the logic to do two things:

  1. Return the found item (or NULL) as the functional value (change void to View and drop the v parameter).
  2. Capture this return value inside your loop, and continue only so long as it's NULL. Break when you get a good value. Regardless of your method of loop exit, return the "best" value found (success or failure).

I don't have a JRE to test in here, but let me try a blind hand-edit:

public View findViewByTag(ViewGroup vg, Object obj) {

    result = null

    if (vg == null)
        return null;

    for (int i = 0; i < vg.getChildCount(); i++) {
        //because some are not set and we don't like NullPtrs
        if (vg.getChildAt(i).getTag() != null) {
            if (vg.getChildAt(i).getTag().toString().equals(obj)) {
                Log.d("Found", "Yes." + obj.toString());

                result = vg.getChildAt(i);
            }
        }
    }
    for (int i = 0; i < vg.getChildCount(); i++) {
        if (vg.getChildAt(i) instanceof ViewGroup) {
            result = findViewByTag((ViewGroup) vg.getChildAt(i), obj);
            if (result) break;
        }
    }
    return result;
}

Your previous version failed to return a successful result. You can clean up this logic flow a little, but I tried to keep the changes minimal.

Prune
  • 76,765
  • 14
  • 60
  • 81
  • Yes, you were right. First, I modify only the copy **inside**. Second, when using returns, I return the one at the bottom (otherwise `missing return statement` as in SamTebbs33's answer) as null thus overwriting the previously set value. Now with the `result` check works. Thanks a lot. – Dimitar Jun 27 '16 at 23:15