简体   繁体   中英

Send a variable from one class in a parameter to another class. Simple error

The variable I want to send to the other class is int position. It is in the parameter for the instantiateItem method. This basically indicates what position the swipe layout is at.

Now the variable position is only avaliable inside the onClick method. As soon as it's outside the method it's always 0. Will put examples in the code.

public class Csa{

private int getposition; 

public Object instantiateItem(ViewGroup container, int position) {
    layoutInflater = (LayoutInflater) ctx.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    View item_view = layoutInflater.inflate(R.layout.swipe_layout, container, false);
    imageView = (ImageView) item_view.findViewById(R.id.image_view);
    TextView textView = (TextView) item_view.findViewById(R.id.image_count);
    imageView.setImageResource(image_resources[position]);
    textView.setText(names[position]);
    container.addView(item_view);

    imageView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            switch(position){
             getposition = position;        
             case 1:
                 System.out.println(position); //Outputs 1. Correct.
                 Log.d("Exercise", "Deadlift!");
                 Intent intent1 = new Intent(CustomSwipeAdapter.this.ctx, AnalysisPage.class);
                 CustomSwipeAdapter.this.ctx.startActivity(intent1);
                 break;
             case 2:
                 getposition = position; 
                 System.out.println(position); // Outputs 2. Correct.
                 System.out.println(getposition()); // Outputs 2. Correct.
                 Log.d("Exercise", "Squats");
                 Intent intent2 = new Intent(CustomSwipeAdapter.this.ctx, AnalysisPage.class);
                 CustomSwipeAdapter.this.ctx.startActivity(intent2);
                 break;
         }


            }

    });

    return item_view;
}

   public int getposition() {
    return getposition;
}



 public class AnotherClass{
 Csa chooser = new Csa(this);
 private int command = chooser.getPosition();//Debugged. This is 0 always 0. Should be 1/2. Wrong.

 public static void main(String args[]){
 System.out.println(command);// Always prints out 0.

The variables inside the case/switches are always right. However if I'm making a global variable or even I assign the position variable to another variable, 0 is always the output. (See example in code).

Ultimately, I want the position variable to be in another class but the output is always 0. I have tried Getter/Setter methods and they still don't work.

An anonymous class can only access final variables of the enclosing class. In order to get around this, add the following class (in a separate file) to your project:

public class ValueHolder<T> {

    private T value = null;

    public ValueHolder() {
        setValue(null);
    }

    public ValueHolder(final T newValue) {
        setValue(newValue);
    }

    public T getValue() {
        return value;
    }

    public void setValue(final T newValue) {
        value = newValue;
    }

}

Then at the top of your code, replace int x = 0 with:

final ValueHolder<Integer> xHolder = new ValueHolder<Integer>(0);

And at each location in your anonymous class:

case 0:
     System.out.println(position); // Prints out 0 Correct
     xHolder.setValue(position);
...

case 1:
     System.out.println(position); // Prints out 1 Correct
     xHolder.setValue(position);
...

Then later when you want to use the value stored in the holder:

int storedX = xHolder.getValue();

EDIT: adding an observer

Create the following interface:

public interface OptionObserver {
    void notifyOptionChange(final int option);
}

Then make the other class that you need to send the value to, implement this interface.

Your CustomWipeAdapter should then have an attribute and a setter:

OptionObserver optionObserver = null;

public void setOptionObserver(OptionObserver observer) {
    optionObserver = observer;
}

Then during initialisation, you call setOptionObserver() passing a reference to the instance of your other class.

And in your CustomWipeAdapter:

case 1:
    System.out.println(position); //Outputs 1. Correct.
    if(optionObserver != null) {
        optionObserver.notifyOptionChange(position);
    }
...

What you are practically doing, is declaring a Java anonymous class inside your listener, implementing the onClick method that will be called. This enclosing class has a different scope by its outter class (they are not related by inheritance or friendship).

Now, the onClick method will be called asynchronously, as onClick is a callback, ie a method called when an event occurs that its containing class instance is registered to.

When the event occurs, the callback will change the values of x, as it is visible beside its scope, but not before the event occurs, and not in a synchronous way.

Think it like this in a simple example:

-Hello Jack, I hold an empty cofee cup. (your x var declared in outter class)

-Hello Joe, When the cofee maker is ready, I want you to fill your cofee cup (when an event occurs, change the value of x).

-What does your cup contain now? (print x, before the event)

-Nothing (0, logical).

-No, no, wrong!

-Hey, but the Coffee maker is not done yet. I will fill it when the coffee maker is ready.

What you should do is handle the data always after the event has occurred. I suggest that you do not use a property of the outter class, instead create a method in the outter class that takes an argument (the variable you want to use) and the rest of your code, and make sure that this method will be invoked inside your callback. For example:

public class CustomSwipeAdapter extends PagerAdapter {
    //Rest of code....
    public void NotifyWhenClickOccurs(int x){
      System.out.println(x);
      //Use x here.
    }


    imageView.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            switch(position){
             case 0:
                 System.out.println(position); // Prints out 0 Correct
                 //Notify your outter class instance.
                 Notify(position);
                 Log.d("Exercise", "Dumbell Press");
                 Intent intent0 = new Intent(CustomSwipeAdapter.this.ctx, AnalysisPage.class);
                 CustomSwipeAdapter.this.ctx.startActivity(intent0);
                 break;
             //Rest of code.....
         }
    }
}

This is similar to saying:

-(Joe) Jack, I will let you know when I fill my cup, so that you can drink my coffee.

A great standardized way of doing this is the Observer design pattern, and you are doing something similar here, considering the outter class as an "observer" in a more draft and general way.

Another thing you should consider is what you are doing inside your callback and notifying methods (what thread do they use? Can they perform changes to GUI/Dispatch thread from there?), but this is out of the scope of the question, just some food for thought.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM