El objeto de interfaz no funciona cuando se llama desde otro fragmento
Ok, así que tengo una aplicación de Android que básicamente es una entrada a un servidor node.js. La estructura de archivos consta de: MainActivity.java, FirstFragment.java, MiddleMan.java y MySocket.java.
MainActivity.java
- Androide HttpResponse siempre muere segunda vez que se llama
- Creación de un libro de ubicación con Android
- Anotación Java ejecuta un método dentro de la declaración de anotación (uso para android)
- La autenticación mutua de SSL FAIL en Android Client acepta el certificado de servidores pero el servidor no obtiene el certificado de cliente
- Al crear una intención de Android y especificar la actividad de destino, ¿cuál es esta sintaxis ".class"?
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(); } }
Hay un activity_main.xml, un first_fragment_root.xml (que se come toda la pantalla) y MySocket.java no tiene ningún diseño asociado.
Hasta ahora lo que ocurre es que la aplicación arranque muestra un editText, textview, y dos botones: conectar y desconectar. Al ingresar un ID y luego hacer clic en el botón de conectar ejecuta este bit de código en FirstFragment.java:
private void buttonConnectClicked() { System.out.println("Connect Button Pressed "); mCallback.onConnectButtonPressed(editText_ID); }
Que pasa a MiddleMan.java para que MainActivity.java ejecute este 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(); } }
Que lo envía a MySocket.java 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(); }
Todo funcionó bien, hasta que añadí un poco sobre MySocket.java tener su propio objeto a Middle man para que pudiera decir MainActivity.java que está terminado. En lugar de ejecutar mCallBack.ConnectionEstablished (); El programa se rompe y me dice Attempt to invoke interface method 'void MiddleMan.ConnectionEstablished()' on a null object reference
No tengo ni idea de lo que estoy haciendo mal, supongo que el método onAttach en MySocket.java no es simplemente llamado así que el mCallBack aquí es nulo, pero ¿por qué? Gracias por leer.
Conclusión
He decidido publicar la versión de trabajo de este para ayudar a las personas que podrían tener el mismo problema o similar.
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>
- HttpResponse usando android issue: ejecutar siempre causa excepción?
- Eclipse se bloquea con límite de gastos generales de GC superado después de enlazar servicios de Google Play
- ¿Clase insegura en Android?
- Cómo reproducir archivos mp3 de la tarjeta SD interna y externa en android?
- OutOfMemoryError ¿qué aumentar y cómo?
- Cómo hacer la reanudación de sesión SSL en Android
- Cómo pasar valores hexadecimales a una cadena - Android
- Generación de coeficientes de filtro DSP en C / Java para convolución en el dominio del tiempo
De los desarrolladores de Android:
onAttach(Context context) Called when a fragment is first attached to its context.
No parece que se está uniendo a un contexto, sino que, básicamente, está utilizando el fragmento como si se tratara de una clase java regular. Esto puede ser útil, sin embargo, onAttach no se llama.
Quizás intente algo como esto. En lugar de este código:
@Override public void onAttach(Activity activity){ super.onAttach(activity); try { mCallBack = (MiddleMan) activity; } catch (ClassCastException e) { throw new ClassCastException(activity.toString() + " must implement ReqestConnect"); } }
Llámelo setListener (ReqestConnect callback) como esto:
public void setListener(ReqestConnect callback) { mCallBack = callback; }
A continuación, al crear el fragmento de socket, llame al método setListener. Me gusta esto:
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(); } }
- Reproducir archivos mp3 uno tras otro con poco retraso con un código más elegante?
- Córdoba: cómo tomar una foto sin usar la aplicación de cámara