Search code examples
androidmultithreadingandroid-intentandroid-activityhandler

Launching a new Activity from a Handler


I have a client/server application that needs to be able to launch different Activities. I have a working TCP thread that runs continuously in the background and a working handler in my MainAcitivty which the TCP thread uses to send messages. The problem is getting that handler to launch anything other than strings. My TCP thread creates an object of the MainActivity on start up so it can access my handler which it must do since my handler is not static. Everything works fine if I run it from a button on my MainActivity but I get nullpointexceptions on everything when launched from my handler. I believe it dislikes my Context but I can’t find a work around. Thanks

Handler TCP_handler = new Handler()
{   
@Override
    public void handleMessage(Message msg) {

Message.obtain();
Bundle bundle = msg.getData();          

switch( msg.what ){
        case 1: 
            // this stuff works
    String aResponse1 = bundle.getString("messageStringL1");
        String aResponse2 = bundle.getString("messageStringL2");
        if(aResponse1 != null)
            textViewLineOne.setText(aResponse1);
        if(aResponse2 != null)
            textViewLineTwo.setText(aResponse2);

            break;
        case 2:  
            // Method 1
            // nullpointer exception error
            Intent i = new Intent(MainActivity.this, IdleScreen.class);      
        startActivity(i);

            // Method 2
            // nullpointer exception error
            Toast.makeText(MainContextSaved, "This is Toast!!!", Toast.LENGTH_SHORT).show();  

            // Method 3
            // this launches but can only write to the MainActivty textview 
            runOnUiThread(IdleScreenUI);    
            break;
}
    }
};


private Runnable IdleScreenUI = new Runnable() {
    @Override
    public void run() {

        // this is the new screen I want to display
            setContentView(R.layout.idlescreen );  // nullpointer exception error

            // this is a textview in the MainActivity and it works
            // textViewLineOne.setText("hello");   

        // null pointer exception error
            Toast.makeText(MainContextSaved, "This is Toast!!!", Toast.LENGTH_SHORT).show();  

    }
}; 

Solution

  • My TCP thread creates an object of the MainActivity on start up.
    

    Even if you create the object of the activity , that is not a real activity context. thats why your unable to start the other activity.

    If I understood your problem correctly, when you try to start the other activity from handler, the MainActivity is in foreground(in stack).

    Assuming that you have launched the MainActivity and your TCP operations are done in background.

    If your background TCP operations are done from a service,then when the MainActivity is started you can bind to the service and share the activity context to the service.

    So now with the MainActivity context you can send Message to the handler.

    Here is a sample I created..

    CustomService.java

    public class CustomService extends Service {
    private final IBinder mIBinder = new LocalBinder();
    // temporary handler
    private Handler mHandler = new Handler();
    // context to hold MainActivity handler 
    private Context mActivityContext = null;
    
    @Override
    public int onStartCommand(Intent intent, int flag, int startId) {
    
        // for testing Iam sending an empty message to the handler after 10 seconds
        mHandler.postDelayed(new Runnable() {
            @Override
            public void run() {
                if (mActivityContext != null) {
                    ((MainActivity) mActivityContext).TCP_handler.sendEmptyMessage(2);
                }
            }
        }, 10000);
        return START_STICKY;
    }
    
    @Override
    public IBinder onBind(Intent intent) {
        return mIBinder;
    }
    
    public void setActivityContext(Activity activityContext) {
        mActivityContext = activityContext;
    }
    
    public class LocalBinder extends Binder {
        public CustomService getInstance() {
            return CustomService.this;
        }
      }
    }
    

    Now , you can start the service from activity and bind a service connection.

    MainActivity.java

    public class MainActivity extends ActionBarActivity {
    
    CustomService customService = null;
    TextView textViewLineOne;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // start the service, even if already running no problem.
        startService(new Intent(this, CustomService.class));
        // bind to the service.
        bindService(new Intent(this,
                CustomService.class), mConnection, Context.BIND_AUTO_CREATE);
    }
    
    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            customService = ((CustomService.LocalBinder) iBinder).getInstance();
            // pass the activity context to the service
            customService.setActivityContext(MainActivity.this);
        }
    
        @Override
        public void onServiceDisconnected(ComponentName componentName) {
            customService = null;
        }
    };
    
    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (customService != null) {
            // Detach the service connection.
            unbindService(mConnection);
        }
      }
    
      // Add your handler code stuff here..
    }