I am very confused on how to send data between a fragment and an activity, since I found how to send data between activities and even fragments but not from an activity that is called from a fragment (which I think is different because I tried those methods and they didn't work).
In my case I want to start a new activity from a fragment and send some data (time from a timepicker) back to the fragment that started the activity.
So basically my question is,
How do I start a new Activity from a class that extends fragment?
And then, How do send data back to the fragment.
to start activity from fragment which deliver you some result back; you can use startActivityForResult :
For ex:
public class YourFragment extends Fragment {
private static final int REQUEST_GET_DATA_FROM_SOME_ACTIVITY = 1;
//start activity for result
....
Intent intent = new Intent(getActivity(),SomeActivity.class);
startActivityForResult(intent,REQUEST_GET_DATA_FROM_SOME_ACTIVITY)
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == REQUEST_GET_DATA_FROM_SOME_ACTIVITY && resultCode == Activity.RESULT_OK) {
Bundle extras = data.getExtras();
//get data from extras
}
}
}
and inside your activity
public class SomeActivity extends Activity {
//complete process and deliver result
........
Intent resultIntent = new Intent();
resultIntent .putExtra("extra","put anything");
setResult(Activity.RESULT_OK, resultIntent);
finish();
}
}
Declare a field in fragment (you will see usage below)
private static int RC_SOME_ACTIVITY = 101;
To start activity from fragment
startActivityForResult(new Intent(getContext(), SomeActivity.class), RC_SOME_ACTIVITY);
In the the started activity to send data back
Intent data = new Intent();
// add data to intent
setResult(RESULT_OK, data);
finish();
In your fragment you will need to override onActivityResult to extract data in
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == RC_SOME_ACTIVITY && resultCode == RESULT_OK) {
// extract data
}
}
Related
I have a helper class that takes an activity and does stuff with it.
public MyClass(AppCompatActivity activity, Callbacks callbacks) {
this.activity = activity;
this.callbacks = callbacks;
}
What I do in this class is basically call other activies/libraries in a certain order and use the results. I put this in a helper class so that I can easily reuse the code.
This is the problem I have:
With the new ActivityResultLauncher it's easy to "modularize" what I need:
ActivityResultLauncher<Intent> chooseImageLauncher = activity.registerForActivityResult(...);
...
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("image/*");
chooseImageLauncher.launch(intent);
And in the implementation of chooseImageLauncher I do whatever I want next. In this case, I will call a library.
The problem is that the library I'm calling was last updated 2020 and doesn't provide a method for an ActivityResultLauncher. It only supports the old way with onActivityResult:
MyLibrary.init().start(activity);
And the result can be caught like this:
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
if (requestCode == MyLibrary.REQUEST_CODE && resultCode == RESULT_OK) {
...
}
}
But I can only implement that in each activity itself. How can I implement here?
You could add a private class inside your helper class that extends Activity. This way you can still catch the value emitted by your library.
private class MyLibraryActivityWrapper extends AppCompatActivity {
public void init() {
MyLibrary.init().start(activity);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == MyLibrary.REQUEST_CODE && resultCode == RESULT_OK) {
}
}
}
I have a plane java class which accepts an Activity in constructor. Now with that activity I am starting another activity for some permissions. Now I want to wait for this activity to complete before proceeding next.
public final class Test{
#NonNull
private final Activity activity;
public Test(final Activity activity) {
this.activity = activity;
}
public void initialize() {
try {
if(isEnabled) {
this.activity.startActivity(new Intent(this.activity, CheckPermissionsActivity.class));
}
FileUtils.readFile(Constants.XX+ Constants.YY);
}
I want to make this readFile method run after the CheckPermissionsActivity is complete. How to make the main thread wait?
if you have a separate class for permission checking then do something like this.
NOTE: I'm only explaining the basic concept. do the changes according to your requirements.
Intent intent = new Intent(this, CheckPermissionsActivity.class);
startActivityForResult(intent, 101);//101=requestCode
// write this according to your requirements in CheckPermissionsActivity
Intent i = new Intent();
i.putExtra("result", mString);
if (mString.length() > 2) {
setResult(Activity.RESULT_OK, i);
} else {
setResult(Activity.RESULT_CANCELED, i);
}
finish();
// in your main activity use this callback and use in your Test class
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 101 && data != null) {
// write your code here
}
}
I have an adapter inside a fragment, in this adapter I am running an activityForResult to an activity.
Calling the adapter from the Fragment
mAdapClinicSchedule = new ClinicScheduleAdapter(getContext(),mScheduleList);
mLvClinicsSchedules.setAdapter(mAdapClinicSchedule);
Adapter's constructor:
public ClinicScheduleAdapter(Context context, ArrayList<String> mScheduleList) {
this.context = context;
this.mScheduleList = mScheduleList;
}
The call to the startActivityForResult from the adapter
case R.id.tvDaysClinicSchedule:
Intent intent = new Intent(context, ScheduleDaysActivity.class);
((Activity)context).startActivityForResult(intent, 2);
break;
The setResult from the activity
case R.id.tvSelectDays:
checkDaysSelected();
Intent returnIntent = new Intent();
returnIntent.putExtra("monday", mondaySelected);
returnIntent.putExtra("tuesday", tuesdaySelected);
returnIntent.putExtra("wednesday", wednesdaySelected);
returnIntent.putExtra("thursday", thursdaySelected);
returnIntent.putExtra("friday", fridaySelected);
returnIntent.putExtra("saturday", saturdaySelected);
returnIntent.putExtra("sunday", sundaySelected);
setResult(Activity.RESULT_OK, returnIntent);
finish();
break;
Creating an onActivityResult interface
public interface OnActivityResult {
void onActivityResult(int requestCode, int resultCode, Intent data);
}
That implements the adapter:
public class ClinicScheduleAdapter
extends BaseAdapter implements View.OnClickListener, OnActivityResult { ... }
In the fragment it overrite the onActivityResult
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
mAdapClinicSchedule.onActivityResult(requestCode, resultCode, data);
//super.onActivityResult(requestCode, resultCode, data);
}
But in the adapter, it does not show the toast, I do not know what I can be doing wrong
public void onActivityResult (int requestCode, int resultCode, Intent data) {
if (requestCode == 2) {
if (resultCode == Activity.RESULT_OK) {
Toast.makeText(context, "it worked!", Toast.LENGTH_LONG).show();
}
}
}
From the android documentation:
Of course, the activity that responds must be designed to return a result. When it does, it sends the result as another Intent object. Your activity receives it in the onActivityResult() callback.
Although, if I remember correctly, onActivityResult() will get called on whatever started the activity for result. So if you use the activity to start your new intent, then the activity will receive the result call. This means if you want the fragment to handle it, you'll need to call startActivityForResult(...) on the fragment rather than the activity
fragment source
I have activity with one fragment, and then that fragment call some activity which that activity will give some value into first activity. i use onActivityResult but i don't know why resultCode always 0 and data always zero,.
on Activity One i have
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Log.d(TAG, "onActivityResult: "+ requestCode +" "+resultCode+" "+data);
}
Activity one have some fragmentX which call activity two
private final int REQUEST_CODE = 10;
private void start (){
Intent intent = new Intent(getContext(),Main2Activity.class);
intent.putExtra("xxx","test1");
getActivity().startActivityForResult(intent,REQUEST_CODE);
}
then in Activity Two, when i touch onBackpress, will pass some value.
public class Main2Activity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
}
#Override
public void onBackPressed() {
super.onBackPressed();
Intent intent = getIntent().putExtra("yyy","test2");
setResult(RESULT_OK,intent);
}
}
but, i don't know why, onActivityResult i can't get the data.
my final purpose is, i want to setArgument that data to fragmentX.
1.You can call onActivityResult in the fragment
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Log.d(TAG, "onActivityResult: "+ requestCode +" "+resultCode+" "+data);
}
2.Use super.onBackPressed(); after setResult in your method
#Override
public void onBackPressed() {
Intent intent = getIntent().putExtra("yyy","test2");
setResult(RESULT_OK,intent);
super.onBackPressed();
}
In first activity write the below code:
1st method:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
for (Fragment fragment : getSupportFragmentManager().getFragments()) {
fragment.onActivityResult(requestCode, resultCode, data);
}
}
In Fragment
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// In fragment write your logic here
}
2nd method: (I didn't try but as per doc may be this is one of the reason try once) if it will not work go 1st method its 100 percent solution
Here when your calling second activity using getContext()
getContext() - Returns the context view only current running activity.
getActivity()- Return the Activity this fragment is currently associated with.
Try instead of getContext() use getActivity() when you calling intent to next activity
Ex:
private final int REQUEST_CODE = 10;
Intent intent = new Intent(getActivity(),Main2Activity.class);
intent.putExtra("xxx","test1");
getActivity().startActivityForResult(intent,REQUEST_CODE);
For start new activity
private final int REQUEST_CODE = 10;
private void start (){
Intent intent = new Intent(getContext(),Main2Activity.class);
intent.putExtra("xxx","test1");
getActivity().startActivityForResult(intent,REQUEST_CODE);
}
From Second activity
public class Main2Activity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
}
#Override
public void onBackPressed() {
super.onBackPressed();
Intent intent = getIntent().putExtra("yyy","test2");
setResult(10,intent);
}
}
you have to set the integer code using which you have started second activity. you have started second activity with the code "10".so use the same value when you setResult(10,intent);
onActivityResult you need to check Request code
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode==10){
if(data!=null)
{
//you have to manage your own list of fragments for activity because getSupportFragmentManager().getFragments() is deprecated now.
//Send data to fragments
if (arrayFragments != null) {
for (Fragment fragment : arrayFragments) {
fragment.onActivityResult(requestCode, resultCode, data);
}
}
}
}
}
Remember you have to manage your own list of fragments using ArrayList or HashMap.
Hope this will help you if you need any other help inform me.
if you wants to send return data in onActivityResult then you should use super.onBackPressed() after data set in setResult() method
example:
#Override
public void onBackPressed() {
val intent = Intent()
intent.putExtra("IsReturnData", true)
setResult(RESULT_OK,intent);
super.onBackPressed(); //write this line at the end of method
}
I have two activities: main activity and child activity.
When I press a button in the main activity, the child activity is launched.
Now I want to send some data back to the main screen. I used the Bundle class, but it is not working. It throws some runtime exceptions.
Is there any solution for this?
There are a couple of ways to achieve what you want, depending on the circumstances.
The most common scenario (which is what yours sounds like) is when a child Activity is used to get user input - such as choosing a contact from a list or entering data in a dialog box. In this case, you should use startActivityForResult to launch your child Activity.
This provides a pipeline for sending data back to the main Activity using setResult. The setResult method takes an int result value and an Intent that is passed back to the calling Activity.
Intent resultIntent = new Intent();
// TODO Add extras or a data URI to this intent as appropriate.
resultIntent.putExtra("some_key", "String data");
setResult(Activity.RESULT_OK, resultIntent);
finish();
To access the returned data in the calling Activity override onActivityResult. The requestCode corresponds to the integer passed in the startActivityForResult call, while the resultCode and data Intent are returned from the child Activity.
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch(requestCode) {
case (MY_CHILD_ACTIVITY) : {
if (resultCode == Activity.RESULT_OK) {
// TODO Extract the data returned from the child Activity.
String returnValue = data.getStringExtra("some_key");
}
break;
}
}
}
Activity 1 uses startActivityForResult:
startActivityForResult(ActivityTwo, ActivityTwoRequestCode);
Activity 2 is launched and you can perform the operation, to close the Activity do this:
Intent output = new Intent();
output.putExtra(ActivityOne.Number1Code, num1);
output.putExtra(ActivityOne.Number2Code, num2);
setResult(RESULT_OK, output);
finish();
Activity 1 - returning from the previous activity will call onActivityResult:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == ActivityTwoRequestCode && resultCode == RESULT_OK && data != null) {
num1 = data.getIntExtra(Number1Code);
num2 = data.getIntExtra(Number2Code);
}
}
UPDATE:
Answer to Seenu69's comment, In activity two,
int result = Integer.parse(EditText1.getText().toString())
+ Integer.parse(EditText2.getText().toString());
output.putExtra(ActivityOne.KEY_RESULT, result);
Then in activity one,
int result = data.getExtra(KEY_RESULT);
Sending Data Back
It helps me to see things in context. Here is a complete simple project for sending data back. Rather than providing the xml layout files, here is an image.
Main Activity
Start the Second Activity with startActivityForResult, providing it an arbitrary result code.
Override onActivityResult. This is called when the Second Activity finishes. You can make sure that it is actually the Second Activity by checking the request code. (This is useful when you are starting multiple different activities from the same main activity.)
Extract the data you got from the return Intent. The data is extracted using a key-value pair.
MainActivity.java
public class MainActivity extends AppCompatActivity {
private static final int SECOND_ACTIVITY_REQUEST_CODE = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
// "Go to Second Activity" button click
public void onButtonClick(View view) {
// Start the SecondActivity
Intent intent = new Intent(this, SecondActivity.class);
startActivityForResult(intent, SECOND_ACTIVITY_REQUEST_CODE);
}
// This method is called when the second activity finishes
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// Check that it is the SecondActivity with an OK result
if (requestCode == SECOND_ACTIVITY_REQUEST_CODE) {
if (resultCode == RESULT_OK) {
// Get String data from Intent
String returnString = data.getStringExtra("keyName");
// Set text view with string
TextView textView = (TextView) findViewById(R.id.textView);
textView.setText(returnString);
}
}
}
}
Second Activity
Put the data that you want to send back to the previous activity into an Intent. The data is stored in the Intent using a key-value pair.
Set the result to RESULT_OK and add the intent holding your data.
Call finish() to close the Second Activity.
SecondActivity.java
public class SecondActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
}
// "Send text back" button click
public void onButtonClick(View view) {
// Get the text from the EditText
EditText editText = (EditText) findViewById(R.id.editText);
String stringToPassBack = editText.getText().toString();
// Put the String to pass back into an Intent and close this activity
Intent intent = new Intent();
intent.putExtra("keyName", stringToPassBack);
setResult(RESULT_OK, intent);
finish();
}
}
Other notes
If you are in a Fragment it won't know the meaning of RESULT_OK. Just use the full name: Activity.RESULT_OK.
See also
Fuller answer that includes passing data forward
Naming Conventions for the Key String
FirstActivity uses startActivityForResult:
Intent intent = new Intent(MainActivity.this,SecondActivity.class);
startActivityForResult(intent, int requestCode); // suppose requestCode == 2
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 2)
{
String message=data.getStringExtra("MESSAGE");
}
}
On SecondActivity call setResult() onClick events or onBackPressed()
Intent intent=new Intent();
intent.putExtra("MESSAGE",message);
setResult(Activity.RESULT_OK, intent);
Call the child activity Intent using the startActivityForResult() method call
There is an example of this here:
http://developer.android.com/training/notepad/notepad-ex2.html
and in the "Returning a Result from a Screen" of this:
http://developer.android.com/guide/faq/commontasks.html#opennewscreen
UPDATE Mar. 2021
As in Activity v1.2.0 and Fragment v1.3.0, the new Activity Result APIs have been introduced.
The Activity Result APIs provide components for registering for a result, launching the result, and handling the result once it is dispatched by the system.
So there is no need of using startActivityForResult and onActivityResult anymore.
In order to use the new API, you need to create an ActivityResultLauncher in your origin Activity, specifying the callback that will be run when the destination Activity finishes and returns the desired data:
private val intentLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
result.data?.getStringExtra("key1")
result.data?.getStringExtra("key2")
result.data?.getStringExtra("key3")
}
}
and then, launching your intent whenever you need to:
intentLauncher.launch(Intent(this, YourActivity::class.java))
And to return data from the destination Activity, you just have to add an intent with the values to return to the setResult() method:
val data = Intent()
data.putExtra("key1", "value1")
data.putExtra("key2", "value2")
data.putExtra("key3", "value3")
setResult(Activity.RESULT_OK, data)
finish()
For any additional information, please refer to Android Documentation
I have created simple demo class for your better reference.
FirstActivity.java
public class FirstActivity extends AppCompatActivity {
private static final String TAG = FirstActivity.class.getSimpleName();
private static final int REQUEST_CODE = 101;
private Button btnMoveToNextScreen;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
btnMoveToNextScreen = (Button) findViewById(R.id.btnMoveToNext);
btnMoveToNextScreen.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent mIntent = new Intent(FirstActivity.this, SecondActivity.class);
startActivityForResult(mIntent, REQUEST_CODE);
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == RESULT_OK){
if(requestCode == REQUEST_CODE && data !=null) {
String strMessage = data.getStringExtra("keyName");
Log.i(TAG, "onActivityResult: message >>" + strMessage);
}
}
}
}
And here is SecondActivity.java
public class SecondActivity extends AppCompatActivity {
private static final String TAG = SecondActivity.class.getSimpleName();
private Button btnMoveToPrevious;
private EditText editText;
#Override
protected void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
editText = (EditText) findViewById(R.id.editText);
btnMoveToPrevious = (Button) findViewById(R.id.btnMoveToPrevious);
btnMoveToPrevious.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
String message = editText.getEditableText().toString();
Intent mIntent = new Intent();
mIntent.putExtra("keyName", message);
setResult(RESULT_OK, mIntent);
finish();
}
});
}
}
In first activity u can send intent using startActivityForResult() and then get result from second activity after it finished using setResult.
MainActivity.class
public class MainActivity extends AppCompatActivity {
private static final int SECOND_ACTIVITY_RESULT_CODE = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
// "Go to Second Activity" button click
public void onButtonClick(View view) {
// Start the SecondActivity
Intent intent = new Intent(this, SecondActivity.class);
// send intent for result
startActivityForResult(intent, SECOND_ACTIVITY_RESULT_CODE);
}
// This method is called when the second activity finishes
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// check that it is the SecondActivity with an OK result
if (requestCode == SECOND_ACTIVITY_RESULT_CODE) {
if (resultCode == RESULT_OK) {
// get String data from Intent
String returnString = data.getStringExtra("keyName");
// set text view with string
TextView textView = (TextView) findViewById(R.id.textView);
textView.setText(returnString);
}
}
}
}
SecondActivity.class
public class SecondActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
}
// "Send text back" button click
public void onButtonClick(View view) {
// get the text from the EditText
EditText editText = (EditText) findViewById(R.id.editText);
String stringToPassBack = editText.getText().toString();
// put the String to pass back into an Intent and close this activity
Intent intent = new Intent();
intent.putExtra("keyName", stringToPassBack);
setResult(RESULT_OK, intent);
finish();
}
}
All these answers are explaining the scenario of your second activity needs to be finish after sending the data.
But in case if you don't want to finish the second activity and want to send the data back in to first then for that you can use BroadCastReceiver.
In Second Activity -
Intent intent = new Intent("data");
intent.putExtra("some_data", true);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
In First Activity-
private BroadcastReceiver tempReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// do some action
}
};
Register the receiver in onCreate()-
LocalBroadcastManager.getInstance(this).registerReceiver(tempReceiver,new IntentFilter("data"));
Unregister it in onDestroy()
Another way of achieving the desired result which may be better depending on your situation is to create a listener interface.
By making the parent activity listen to an interface that get triggered by the child activity while passing the required data as a parameter can create a similar set of circumstance
There are some ways of doing this.
1. by using the startActivityForResult() which is very well explained in the above answers.
by creating the static variables in your "Utils" class or any other class of your own. For example i want to pass studentId from ActivityB to ActivityA.First my ActivityA is calling the ActivityB. Then inside ActivityB set the studentId (which is a static field in Utils.class).
Like this Utils.STUDENT_ID="1234"; then while comming back to the ActivityA use the studentId which is stored in Utils.STUDENT_ID.
by creating a getter and setter method in your Application Class.
like this:
public class MyApplication extends Application {
private static MyApplication instance = null;
private String studentId="";
public static MyApplication getInstance() {
return instance;
}
#Override
public void onCreate() {
super.onCreate();
instance = this;
}
public void setStudentId(String studentID){
this.studentId=studentID;
}
public String getStudentId(){
return this.studentId;
}
}
so you are done . just set the data inside when u are in ActivityB and after comming back to ActivityA , get the data.
Just a small detail that I think is missing in above answers.
If your child activity can be opened from multiple parent activities then you can check if you need to do setResult or not, based on if your activity was opened by startActivity or startActivityForResult. You can achieve this by using getCallingActivity(). More info here.
Use sharedPreferences and save your data and access it from anywhere in the application
save date like this
SharedPreferences sharedPreferences = getPreferences(MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(key, value);
editor.commit();
And recieve data like this
SharedPreferences sharedPreferences = getPreferences(MODE_PRIVATE);
String savedPref = sharedPreferences.getString(key, "");
mOutputView.setText(savedPref);