1

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();  

    }
}; 
Steve
  • 33
  • 7
  • How do you start your MainActivity ? – Libin Apr 09 '14 at 00:14
  • I just call setContentView(R.layout.activity_main); from onCreate. Then I launch my TCP thread which listens and then connects to the server. I also have another thread I'll use for misc things I'll be adding over time. – Steve Apr 09 '14 at 12:19

3 Answers3

2
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..
}
Libin
  • 16,967
  • 7
  • 61
  • 83
  • 1
    I created a new project with your code (don't forget to add the service to your manifest file) but don't see the advantage to using a service for my network data over a dedicated thread. I liked your idea of passing the context to the service/thread and casting it to the MainActivity. I added that to my project and now can call the Intent from the handler in my MainActivity. So I would say this problem is solved - thanks. – Steve Apr 09 '14 at 19:38
1

Handler class doesn't have a startActivity() method, does it! You can use a static context and store the value of the activity in it in onCreate() then call context.startActivity()

StarDust
  • 846
  • 1
  • 13
  • 26
  • Good idea, I can now launch my Intent directly from the handler or from my runOnUiThread but I'm not sure how to incorporate the two. I'd like to have the runOnUiThread run and provide a way to update the display from various events and then close and return to the MainActivity when complete. – Steve Apr 08 '14 at 23:46
0
Intent mIntent = new Intent(context,YourActivity.class);
mIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(mIntent);
Shaido
  • 27,497
  • 23
  • 70
  • 73
  • 2
    Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Oct 06 '21 at 13:34