androidwebsocketnullfragmentgetview

Android fragment reutn null on getview() when OnTextMessage is triggered


I want to update text in a fragment when the messages come.

In the Main Activity I do the connection with wsuri. Every message that I received the callback onTextMessage is triggered. The library I use is autoBahn.

public class MainActivity extends AppCompatActivity{

private   static  WebSocketConnection mConnection = new WebSocketConnection();  

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

        if(savedInstanceState == null){
                frag_Home = new HomeFragment();
                fragmentManager.beginTransaction().add(R.id.fragmentContent, frag_Home, getString(R.string.TAG_HOME)).commit();
            }else{
                if(fragmentManager.findFragmentByTag(getString(R.string.TAG_HOME)) == null){
                    frag_Home = new HomeFragment();
                    fragmentManager.beginTransaction().add(R.id.fragmentContent, frag_Home, getString(R.string.TAG_HOME)).commit();
                }

        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        // Start Connection
        Connect(ipAdress);
        Log.i("ROOT ACTIVITY", "onResume");
    }


    // Function callback events
    private void Connect(String ipAddress){

    final String wsuri = "ws://" + ipAddress + ":" + port;

        try {
            // Handle Websocket Event
            mConnection.connect(wsuri, new WebSocketHandler() {

                @Override
                public void onOpen() {
                    Log.d("WIFI", "onOpen: Conneced to "+ wsuri);
                }



                @Override
                public void onTextMessage(String payload) { 
                    HomeFragment home = (HomeFragment) getSupportFragmentManager().findFragmentByTag(getString(R.string.TAG_HOME));
                    ((TextView)home.getView().findViewById(R.id.txtMsg)).setText(payload);
                }

                Override
                public void onClose(int code, String reason) {
                }
            }   
        }
    }
}   

All run fine the texts updates correctly but when I rotate my phone and when I receive a message I get an error

java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.View test.test.com.test.HomeFragment.getView()' on a null object reference 

And the texts never updates again.


Solution

  • Short Answer

    This can be fixed with adding android:configChanges="orientation" in the manifest of your activity but this can lead to UI bugs because you're left on your own to handle the changes of the orientation.

    Long Answer

    mConnection.connect(wsuri, new WebSocketHandler() {
    
                @Override
                public void onOpen() {
                    Log.d("WIFI", "onOpen: Conneced to "+ wsuri);
                }
    

    This inner anonymous class WebSocketHandler contains an implicit reference to the current instance of your MainActivity on the point of creation but that instance will be trashed by the Android system on orientation change. So what you're seeing after the orientation change is now a different instance than what your WebSocketHandler class points to, resulting to having null returned in your findFragmentByTag call because the HomeFragment that you're trying to request for was already cleaned up in the old instance of your MainActivity. Also this causes a memory leak because your WebSocketHandler will prevent the old instance of MainActivity to be GC'ed.

    What I suggest you to do is have an entirely separate class that will handle the websocket connection and is not an inner class of the any Activity. Or you can use android:configChanges="orientation" and make sure that you handle the orientation changes properly through

    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        // Checks the orientation of the screen
        if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
            //handle the orientation change, ex change/rearrange fragments
        }
    }