result code is zero when the parent activity calls finishActivity() - android

I put setResult(200) in onCreate() at the child activity.
But once I call finishActivity() from the parent, I got resultCode 0.
I Don't know How to explain this situation.
04-25 11:52:55.191: D/TEST(28141): onActivityResult 1000 : 0 : null
The parent is :
public class Main extends Activity {
Button b;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
b = (Button) findViewById(R.id.button1);
b.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
Intent intent = new Intent(Main.this, Popup.class);
startActivityForResult(intent, 1000);
new Timer().schedule(new TimerTask() {
#Override
public void run() {
Main.this.finishActivity(1000);
}
}, 1000);
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.d("TEST", "onActivityResult " + requestCode + " : " + resultCode + " : " + data);
super.onActivityResult(requestCode, resultCode, data);
}
}
Child :
public class Popup extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setResult(200);
}
}
UPDATE :
I got understand that onActivityResult() will be called, when the child activity ends.
And calling finishActivity() won't get the ActivityResult of child activity.
But I want to know correct way to get the ActivityResult(resultCode and intent data) once the child activity is destroyed by parent activity.
And Is there any reason to shouldn't do this like bellow code? (I'm just curious.)
Because It seems work fine.
I coded like this :
public class Main extends Activity {
Button b;
public static boolean closePopup = false;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
b = (Button) findViewById(R.id.button1);
b.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
closePopup = false;
Intent intent = new Intent(Main.this, Popup.class);
startActivityForResult(intent, 1000);
new Timer().schedule(new TimerTask() {
#Override
public void run() {
closePopup = true;
}
}, 1000);
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.d("TEST", "onActivityResult " + requestCode + " : " + resultCode + " : " + data);
super.onActivityResult(requestCode, resultCode, data);
}
}
public class Popup extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mCloseHandler.sendEmptyMessage(0);
}
Handler mCloseHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
if (Main.closePopup == true) {
Popup.this.finish();
} else {
mCloseHandler.sendEmptyMessageDelayed(0, 100);
}
}
};
#Override
public void finish() {
setResult(200);
super.finish();
}
}

In your Popup activity use
if(null != getParent())
getParent().setResult(200);
else
setResult(200);
instead of just setResult(200);
As you need to bind the data to parent activity and set the Result.
UPDATE:
Understand the difference between finish() and finishActivity (int requestCode)
finish ()
Call this when your activity is done and should be closed. The
ActivityResult is propagated back to whoever launched you via
onActivityResult().
finishActivity (int requestCode)
Force finish another activity that you had previously started with
startActivityForResult(Intent, int).
So in your case you are calling finishActivity on Main which is finishing the child activity Popup. Hence you are getting result code as 0 and intent as null (default values) as the data is not propagated back to Main (Parent).
I suggest you to modify your code as follows and try:
Remove timer block ie. call to finishActivity.
call finish() after setResult(200); in Popup.
if(null != getParent())
getParent().setResult(200);
else
setResult(200);
finish();
UPDATE 2 :
Let me explain it further.
When you start the activity with the startActivityForResult() method call, and once the sub-activity ends, the onActivityResult() method on the sub-activity is called and you can perform actions based on the result.
The started activity(sub-activity) can also set a result code which the caller can use to determine if the activity was canceled or not.(Your case)
The sub-activity uses the finish() method to create a new intent and to put data into it. It also sets a result via the setResult() method call.
If the sub-activity is finished, it can send data back to its caller via an Intent. This is done in the finish() method. So you can override finish method as follows.
#Override
public void finish() {
// Prepare data intent
Intent data = new Intent();
// Put data in intent
// Activity finished, return the data
setResult(200, data);
super.finish();
}

Related

How can I pass parameters between two Activity but one must only support the first one

I have an activity that very quickly has to process data and then return to the previous activity, I give an example: I have a MainActivity class that passes information through Intent to another Loader class, this processes the data and sends it back to the MainActivity. I don't know how to put this procedure into practice...
From your MainActivity call the TargetActivity using startActivityForResult()-
For example:
Intent intent = new Intent(this, TargetActivity.class);
intent.putExtra(); // sent your putExtra data here to pass through intent
startActivityForResult(intent, 1000);
In your intent set the data which you want to return back to MainActivity. If you don't want to return back any data then you don't need to set any data.
For example:
In TargetActivity if you want to send back data:
Intent returnIntent = new Intent();
returnIntent.putExtra("result", result);
setResult(Activity.RESULT_OK, returnIntent);
finish();
If you don't want to return data:
Intent returnIntent = new Intent();
setResult(Activity.RESULT_CANCELED, returnIntent);
finish();
Now in your MainActivity class write following code for the onActivityResult() method.
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 1000) {
if(resultCode == Activity.RESULT_OK){
String result=data.getStringExtra("result");
}
if (resultCode == Activity.RESULT_CANCELED) {
// Do your task here.
}
}
}
//do Some work
Intent i = new Intent(this,MainActivity2..class);
startActivityForResult(i,12);
}
In MainActivity2.class
// after your work complete
Intent i =new Intent();
i.putExtra("result",true);// any data you want to pass
setResult(RESULT_OK,i);
After this we handle result
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
switch(requestCode){
case 12:
if(resultCode == Activity.RESULT_OK){// onsuccess do something
boolean isSucces = data.getBooleanExtra("result",false);
if(isSuccess)// perform action
{// show toast}
}
}
}
I find the best to use callbacks.
in Loader:
Create inner class
MyCallback callback;
viod setCallback(MyCallback callback){
this.callback = callback;
}
viod onStop(){
callback = null;
}
interface MyCallback{
void doSomething(Params params);
}
in MainActivity:
implement MyCallback
set reference in onCreate
Loader loader = new Loader();
loader.setCallback(this);
override method doSomething()
#override
void doSomething(Params params){
//do your thing with the params…
}
when the job is done inside Loader call MainActivity:
callback.doSomething(params);
destroy reference inside MainActivity in onStop()
loader.onStop();
By the help of android startActivityForResult() method, you can get result from another activity.
By the help of android startActivityForResult() method, you can send information from one activity to another and vice-versa. The android startActivityForResult method, requires a result from the second activity (activity to be invoked).
In such case, we need to override the onActivityResult method that is invoked automatically when second activity returns result.
MainActivity.java
public class MainActivity extends Activity {
TextView textView1;
Button button1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
textView1=(TextView)findViewById(R.id.textView1);
button1=(Button)findViewById(R.id.button1);
button1.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
Intent intent=new Intent(MainActivity.this,SecondActivity.class);
startActivityForResult(intent, 2);// Activity is started with
requestCode 2
}
});
}
// Call Back method to get the Message form other Activity
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
// check if the request code is same as what is passed here it is 2
if(requestCode==2)
{
String message=data.getStringExtra("MESSAGE");
textView1.setText(message);
}
}
SecondActivity.java
public class SecondActivity extends Activity {
EditText editText1;
Button button1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
editText1=(EditText)findViewById(R.id.editText1);
button1=(Button)findViewById(R.id.button1);
button1.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View arg0) {
String message=editText1.getText().toString();
Intent intent=new Intent();
intent.putExtra("MESSAGE",message);
setResult(Activity.RESULT_OK,intent);
finish();//finishing activity
}
});
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.second, menu);
return true;
}
}

Communication to activity in stack

Let's consider the following situation:
Activity A opens Activity B. Now, A is in activity stack. B downloads any data from the Internet and, basing on that data, we conclude that when user come back to the A ( after press back) A should refresh its content. How to say: B: Hey A in stack, please remember that you should refresh your content. I see that I can set some flag in App instance, but, it seems to be weird.
Consider using startActivityForResult in your ActivityA to call ActivityB, then within your ActivityB, override onBackPressed() method and call setResult() based on downloaded data. Finally back into your ActivityA override onActivityResult(int requestCode, int resultCode, Intent data)
Use the following example as guide:
ActivityA.java
public class ActivityA extends AppCompatActivity {
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Intent intent = new Intent(this, ActivityB.class);
startActivityForResult(intent, 1234);
}
#Override
protected void onActivityResult(final int requestCode, final int resultCode, Intent intent) {
if (1234 == requestCode) {
if (resultCode == Activity.RESULT_OK) {
Toast.makeText(this, "Do action 1", Toast.LENGTH_SHORT).show();
}
if (resultCode == Activity.RESULT_CANCELED) {
Toast.makeText(this, "Do action 2", Toast.LENGTH_SHORT).show();
}
}
}
}
ActivityB.java
public class ActivityB extends AppCompatActivity {
#Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
public void onBackPressed() {
final Intent intent = new Intent();
if (true) { //Replace this condition by yours based on downloaded data
setResult(Activity.RESULT_OK, intent);
} else {
setResult(Activity.RESULT_CANCELED, intent);
}
super.onBackPressed();
}
}
Not that way. Always update Activity A content in the onResume() method of A activity.

onActivityResult doesn't get called by finish() when the parent activity is passed as parameter to an intent in a non-activity class

I've got a class which handles a question sequence. It doesn't extend Activity. In the class there is the method:
public class QuizMaster {
public void startQuiz(Activity activity, Model model) {
//switch - case statement using model
Intent intent = new Intent(activity, QuestionTextActivity.class)
activity.startActivityForResult(intent, requestCode);
//other case statements with other intents
}
}
When I call this method from a working activity with
mQuizMaster.startQuiz(this, mModel);
And I finish() the child activity:
Intent returnIntent = new Intent();
returnIntent.putExtra(ARG_SELECTED_CHECKBOX, checkedBox);
setResult(RESULT_CODE, returnIntent);
finish();
it doesn't execute the parent activity's
#Override
protected void onActivityResult(final int requestCode, final int resultCode, final Intent data) {
Log.d(LOG_TAG, "OnActivityResult called in SignDetailsActivity. Resultcode is: ");
}
But when I execute the
Intent intent = new Intent(activity, QuestionTextActivity.class)
activity.startActivityForResult(intent, requestCode);
in the actual parent activity file, it does execute the onActivityResult method.
Why doesn't the child activity run the onActivityResult in the parent activity if sent with a non-activity class? How do i fix this?
I haven't found anyone with the same problem with executing new Intent() in a non-activity class like this. If there is someone, i didn't use the right search keywords and some others might type in the same as I did and come on this page.
You need to call setResult(int) before call finish(). This is from Activity documentation:
When an activity exits, it can call setResult(int) to return data back
to its parent. It must always supply a result code, which can be the
standard results RESULT_CANCELED, RESULT_OK, or any custom values
starting at RESULT_FIRST_USER. In addition, it can optionally return
back an Intent containing any additional data it wants. All of this
information appears back on the parent's Activity.onActivityResult(),
along with the integer identifier it originally supplied.
Here is my implementation, which worked:
MainActivity.java (parent activity)
public class MainActivity extends AppCompatActivity {
private Sample sample;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn = (Button) findViewById(R.id.button);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
sample = new Sample();
sample.startActivity(MainActivity.this);
}
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Log.d("TEST", "DONE");
}
}
LaunchActivity.java (child activity)
public class LaunchActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_launch);
Button btn = (Button) findViewById(R.id.button2);
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
setIntent(new Intent());
finish();
}
});
}
}
Sample.java (class start activity)
public class Sample {
public Sample () {}
public void startActivity (Activity a) {
Intent it = new Intent(a, LaunchActivity.class);
a.startActivityForResult(it, 0);
}
}

neither onActivityResult( ) nor notifyDataSetChanged() work

I've read many answers on the same question but still I do not understand why my code doesn't work properly. I have a problem with (as I think) exchanging data between two activities.
I have 2 activities - the first contains ListView and an Add button.
When user presses Add new activity starts with the form to fill. When user completes the form he/she presses OK and my first activity starts again (it really does) and it should contain new item (but it doesn't).
This is my first activity:
public class DatabaseActivity extends Activity implements OnClickListener {
ArrayList<Student> students;
StudentDatabaseAdapter adapter;
ListView lvStudentList;
ImageButton imgBtnAdd;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.database);
students = new ArrayList<Student>();
fillArrayList();
adapter = new StudentDatabaseAdapter(this, students);
lvStudentList = (ListView)findViewById(R.id.lvStudentsList);
lvStudentList.setAdapter(adapter);
imgBtnAdd = (ImageButton)findViewById(R.id.imagBtnAddStudent);
imgBtnAdd.setOnClickListener(this);
}
public void fillArrayList() {
//code here
}
#Override
public void onClick(View v) {
Intent intent;
intent = new Intent(this, WizardActivity.class);
startActivity(intent);
}
public void addStudent(Student student) {
students.add(student);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
if(resultCode==RESULT_OK)
{
if(requestCode==2)
{
if (intent == null) {return;}
Student newStudent = new Student(intent.getStringExtra("name"), intent.getStringExtra("surname"),
intent.getStringExtra("last_name"), Integer.parseInt(intent.getStringExtra("year_of_birth")), R.drawable.default_ava);
addStudent(newStudent);
adapter.notifyDataSetChanged();
}
}
}
}
And that's my second activity:
public class WizardActivity extends Activity implements OnClickListener {
EditText etName, etSurname, etLastName, etYearOfBirth;
ImageButton imgBtnOK;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.wizard);
etName = (EditText)findViewById(R.id.etName);
//initializing other edit texts
imgBtnOK = (ImageButton)findViewById(R.id.imgBtnOK);
imgBtnOK.setOnClickListener(this);
}
#Override
public void onClick(View v) {
Intent intent = new Intent(this, DatabaseActivity.class);
intent.putExtra("name", etName.getText().toString());
intent.putExtra("surname", etSurname.getText().toString());
intent.putExtra("last_name", etLastName.getText().toString());
intent.putExtra("year_of_birth", etYearOfBirth.getText().toString());
setResult(RESULT_OK, intent);
startActivityForResult(intent, 2);
}
}
There is nothing wrong with your notifyDataSetChanged(). You seem to be missing the way a secondary activity communicates results back to its caller activity.
DatabaseActivity.onClick() should call startActivityForResult() instead of startActivity().
WizardActivity.onClick() should just call finish() after setResult() (remove the startActivityForResult() call, it doesn't make sense there). Also notice that the intent you provide to setResult() can be an empty intent, i.e. Intent intent = new Intent();
After the secondary activity finishes, DatabaseActivity will be back to foreground and the result will be processed by DatabaseActivity.onActivityResult().
I think you haven't to start new activity in WizardActivity
try this :
WizardActivity
......
#Override
public void onClick(View v) {
Intent intent = new Intent(this, DatabaseActivity.class);
intent.putExtra("name", etName.getText().toString());
intent.putExtra("surname", etSurname.getText().toString());
intent.putExtra("last_name", etLastName.getText().toString());
intent.putExtra("year_of_birth", etYearOfBirth.getText().toString());
setResult(RESULT_OK, intent);
finish();
}
and in
DatabaseActivity
add if you want
#Override
protected void onResume (){
......
adapter.notifyDataSetChanged();
}

Why onStop() is called after onCreate() when starting an Activity within onActivityResult()

I have the following workflow:
startActivityForResult(Activity1)
finish() called on Activity1 (when pushing a button)
onActivityResult() ==> startActivityForResult(Activity2)
===> Activity2.onCreate() is called before Activity1.onStop()
Why I have that?
Edited:
Here is the code:
1- MainActivity.java
// On click on a button
public void start(View view) {
Intent activityIntent = new Intent(this, Activity2.class);
startActivityForResult(activityIntent, 0);
}
protected void onActivityResult(int requestCode,
int resultCode,
Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Intent activityIntent = new Intent(this, Activity3.class);
startActivityForResult(activityIntent, 0);
}
2- Activity2.java
// A button to finish the activity
public void stop(View view) {
finish();
}
#Override
protected void onStop() {
super.onStop();
}
3- Activity3.java
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_activity3);
}
Because of the lifecycle. onStop isn't called until after an Activity is removed from view. So onStop won't be called until something else is blocking it from the user- activity2 in this case. That means Activity2 will already have to have been created, because you can't block another activity if you don't exist.

Categories

Resources