How to Communicate Between Activities

How should I communicate between activities?

Use Bundle please read sth more about it. http://developer.android.com/reference/android/os/Bundle.html

1) Use the Bundle from the Intent:

Intent mIntent = new Intent(this, Example.class);
Bundle extras = mIntent.getExtras();
extras.putString(key, value);

2) Create a new Bundle

Intent mIntent = new Intent(this, Example.class);
Bundle mBundle = new Bundle();
mBundle.extras.putString(key, value);
mIntent.putExtras(mBundle);

3) Use the putExtra() shortcut method of the Intent

Intent mIntent = new Intent(this, Example.class);
mIntent.putExtra(key, value);

Then, in the launched Activity, you would read them via:

String value = getIntent().getExtras().getString(key);

This is the proper way to do that. Another way is SharedPreferences. http://developer.android.com/training/basics/data-storage/shared-preferences.html

How to communicate between activities in Android

The problem is that I was thinking in the "Desktop" mode of developing java (e.g. with Swing) in which the windows are persistent objects, unlike in Android where Activities come and go at all the time.

My solution is to make the LoggingReceiver constructor private and to make LoggingReceiver its own factory with a singleton pattern (i.e. with a getInstance() method returning the sole static instance in existence). Then both the SettingsActivity and the TextViewActivity can access it. The former to do its business of linking the receiver to the right MIDI source, the latter to register itself as the ScopeLogger. Obviously I need also a setScopeLogger() (called by TextViewActivity in its onCreate()) and some null checks in the LoggingReceiver.onSend() if mLogger is not set, since the original code assumed that would happen in the constructor. But this part "business as usual" in java.

Android communication between Activities without onActivityResult

What about using BroadCastReceiver?

Basically you send a broadcast and every activity that is registered to receive that broadcast will receive that broadcast will receive the message in onReceive

First of all declare in the manifesto what you are going to listen for, something like:

   <receiver android:name=".TestBroadCast”>
<intent-filter>
<action android:name="io.test.TEST"/>
</intent-filter>
</receiver>

Than simply extend BroadCastReceiver

public class TestBroadCastReceiver extends BroadcastReceiver {

@Override
public void onReceive(Context context, Intent intent) {
//TODO: Handle the Intent received.

}

Example of how to send a broadcast:

   public static final String INTENT_ACTION = "io.test.TEST";
public static final String INTENT_EXTRA = "someData";

Intent intent = new Intent();
intent.setAction(INTENT_ACTION);
intent.putExtra(INTENT_EXTRA,"test");
sendBroadcast(intent);

And you will get the Intent and than you can handle it as you wish :)!

UPDATE ~ Registering from code instead of manifesto

To avoid registering the service from the Manifesto you can do it from the code, with a code similar to the following listing:

IntentFilter intentFilter = new IntentFilter("io.test.TEST");
TestBroadCastReceiver mReceiver = new TestBroadCastReceiver();
context.registerReceiver(mReceiver, intentFilter);

P.S.
I suggest you using LocalBroadcastReceiver if you don't need other applications to be able to send results insted of the common BroadcastReceiver for security reasons

How to communicate between Activity and Threads created by other Actvity

A WeakReference probably isn't what you want, here. That is, presuming that your Thread object either does not terminate, or somehow maintains some information useful to Activity A after Activity B has stopped. If you use a WeakReference, it might become "null" as soon as Activity B ends, and the thread terminates. Just use regular old strong references. It'll ensure T1, and the information contains, continues to exist until you're done with it.

public class ActivityB extends Activity
{
private T1 t1;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
t1 = startMyThread();
}

@Override
public void onBackPressed()
{
ActivityA.tempT1 = t1;

//This technique presumes that Activity A is guaranteed to resume after a
//back button press, based on the arrangement of your backstack, etc. If
//Activity A is started via some other means (e.g., an explicit startActivity(),
//finish(), etc.), then this reference will have to be set prior to
//that call, as well, in order to establish the appropriate "happens before" relationship.
//If you fail to ensure that Activity A resumes after this point, you will
//risk a memory leak.

super.onBackPressed();
}
}

public class ActivityA extends Activity
{
public static T1 tempT1 = null;
private T1 t1;

@Override
public void onResume()
{
super.onResume();
if(tempT1 == null)
{
//Apparently, Activity B hasn't executed yet. Provide the user with a button to start it.
}
else
{
t1 = tempT1;
tempT1 = null; //To avoid a memory leak

//We just retrieved the reference that Activity B left for us.
//Now, change UI states so that the user can see information about t1.
}
}
}

Communication between Activity and Service

I have implemented communication between Activity and Service using Bind and Callbacks interface.

For sending data to the service I used Binder which retruns the Service instace to the Activity, and then the Activity can access public methods in the Service.

To send data back to the Activity from the Service, I used Callbacks interface like you are using when you want to communicate between Fragment and Activity.

Here is some code samples for each:
The following example shows Activity and Service bidirectional relationship:
The Activity has 2 buttons:
The first button will start and stop the service.
The second button will start a timer which runs in the service.

The service will update the Activity through callback with the timer progress.

My Activity:

    //Activity implements the Callbacks interface which defined in the Service  
public class MainActivity extends ActionBarActivity implements MyService.Callbacks{

ToggleButton toggleButton;
ToggleButton tbStartTask;
TextView tvServiceState;
TextView tvServiceOutput;
Intent serviceIntent;
MyService myService;
int seconds;
int minutes;
int hours;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
serviceIntent = new Intent(MainActivity.this, MyService.class);
setViewsWidgets();
}

private void setViewsWidgets() {
toggleButton = (ToggleButton)findViewById(R.id.toggleButton);
toggleButton.setOnClickListener(btListener);
tbStartTask = (ToggleButton)findViewById(R.id.tbStartServiceTask);
tbStartTask.setOnClickListener(btListener);
tvServiceState = (TextView)findViewById(R.id.tvServiceState);
tvServiceOutput = (TextView)findViewById(R.id.tvServiceOutput);

}

private ServiceConnection mConnection = new ServiceConnection() {

@Override
public void onServiceConnected(ComponentName className,
IBinder service) {
Toast.makeText(MainActivity.this, "onServiceConnected called", Toast.LENGTH_SHORT).show();
// We've binded to LocalService, cast the IBinder and get LocalService instance
MyService.LocalBinder binder = (MyService.LocalBinder) service;
myService = binder.getServiceInstance(); //Get instance of your service!
myService.registerClient(MainActivity.this); //Activity register in the service as client for callabcks!
tvServiceState.setText("Connected to service...");
tbStartTask.setEnabled(true);
}

@Override
public void onServiceDisconnected(ComponentName arg0) {
Toast.makeText(MainActivity.this, "onServiceDisconnected called", Toast.LENGTH_SHORT).show();
tvServiceState.setText("Service disconnected");
tbStartTask.setEnabled(false);
}
};

View.OnClickListener btListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
if(v == toggleButton){
if(toggleButton.isChecked()){
startService(serviceIntent); //Starting the service
bindService(serviceIntent, mConnection, Context.BIND_AUTO_CREATE); //Binding to the service!
Toast.makeText(MainActivity.this, "Button checked", Toast.LENGTH_SHORT).show();
}else{
unbindService(mConnection);
stopService(serviceIntent);
Toast.makeText(MainActivity.this, "Button unchecked", Toast.LENGTH_SHORT).show();
tvServiceState.setText("Service disconnected");
tbStartTask.setEnabled(false);
}
}

if(v == tbStartTask){
if(tbStartTask.isChecked()){
myService.startCounter();
}else{
myService.stopCounter();
}
}
}
};

@Override
public void updateClient(long millis) {
seconds = (int) (millis / 1000) % 60 ;
minutes = (int) ((millis / (1000*60)) % 60);
hours = (int) ((millis / (1000*60*60)) % 24);

tvServiceOutput.setText((hours>0 ? String.format("%d:", hours) : "") + ((this.minutes<10 && this.hours > 0)? "0" + String.format("%d:", minutes) : String.format("%d:", minutes)) + (this.seconds<10 ? "0" + this.seconds: this.seconds));
}
}

And here is the service:

 public class MyService extends Service {
NotificationManager notificationManager;
NotificationCompat.Builder mBuilder;
Callbacks activity;
private long startTime = 0;
private long millis = 0;
private final IBinder mBinder = new LocalBinder();
Handler handler = new Handler();
Runnable serviceRunnable = new Runnable() {
@Override
public void run() {
millis = System.currentTimeMillis() - startTime;
activity.updateClient(millis); //Update Activity (client) by the implementd callback
handler.postDelayed(this, 1000);
}
};

@Override
public int onStartCommand(Intent intent, int flags, int startId) {

//Do what you need in onStartCommand when service has been started
return START_NOT_STICKY;
}

@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
//returns the instance of the service
public class LocalBinder extends Binder{
public MyService getServiceInstance(){
return MyService.this;
}
}

//Here Activity register to the service as Callbacks client
public void registerClient(Activity activity){
this.activity = (Callbacks)activity;
}

public void startCounter(){
startTime = System.currentTimeMillis();
handler.postDelayed(serviceRunnable, 0);
Toast.makeText(getApplicationContext(), "Counter started", Toast.LENGTH_SHORT).show();
}

public void stopCounter(){
handler.removeCallbacks(serviceRunnable);
}

//callbacks interface for communication with service clients!
public interface Callbacks{
public void updateClient(long data);
}
}

Communication between two activities using interface not working as expected

Your problem is that you are calling onReturnedToActivity() on a new instance of MainActivity, not the one you started from or the one that you will return to.

There are several ways to share data between activities, one is to use startActivityForResult().

I think your problem however is that Activity1 will be stopped, so you can't really send it data from Activity2. You can however start Activity2 with startActivityForResult and return a result.
Here is the example from the documentation.

Starting the activity.

const val PICK_CONTACT_REQUEST = 1  // The request code
...
private fun pickContact() {
Intent(Intent.ACTION_PICK, Uri.parse("content://contacts")).also { pickContactIntent ->
pickContactIntent.type = Phone.CONTENT_TYPE // Show user only contacts w/ phone numbers
startActivityForResult(pickContactIntent, PICK_CONTACT_REQUEST)
}
}

Getting the returned data.

override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent) {
// Check which request we're responding to
if (requestCode == PICK_CONTACT_REQUEST) {
// Make sure the request was successful
if (resultCode == Activity.RESULT_OK) {
// The user picked a contact.
// The Intent's data Uri identifies which contact was selected.

// Do something with the contact here (bigger example below)
}
}
}

Other schemes include a Global Singleton, launching activities with Intents, or using SharedPreferences writting data in one activity and then reading it back in another.
If you do a search on android share data between activities You will see there are various options on the best way to accomplish this.

Communication between two Activities?

You can use Intent with extra parameters.
For example, on ToursActivity.java

Intent intent = new Intent(ToursActivity.this, MapActivity.class);
intent.putExtra("lat", latitude);
intent.putExtra("long", longitude);
startActivity(intent);

Then you can get get these parameters on onCreate() method of MapActivity.java:

Intent intent = getIntent();
long latitude = intent.getLongExtra("lat", 0);
long longitutde = intent.getLongExtra("long", 0);

Communicating between Activities and Fragments when using Navigation Architecture Component

You can use the LiveData data holder class for such purposes.

Here is an article explaining both Fragment <--> Fragment communication and Activity <--> Fragment communication.



Related Topics



Leave a reply



Submit