Java's inner class, anonymous class would have thought that their use has been very slip, the result, just yesterday at 12 o'clock, a major accident happened. To say the seriousness of the accident, that is to cause me to sleep all night.
Let's use a mock-up code to describe my problem:
public class Test {public static void main (string[] args) throws Interruptedexception {View V = new View (); v.show (1); Thread.Sleep (+); V.mtextview.execute (); Thread.Sleep (+); V.show (2); Thread.Sleep (+); V.mtextview.execute ();}} Class View {public TextView mtextview;public void Show (int position) {if (Mtextview = = null) {Mtextview = new TextView (); MT Extview.setlistener (New Listener () {@Overridepublic void click () {System.out.println ("position =" + position);}}); Mtextview.show ();}} Class TextView {private Listener mlistener;public void Setlistener (Listener l) {mlistener = l;} public void Execute () {Mlistener.click ();} public void Show () {System.out.println ("TextView show ...");}} Interface Listener {public void click ();}
No accident, the console must be printed 1 2, but it is in this troubled me, the result of the printing is 1 1, carefully go through the code, we should think about how the anonymous inner class is using the external class that method parameters.
From the printed results, I guess I must have saved the position parameter in an instance of this inner class, and with this conjecture, let's debug the program.
This is the first time the implementation of the time, found what the problem. There is a variable associated with position in Mlistener. Here, we feel that the speculation may be correct. Think again, since this variable is saved in the Mlistener object, the next time we execute the same object, the variables are definitely the same, which will solve our doubts.
To summarize:
In our new anonymous inner class, if we use something in the method, then the JVM will add a constructor to our anonymous class and pass this parameter in, for example, in the example above:
Class View$listener {public View$listener (int. position) {this. Listener$position = position;} public void Click () {...}}
Now that we know this, then our doubts will be solved, then how to solve the problem? In fact, we already knew the solution very early, think of the android in the custom adapter GetView () method, you will suddenly understand. How to solve the problem above? is to put the setlistener behind the IF, not inside.
public class Test {public static void main (string[] args) throws Interruptedexception {View V = new View (); v.show (1); Thread.Sleep (+); V.mtextview.execute (); Thread.Sleep (+); V.show (2); Thread.Sleep (+); V.mtextview.execute ();}} Class View {public TextView mtextview;public void Show (int position) {if (Mtextview = = null) {Mtextview = new TextView ();// Mtextview.setlistener (New Listener () {//@Override//public void Click () {//system.out.println ("position =" + position) ;//}//});} Mtextview.setlistener (New Listener () {@Overridepublic void click () {System.out.println ("position =" + position);}); Mtextview.show ();}} Class TextView {private Listener mlistener;public void Setlistener (Listener l) {mlistener = l;} public void Execute () {Mlistener.click ();} public void Show () {System.out.println ("TextView show ...");}} Interface Listener {public void click ();}
This will re-new the listener inner class each time the show method is called.
Start with an accident. Java Anonymous inner class