setText after ActivityResult force closes with NullPointerException - android

I created a (very simple) class wich gets a string value from an intent. If i create a Toast with the result, it's oké. But when i try to set the text of the TextView the program stops with a NullPointerException. Eclipse gives a warning on:
TextView debugView = (TextView) findViewById(R.id.debugView);
The local variable debugView is never read
I hope someone has an idea.
public class Main extends Activity {
TextView debugView;
Button chooseOne;
Intent myIntent;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
TextView debugView = (TextView) findViewById(R.id.debugView);
//debugView.setText("Hola supermercado!");
Button ChooseOne = (Button) findViewById(R.id.chooseOne);
ChooseOne.setOnClickListener(new OnClickListener() {
public void onClick(View arg0) {
myIntent = new Intent(Main.this, ResultFromSelection.class);
myIntent.putExtra("sampleData", "This is Sample Data");
startActivityForResult(myIntent, 1);
}
});
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (resultCode == RESULT_OK && requestCode == 1) {
String msg = data.getStringExtra("returnedData");
//Toast.makeText(Main.this, ""+msg, Toast.LENGTH_LONG).show();
debugView.setText(""+msg);
}
}
}
Where i get the result from:
public class ResultFromSelection extends Activity {
Intent intent;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.selection);
Intent intent= getIntent();
intent.putExtra("returnedData", "A Value");
setResult(RESULT_OK, intent);
finish();
}
}
XML From Main:
Logcat doesn't give me any info at all, just the nullPointer. I can't post a logcat right now because the emulator gives me some more trouble (after this briljant update >:(). Will try again when needed.

You are creating the debugView inside your oncreate which makes it a variable that only can be used there. Change
TextView debugView = (TextView) findViewById(R.id.debugView);
to
this.debugView = (TextView) findViewById(R.id.debugView);

The debugView is not available in the onActivityResult. Do you also have a field in the class called debugView? Because you're declaring a local variable called debugView in onCreate.

You declared debugView in one method, and then tried to reference it in another. You need to move the variable declaration outside the onCreate() method.

Related

TextView, ListView is null then returning in onActivityResult

In MainActivity i have a TextView. It gets instantiated in onCreate().
I press a button and begin another activity calling startActivityForResult().
Then I return to the MainActivity and onActivityResult() is called. In this method I want to update the TextView with new text, but it's null, resulting to NullPointerException.
I would like to note that this error does not always occur, but sometimes and somewhere about 2% of my users.
Why may it happen?
Should I use onSaveInstanceState()/onRestoreInstanceState()?
p.s. I have read it is better updating a textview in onResume() or onRestart() method because TextView (and rest of Views) restores its value in onResume() method, but this method comes after onActivityResult(), so TextView may become null.
public class MyActivity extends Activity {
TextView tv;
Button btn;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
tv = (TextView) findViewById(R.id.myTextVIew);
tv.setText("Text1");
} // end onCreate
protected void onActivityResult(int requestCode, int resultCode, Intent resultData) {
if (resultCode == RESULT_OK) {
tv.setText("Text2");
}
}
public void onClickBtn(View v)
{
Intent i = new Intent(MyActivity.this, SecondActivity.class);
startActivityForResult(i, 0);
} }

Intent data not returning

I have been looking through many other answers, with the most complete one being this answer: Sending data back to the Main Activity in android. Following these the best I can, I am not seeing any data when I try and get the string from the intent that is returned.
Here is the main activity which calls the second activity with startActivityForRestult(), and would then display the string from intent in a textview.
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Bundle extras = getIntent().getExtras();
if (extras != null) {
String myStr = extras.getString("TASK");
TextView tv = (TextView) findViewById(R.id.taskList);
tv.setText(myStr);
}
}//onActivityResult
/** Called when the user clicks the Add Task button */
public void addTask(View view) {
Intent intent = new Intent(this, AddTaskActivity.class);
startActivityForResult(intent, 1);
}
}
And the second activity that I am trying to return the variable string task to the main activity.
Code truncated to just the intent return section:
String task = "foo";
Intent returnIntent = getIntent();
returnIntent.putExtra("TASK", task);
setResult(Activity.RESULT_OK,returnIntent);
finish();
From everything I have read, this should be all that is involved, but I have missed something, as nothing shows up in the first activity, and I am unclear why.
Use the intent passed into onActivityResult called data in your example, not getIntent which gets the intent passed in when the activity was created.
I.E.
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
Bundle extras = data.getExtras(); //THIS IS THE LINE I CHANGED
if (extras != null) {
String myStr = extras.getString("TASK");
TextView tv = (TextView) findViewById(R.id.taskList);
tv.setText(myStr);
}
}//onActivityResult
In onActivityResult() method you didnot get the data by using the getIntent() method.
onActivityResult() method has 3 arguments.
Request code passed to startActivityForResult() method.
Result code specified by the second activity. This is either RESULT_OK if the operation was successful or RESULT_CANCELED if the user backed out or the operation failed for some reason.
An Intent that carries the result data.
So, from the third argument, you can get the data.

Use same instance of Activity

I am making a game, and i want to use the same Activity every time when a user fails the Level and i don't wanna create all the Views every time when the FailedActivity is shown.
For example i have Level1Activity:
public class Level1Activity extends Activity{
private static final int REQUEST_FAIL_ACTIVITY = 10;
private static final int RESULT_RETRY_LEVEL= 11;
public void onCreate(Bundle savedIntanceState){
...
}
public void showFailedActivity(){
Intent intent = new Intent(this, FailedActivity);
intent.putExtra("text1", "You failed! You made only 50 points");
intent.putExtra("text2", "Try again later");
startActivityForResult(intent, REQUEST_FAIL_ACTIVITY );
}
protected void onActivityResult(int requestCode, int resultCode, Intent data){
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == REQUEST_FAIL_ACTIVITY ){
if(resultCode == RESULT_BACK){
finish();
}else if(resultCode == RESULT_RETRY_LEVEL){
retryLevel();
}else{
finish();
}
}
}
}
And class FailedActivity
private RelativeLayout bgLayout;
private TextView text1;
private TextView text2;
private TextView text3;
private TextView text4;
private TextView text5;
private Button buttonRetryLevel;
private Button buttonBack;
public class FailedActivity extends Activity{
public void onCreate(Bundle saved){
super.onCreate(saved)
setContentView(R.layout.activity_failed);
bgLayout = (RelativeLayout)findViewById(R.id.bgLayout);
text1 = (TextView)findViewById(R.id.textView1);
...
buttonBack = (Button)findViewById(R.id.btnBack);
Bundle bundle = getIntent().getExtras();
text1.setText(bundle.getString("text1");
...
text5.setText(bundle.getString("text5);
}
public void buttonRetryClicked(View view){
setResult(Level1Activity.RESULT_RETRY_LEVEL);
finish();
}
...
}
So, i want to call findViewById for all the Views only once, and reuse the Activity because the FailedActivity i use for all my Levels, i need to pass only the Strings that will be shown, maybe the background color, etc.
My question is: can i create the FailedActivity only ones, and then when i call startActivityForResult just to pass the Bundle and the Views to be created only once.
You can use
singleInstance
as launch mode and override onNewIntent() function to bypass the re-creation of the activity UI components.
#Override
protected void onNewIntent(Intent intent) {
setIntent(intent);
// handle parameters here.
}
Yes, this is possible as noted in the another answer. If you do this though, you are stepping outside of the standard Activity lifecycle. Generally, when an android app starts a new Activity, the old Activity is destroyed and a new instance of the new one is created. This also occurs when you change the device orientation (portrait -> landscape). The Android runtime does this for memory efficiency and because the view dimensions may have changed. Have a look at this if you want to learn more about the activity lifecycle.
Are the bundled values you're putting in an intent from your Level1Activity going to be the same for other levels? If so you could hardcode those strings directly into the xml layout file for FailedActivity. If you need all level activities to have the ability to open the FailedActivity, I'd consider creating a levelActivity superclass. This will simplify the FailedActivity creation code and stop you from having to repeat yourself. Something like this:
public abstract class LevelActivity extends Activity {
public void showFailedActivity(){
Intent intent = new Intent(this, FailedActivity);
intent.putExtra("text1", "You failed! You made only 50 points");
intent.putExtra("text2", "Try again later");
startActivityForResult(intent, REQUEST_FAIL_ACTIVITY );
}
}
public class Level1Activity extends LevelActivity {
protected void onActivityResult(int requestCode, int resultCode, Intent data){
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == REQUEST_FAIL_ACTIVITY ){
if(resultCode == RESULT_BACK){
finish();
}else if(resultCode == RESULT_RETRY_LEVEL){
super.retryLevel(); // calls LevelActivity.retryLevel()
}else{
finish();
}
}
}

How to Call onActivityResult in adapter listview?

i'm learning how to change Single item with resultActivity in in my custom Adapter listview. how it's can work ?
this my code when startActivityForResult in custom adapter listview
holder.isi_layout.setOnClickListener(new android.view.View.OnClickListener(){
public void onClick(View v)
{
Intent i = null;
i = new Intent(activity, DetailLaporanActivity.class);
Bundle b = new Bundle();
b.putString("position", Integer.toString(position));
i.putExtras(b);
activity.startActivityForResult(i, mRequestCode);
activity.overridePendingTransition (R.anim.push_left_in, R.anim.push_left_out);
}
});
and this OnResultActivity
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode==mRequestCode) {
if(resultCode == RESULT_OK){
String position = data.getStringExtra("position");
String status_favorite = data.getStringExtra("status_favorite");
String jumlah_favorite = data.getStringExtra("jumlah_favorite");
String jumlah_komentar = data.getStringExtra("jumlah_komentar");
}
Toast.makeText(getApplicationContext(), "This code Success get Result", Toast.LENGTH_LONG).show();
}
}
When i put OnResultActivity in Adapter, code is error, RESULT_OK get notice Cannot be resolved to a variable,
but if i put in MainActivity , this not error but not get value result, i check with Toast.makeText(getApplicationContext(), "This code Success get Result", Toast.LENGTH_LONG).show(); but no toast,....
anybody help me ? how it's work ?
sorry, for my english...
You added unresolved RESULT_OK so you should set it in DetailLaporanActivity.class like that.
public class DetailLaporanActivity extends Activity {
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
setResult(RESULT_OK);
}
}
and than you can use RESULT_OK in your onActivityResult method.
That's because RESULT_OK is a constant of the Activity class. So, you need to qualify it in your Adapter class as so:
Activity.RESULT_OK

Sending data back to the Main Activity in Android

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

Categories

Resources