简体   繁体   中英

Interface object not working when called from another fragment

Ok, so I have an Android app that basically is a login to a node.js server. The file structure consist of: MainActivity.java, FirstFragment.java, MiddleMan.java, and MySocket.java.

MainActivity.java

package "";

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.EditText;

import java.net.URISyntaxException;

public class MainActivity extends Activity implements MiddleMan {
    String SERVER_ADDRESS = "";
    MySocket my_socket;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    public void onConnectButtonPressed(EditText editText_ID){
        System.out.println("Received connect request from first fragment.");
        my_socket = new MySocket();
        try {
            my_socket.EstablishConnection(SERVER_ADDRESS, editText_ID);
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
    }

    public void ConnectionEstablished() {
        System.out.println("Received established connection from MySocket.java.");
    }
}

FirstFragment.java

package "";

import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class FirstFragment extends Fragment{
    MiddleMan mCallback;

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

    }
    private static TextView textView_state;
    private static EditText editText_ID;
    Button button_connect;
    Button button_disconnect;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
        View view = inflater.inflate(R.layout.first_fragment_root,container,false);
        textView_state = (TextView) view.findViewById(R.id.textView_state);
        editText_ID = (EditText) view.findViewById(R.id.editText_ID);
        button_connect = (Button) view.findViewById(R.id.button_connect);
        button_connect.setOnClickListener(new View.OnClickListener(){
            public void onClick(View v){
                buttonConnectClicked();
            }
        });
        Button button_disconnect = (Button) view.findViewById(R.id.button_disconnect);

        return view;
    }

    private void buttonConnectClicked() {
        System.out.println("Connect Button Pressed ");
        mCallback.onConnectButtonPressed(editText_ID);
    }

}

MiddleMan.java

package "";

import android.widget.EditText;

public interface MiddleMan {
    void onConnectButtonPressed(EditText editText_ID);
    void ConnectionEstablished();
}

MySocket.java

package "";

import android.app.Activity;
import android.app.Fragment;
import android.widget.EditText;

import com.github.nkzawa.emitter.Emitter;
import com.github.nkzawa.socketio.client.IO;
import com.github.nkzawa.socketio.client.Socket;

import java.net.URISyntaxException;

public class MySocket extends Fragment{
    public Socket lobby;

    MiddleMan mCallBack;

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

    public String getUserID(EditText editText_ID) {
        String string = editText_ID.getText().toString();
        if (string.length() > 0) {
            return string;
        }
        else {
            return null;
        }
    }

    public void EstablishConnection(String SERVER_ADDRESS,EditText editText_ID) throws URISyntaxException {
        lobby = IO.socket(SERVER_ADDRESS);
        final String client = getUserID(editText_ID);
        System.out.println("client: " + client);
        lobby.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
            @Override
            public void call(Object... args) {
                System.out.println("Connection established");
                mCallBack.ConnectionEstablished();
            }
        }).on("event", new Emitter.Listener() {

            @Override
            public void call(Object... args) {

            }
        }).on(Socket.EVENT_DISCONNECT, new Emitter.Listener() {

            @Override
            public void call(Object... args) {
                System.out.println("Connection terminated.");
            }
        });
        lobby.connect();
    }
}

There is an activity_main.xml, a first_fragment_root.xml (that eats up all of the display) and MySocket.java has no associated layout.

So far what happens is the app boots up displays an editText, textview, and two buttons: connect and disconnect. Entering some ID and then clicking the connect button executes this bit of code in FirstFragment.java:

private void buttonConnectClicked() {
        System.out.println("Connect Button Pressed ");
        mCallback.onConnectButtonPressed(editText_ID);
    }

Which moves on over to MiddleMan.java to have MainActivity.java execute this bit:

public void onConnectButtonPressed(EditText editText_ID){
        System.out.println("Received connect request from first fragment.");
        my_socket = new MySocket();
        try {
            my_socket.EstablishConnection(SERVER_ADDRESS, editText_ID);
        } catch (URISyntaxException e) {
            e.printStackTrace();
        }
    }

Which sends it into MySocket.java's EstablishConnection:

public void EstablishConnection(String SERVER_ADDRESS,EditText editText_ID) throws URISyntaxException {
        lobby = IO.socket(SERVER_ADDRESS);
        final String client = getUserID(editText_ID);
        System.out.println("client: " + client);
        lobby.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
            @Override
            public void call(Object... args) {
                System.out.println("Connection established");
                mCallBack.ConnectionEstablished();
            }
        }).on("event", new Emitter.Listener() {

            @Override
            public void call(Object... args) {

            }
        }).on(Socket.EVENT_DISCONNECT, new Emitter.Listener() {

            @Override
            public void call(Object... args) {
                System.out.println("Connection terminated.");
            }
        });
        lobby.connect();
    }

Everything worked fine, until I added that wee bit about MySocket.java having its own object to Middle man so it could tell MainActivity.java it is finished. Instead of it running mCallBack.ConnectionEstablished(); the program breaks and tells me Attempt to invoke interface method 'void MiddleMan.ConnectionEstablished()' on a null object reference

I have no idea what I am doing wrong, I assume that the onAttach method in MySocket.java is just not getting called so the mCallBack here is null, but why? Thanks for reading.

Conclusion

I've decided to post the working version of this to help people who might have the same or similar issue.

MainActivity.java

package "";

import android.app.Activity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.EditText;


import java.net.URISyntaxException;

public class MainActivity extends Activity implements MiddleMan {
    String SERVER_ADDRESS = "";
    MySocket my_socket;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    public void onConnectButtonPressed(EditText editText_ID){
        if (my_socket==null) {
            System.out.println("Received connect request from first fragment.");
            my_socket = new MySocket();
            my_socket.setListener(this);
            try {
                my_socket.EstablishConnection(SERVER_ADDRESS, editText_ID);
            } catch (URISyntaxException e) {
                e.printStackTrace();
            }
        }
    }

    public void ConnectionEstablished() {
        System.out.println("Received established connection from MySocket.java.");
        System.out.println("Attempting to establish room for client.");
        my_socket.requestRoom();
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                FirstFragment f = (FirstFragment) getFragmentManager().findFragmentById(R.id.first_fragment_root);
                f.updateTextViewState("Connected");
            }
        });
    }

    @Override
    public void onDisconnectButtonPressed() {
        if (my_socket!=null) {
            System.out.println("Received disconnect request from first fragment.");
            my_socket.requestDisconnect();
        }
    }

    @Override
    public void DisconnectEstablished() {
        System.out.println("Received disconnected from MySocket.java.");
        my_socket = null;
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                FirstFragment f = (FirstFragment) getFragmentManager().findFragmentById(R.id.first_fragment_root);
                f.updateTextViewState("Disconnected");
            }
        });

    }
}

FirstFragment.java

package "";

import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class FirstFragment extends Fragment{
    MiddleMan mCallback;

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

    }
    private static TextView textView_state;
    private EditText editText_ID;
    Button button_connect;
    Button button_disconnect;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState){
        View view = inflater.inflate(R.layout.first_fragment_root,container,false);
        textView_state = (TextView) view.findViewById(R.id.textView_state);
        editText_ID = (EditText) view.findViewById(R.id.editText_ID);
        button_connect = (Button) view.findViewById(R.id.button_connect);
        button_connect.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                buttonConnectClicked();
            }
        });
        button_disconnect = (Button) view.findViewById(R.id.button_disconnect);
        button_disconnect.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {
                buttonDisconnectClicked();
            }
        });

        return view;
    }

    private void buttonDisconnectClicked() {
        System.out.println("Disconnect Button Pressed ");
        mCallback.onDisconnectButtonPressed();
    }

    private void buttonConnectClicked() {
        System.out.println("Connect Button Pressed ");
        if (this.editText_ID.getText().toString()!=null && !this.editText_ID.getText().toString().isEmpty()) {
            mCallback.onConnectButtonPressed(editText_ID);
        }
    }

    public void updateTextViewState(String s){
        textView_state.setText(s);
    }

}

MySocket.java

package "";

import android.app.Fragment;
import android.content.Context;
import android.widget.EditText;

import com.github.nkzawa.emitter.Emitter;
import com.github.nkzawa.socketio.client.IO;
import com.github.nkzawa.socketio.client.Socket;

import java.net.URISyntaxException;

public class MySocket extends Fragment{
    public Socket lobby;
    String client;

    MiddleMan mCallBack;

    public void setListener(Context callback) {
        try {
            mCallBack = (MiddleMan) callback;
        } catch (ClassCastException e) {
            throw new ClassCastException(callback.toString()  + " must implement ReqestConnect");
        }
    }

    public String getUserID(EditText editText_ID) {
        String string = editText_ID.getText().toString();
        if (string.length() > 0) {
            return string;
        }
        else {
            return null;
        }
    }

    public void EstablishConnection(String SERVER_ADDRESS,EditText editText_ID) throws URISyntaxException {
        lobby = IO.socket(SERVER_ADDRESS);
        final String client = getUserID(editText_ID);
        this.client = client;
        System.out.println("client: " + this.client);
        lobby.on(Socket.EVENT_CONNECT, new Emitter.Listener() {
            @Override
            public void call(Object... args) {
                System.out.println("Connection established");
                mCallBack.ConnectionEstablished();
            }
        }).on("event", new Emitter.Listener() {

            @Override
            public void call(Object... args) {
                String s = (String) args[0];
                System.out.println(s);
            }
        }).on(Socket.EVENT_DISCONNECT, new Emitter.Listener() {

            @Override
            public void call(Object... args) {
                System.out.println("Connection terminated.");
                if (lobby!=null) {
                    Disconnect();
                }
            }
        }).on("room_created", new Emitter.Listener() {

            @Override
            public void call(Object... args) {
                String s = (String) args[0];
                System.out.println(s);
            }
        });
        lobby.connect();
    }

    public void requestRoom() {
        lobby.emit("request_user_room", this.client);
    }

    public void requestDisconnect() {
        if (lobby!=null) {
            if (lobby.connected()) {
                lobby.disconnect();
            }
        }
    }

    private void Disconnect() {
        lobby.off(Socket.EVENT_CONNECT);
        lobby.off("event");
        lobby.off(Socket.EVENT_DISCONNECT);
        lobby.off("room_created");
        lobby = null;
        mCallBack.DisconnectEstablished();
    }
}

MiddleMan.java

package "";

import android.widget.EditText;

public interface MiddleMan {
    void onConnectButtonPressed(EditText editText_ID);
    void ConnectionEstablished();
    void onDisconnectButtonPressed();
    void DisconnectEstablished();
}

activity_main.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">

    <fragment
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:name="<<PATH_TO_>>.FirstFragment"
        android:id="@+id/first_fragment_root"
        tools:layout="@layout/first_fragment_root"/>
</RelativeLayout>

first_fragment_root.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent" android:layout_height="match_parent">

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:text="@string/textView_ID"
        android:id="@+id/textView_ID"
        android:layout_alignParentTop="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true"
        android:layout_marginTop="23dp" />

    <EditText
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:inputType="phone"
        android:ems="10"
        android:id="@+id/editText_ID"
        android:hint="@string/editText_ID"
        android:layout_marginLeft="23dp"
        android:layout_marginStart="23dp"
        android:layout_alignBottom="@+id/textView_ID"
        android:layout_toRightOf="@+id/textView_ID"
        android:layout_toEndOf="@+id/textView_ID" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:text="@string/textView_status"
        android:id="@+id/textView_status"
        android:layout_alignParentBottom="true"
        android:layout_alignParentLeft="true"
        android:layout_alignParentStart="true" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textAppearance="?android:attr/textAppearanceMedium"
        android:text="@string/textView_state"
        android:id="@+id/textView_state"
        android:layout_alignParentBottom="true"
        android:layout_toRightOf="@+id/textView_status"
        android:layout_marginLeft="23dp"
        android:layout_marginStart="23dp" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/button_connect"
        android:id="@+id/button_connect"
        android:layout_below="@+id/textView_ID"
        android:layout_alignLeft="@+id/editText_ID"
        android:layout_alignStart="@+id/editText_ID"
        android:layout_marginTop="25dp" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/button_disconnect"
        android:id="@+id/button_disconnect"
        android:layout_alignBottom="@+id/button_connect"
        android:layout_alignRight="@+id/editText_ID"
        android:layout_alignEnd="@+id/editText_ID" />

</RelativeLayout>

From android developers:

onAttach(Context context)

Called when a fragment is first attached to its context.

It doesn't look like you are attaching to a context, rather, you are basically using the fragment as if it was a regular java class. This can be useful, however, onAttach isn't called.

Maybe try something like this. Instead of this code:

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

Call it setListener(ReqestConnect callback) like this:

public void setListener(ReqestConnect callback) {
    mCallBack = callback; 
}

Then, when you create the socket fragment call the setListener method. Like this:

public void onConnectButtonPressed(EditText editText_ID){ 
    System.out.println("Received connect request from first fragment.");
    my_socket = new MySocket(); 
    my_socket.setListener(this);
    try { 
        my_socket.EstablishConnection(SERVER_ADDRESS, editText_ID); 
    } catch (URISyntaxException e) { 
        e.printStackTrace(); 
    } 
}

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