简体   繁体   中英

Java, using an interface as a callback

I have been developing a simple touch handler for Android with the possibilites of firing callbacks like onUpdate (when the screen is touched) without having to setup threads. My problem is that my knowledge of Java is fairly limited and i can't do it because i know very little of how to use interfaces. I'm pretty sure that my problem may be a simple typo or something, but i get a NullPointerException when i execute the method from the touch handler (which processed the touch information) so that i can do what i need in the main activity class.

This is the main class code (cut from the irrelevant stuff):

//package and imports

public class Test extends Activity implements TouchHelper {

    StringBuilder builder = new StringBuilder();
    TextView textView;
    TouchReader touchReader;
    List<TouchTable> touchTablesArray;
    TouchTable touchTable;
    public static final String Tag = "TouchTest";

        @Override
        public void onCreate(Bundle savedInstanceState) 
        {
            super.onCreate(savedInstanceState);
            textView = new TextView(this);
            Log.d(Tag, "TextView initialized " + textView);
            textView.setText("Touch and drag (multiple fingers supported)!");
            touchReader = new TouchReader(textView);
            Log.d(Tag, "touchReader initialized");
            touchTablesArray = touchReader.getTouchTables();
            setContentView(textView);
        }

        @Override
        public void onTouchUpdate(int pointerId)
        {
            Log.d(Tag, "onTouchUpdate called");
            touchTable = touchTablesArray.get(pointerId);
            Log.d(Tag, "touchTable get successful");
            //writing on stringbuilder
        }
    }

This is the code of the handler itself:

//package and imports

public class TouchReader implements OnTouchListener
{
    public final static String Tag = "TouchReader";
    List<TouchTable> touchTables;
    TouchHelper helper;
    TouchTable touchTable = new TouchTable();

    public TouchReader(View view)
    {
        view.setOnTouchListener(this);
        touchTables = new ArrayList<TouchTable>(10);
        Log.d(Tag, "TouchReader initialized");
    }

    public boolean onTouch(View v, MotionEvent event)
    {
        synchronized(this)
        {
            //all the common code handling the actual handling, with switches and such
            touchTables.add(pointerId, touchTable); //obviously the pointerId is defined earlier
            Log.d(Tag, "Values updated");
            helper.onTouchUpdate(pointerId); //the exception is here
            Log.d(Tag, "Update called");
        }
        return true;
    }
    public List<TouchTable> getTouchTables()
    {
        synchronized(this)
        {
            return touchTables;
        }
    }
}

As you can see the error is most likely due to my inability to correctly use an interface, and yet all the official docs confused me even more.

Finally, the tiny code of the interface:

//package

public interface TouchHelper 
{
    public void onTouchUpdate(int pointerId);
}

I hope this question isn't too noobish to post it here :)

EDIT: Thanks to all for the help, in the end i followed Bughi's solution.

Your TouchHelper helper; is null, it needs a instance of the interface to be able to call methods on it -in your case the main activity class that implements your interface-

Make a set method for the listener

public void setOnTouchListener(TouchHelper helper)
{
    this.helper = helper;
}

Then call it from on create:

public class Test extends Activity implements TouchHelper {
    ...
    @Override
    public void onCreate(Bundle savedInstanceState) 
    {
        ...
        touchReader = new TouchReader(textView);
        touchReader.setOnTouchListener(this);
        ...
    }
}

Also add a null check to your on touch method:

public boolean onTouch(View v, MotionEvent event)
{
    synchronized(this)
    {
        //all the common code handling the actual handling, with switches and such
        touchTables.add(pointerId, touchTable); //obviously the pointerId is defined earlier
        Log.d(Tag, "Values updated");
        if (helper != null)
            helper.onTouchUpdate(pointerId); //the exception is here
        Log.d(Tag, "Update called");
    }
    return true;
}

If the NullPointerException is here:

helper.onTouchUpdate(pointerId);

Then simply helper is null, where do you initialize it?

I see that you define it:

TouchHelper helper;

But do you ever have?

helper = ...

I know this is old, but I was stuck on this myself. Sam's post above helped me think of it.
I finally added an onAttach method that that checks that the interface is initialized as well as implemented to the main activity that it interfaces with. I added a Log.i inside the main activity to test.

@Override
public void onAttach(Activity activity) {
    super.onAttach(activity);
    try {
        mainActivityCallback = (OnSomethingSelectedListener) activity;
    } catch (ClassCastException e) {
        throw new ClassCastException(activity.toString()
                + " must implement OnSomethingSelectedListener");
    }
}

In TouchReader you define a TouchHelper but nowhere in the code an object is created or an existing object is assigned to that attribute. So it is still null when you try to use it.

helper is null in your in TouchReader

To fix this make the TouchReader take a TouchHelper :

public TouchReader(View view, TouchHelper helper) {
    ...
    this.helper = helper;   
    ...
}

Then in your activity:

touchReader = new TouchReader(textView, this);

Try initializing it in your constructor; all reference that aren't initialized are set to null.

// I see no reason why this should be a member variable; make it local
StringBuilder builder = new StringBuilder();
TextView textView;
TouchReader touchReader;
List<TouchTable> touchTablesArray;
TouchTable touchTable;
public TouchReader(View view)
{
    // textView is null
    // touchReader is null
    view.setOnTouchListener(this);
    // why "10"?  why a List of touchTables and a touchTable member variable?  why both?
    touchTables = new ArrayList<TouchTable>(10);
    Log.d(Tag, "TouchReader initialized");
    // touchTable is null;
}

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