I have 3 Activities on the app:
MainMenuActivity -> ExecuteTrainingActivity -> ExecuteExerciseActivity.
From MainMenuActivity to ExecuteTrainingActivity, I'm passing an idExecution and an idExercise for ExecuteTrainingActivity query and load the initial data.
ExecuteTrainingActivity onCreate:
#Override
protected void onCreate(Bundle savedInstanceState) {
//...
initialize();
setupRecyclerView(exercises);
}
private void initialize() {
Bundle extras = getIntent().getExtras();
if (extras != null) {
if (extras.containsKey("id_execution")) {
idExecution = extras.getLong("id_execution");
idExercise = extras.getLong("id_exercise");
execution = queryExecution(idExecution);
} else {
insertExecution();
}
}
}
In the 3rd activity, ExecuteExerciseActivity, I have a TimerFragment that, and when TimerCountdown reaches 0, it opens a Notification popup, that when clicked open an fresh ExecuteExerciseActivity.
On this TimerFragment, I'm passing as Extras the same ids, so I can get them in the new fresh ExecuteExerciseActivity:
public class TimerFragment extends Fragment {
//...
private void showNotification(){
Intent intent = new Intent(getActivity(), ExecuteExerciseActivity.class);
intent.putExtra("id_execution", idExecution);
intent.putExtra("id_exercise", idExercise);
intent.putExtra("position", position);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(getActivity());
stackBuilder.addNextIntentWithParentStack(intent);
PendingIntent pendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
/*=== CHECK IF NOTIFICATION CHANNEL IS ACTIVE ===*/
boolean ok = isNotificationChannelEnabled(getActivity(), Constants.CHANNEL_ID);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(requireNonNull(getActivity()), Constants.CHANNEL_ID)
.setSmallIcon(R.drawable.d77)
.setContentTitle("Teste Notificação")
.setContentText("Ababa")
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setContentIntent(pendingIntent)
.setAutoCancel(true);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(getActivity());
notificationManager.notify(0, mBuilder.build());
}
From this new fresh ExecuteExerciseActivity, I want to make the system maintain the same navigation flow of Activities, but when I backpress from the new ExecuteExerciseActivity to ExecuteTrainingActivity, i can't pass the Id's for the ExecuteTrainingActivity query and load.
Is there a way to pass arguments onBackPress?
Is the best approach override onBackPress creating a new intent and a starting a new Activity?
**My manifest is using parentActivityName correctly.
Save your query and id into a SharedPreferences in onDestroy of your ExecuteExerciseActivity then pull out the query and id again in the old ExecuteTrainingActivity. onBackPressed triggers onDestroy event of an activity's life cycle. Then in the onResume of ExecuteTrainingActivity pull this data back out.
I think you can achieve this by overriding onOptionsItemSelected() method of ExecuteExerciseActivity. Try this:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home) {
Intent intent = new Intent(this, ExecuteExerciseActivity.class);
//Add the extras to the intent
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
In Android, if your Activity starts another Activity and want to pass data to that Activity, you would add those data as Intent extras.
This Activity A to Activity B type of sending data is something you're using already.
But for Activity B back to Activity A, there's actually a built-in solution for this, which is through startActivityForResult(Intent, REQUEST_CODE) instead of startActivity(Intent).
Now in Activity B, you simply have to code:
#Override
public void onBackPressed()
{
Intent resultIntent = getIntent();
resultIntent.putExtra(EXTRA_NAME, extra_value);
setResult(Activity.RESULT_OK, resultIntent);
finish();
}
Basically, in Activity B, you're setting the data you want to send back to the Activity A that started Activity B, since there's a connection between these two Activities.
Next, in your Activity A, just override the onActivityResult() method.
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CODE) {
if (resultCode == RESULT_OK) {
// get data through data.getIntExtra() and etc
}
}
}
The request code needs to match the REQUEST_CODE you used for Activity B, so Activity A knows which Activity to respond to. The result code is just a quick way for you to categorize the type of result you're getting back from Activity B, since there might be more than one type of result being returned from Activity B.
This solution of passing data is better than creating a new Intent and starting a new Activity because you don't need to start a new Activity. Your Activity A already exists, so there's no reason to rebuild the entire layout, reload all the data, and have a new Activity existing on the Activity stack.
Since your only intention is to pass data from Activity B back to the Activity A that started it, use startActivityForResult() and onActivityResult() to handle this type of data sharing.
Related
I am creating a notes app, and I've all but finished it. My app starts on the main activity, which shows a recylcerView displaying all of the saved notes. To create a new note, you press a button, which sends you to another activity where you write your note. You then press a button that saves the note as an instance of the Note class and sends that object instance back to the main activity where it updates the recyclerView.
My problem is, every time I press the save button for my note, it just updates the Note instance instead of creating an entirely new one. How do I get it to create a new instance of the Note class so that I can have more than one saved note?
Here is my code for the save button:
Intent intent = new Intent(AddNoteActivity.this, MainActivity.class);
String mTitle = title.getText().toString();
String mContent = content.getText().toString();
intent.putExtra("notePar", new Note(mTitle, mContent));
startActivity(intent);
Here is my code for the mainactivity:
Intent intent = getIntent();
Note sentParcNote = intent.getParcelableExtra("notePar");
if(sentParcNote != null) {
notes.add(sentParcNote);
}
You are using startActivity(intent) to navigate from AddNoteActivity to MainActivity, this method is used to start a new activity, which means, the system will create a new instance of MainActivity class and put it at the top of the activity stack. This way you will always have 0 or 1 note (when sentParcNote != null)
I would suggest to use startActivityForResult when you navigate from MainActivity to AddNoteActivity and call setResult in your AddNoteActivity
Example:
MainActivity:
Declare this static int at the top of your class (e.g: just before onCreate method)
private static final int ADD_NOTE_ACTIVITY_REQUEST_CODE = 2;
Then add this piece of code on your button action to start AddNoteActivity:
Intent addNoteIntent = new Intent(this, AddNoteActivity.class);
startActivityForResult(addNoteIntent, ADD_NOTE_ACTIVITY_REQUEST_CODE);
Then to catch the new note from AddNoteActivity
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == ADD_NOTE_ACTIVITY_REQUEST_CODE) {
if (resultCode == RESULT_OK) {
Note sentParcNote = data.getParcelableExtra("notePar");
if(sentParcNote != null) {
notes.add(sentParcNote);
}
}
}
}
AddNoteActivity:
add this piece of code to your save button action
String mTitle = title.getText().toString();
String mContent = content.getText().toString();
Intent intent = new Intent();
intent.putExtra("notePar", new Note(mTitle, mContent));
setResult(RESULT_OK, intent);
// finish closes the current activity which means in this case it goes back to the MainActivity
finish();
I would suggest using local storage to save your notes otherwise if you restart the app you will always have 0 notes.
I have two activities that should pass data back and forth to each other using intents. I'm not sure where to place some of the puts and gets though.
For Activity1 (MainActivity), I have a button, and on press it creates an intent, and then puts it to Activity2, then starts it using startActivity(intent).
btn.setOnClickListener((v) -> {
Intent intent = new Intent(this, Activity2.class);
intent.putExtra("test", testClass);
startActivity(intent);
});
Then in Activity2, I get that information in the onCreate() function using getIntent.
Now what I want to do is have a button in Activity2 that will pass data to Activity1, but won't necessarily "start/show" the activity.
So I'm wondering how this can be done.
My idea is to have the following similar to before:
Activity2:
btn.setOnClickListener((v) -> {
Intent intent = new Intent(this, MainActivity.class);
intent.putExtra("info", info);
});
But I'm confused about two things
Can I do this without starting the activity right away
Where would I do the getIntent call in MainActivity to retrieve this data
You can use startActivityForResult to start Activity2 and receive a result back to Activity1
Activity 1
int LAUNCH_ACTIVITY_TWO = 1;
Intent i = new Intent(this, Activity2.class);
i.putExtra("test", testClass);
startActivityForResult(i, LAUNCH_ACTIVITY_TWO);
//onActivityResult
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == LAUNCH_ACTIVITY_TWO) {
if(resultCode == Activity.RESULT_OK){
String result=data.getStringExtra("result");
}
}
}
Activity 2
Intent returnIntent = new Intent();
returnIntent.putExtra("result", result);
setResult(Activity.RESULT_OK, returnIntent);
finish();
Full Activity 1 code:
public class MainActivity extends AppCompatActivity {
public static int LAUNCH_ACTIVITY_TWO = 1;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button btn = (Button) findViewById(R.id.btn);
btn.setOnClickListener((v) -> {
Intent i = new Intent(this, Activity2.class);
i.putExtra("test", testClass);
startActivityForResult(i, LAUNCH_ACTIVITY_TWO);
});
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == LAUNCH_ACTIVITY_TWO) {
if(resultCode == Activity.RESULT_OK){
String result= data.getStringExtra("result");
}
}
}
}
Full Activity 2 code:
public class Activity2 extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(getIntent().getExtras() != null) {
// Get intent extras from Activity 1
}
Button btn = (Button) findViewById(R.id.btn);
btn.setOnClickListener((v) -> {
Intent returnIntent = new Intent();
returnIntent.putExtra("result", result);
setResult(Activity.RESULT_OK, returnIntent);
finish();
});
}
}
You can for example create a list in activity2 to which you add the data you want to pass to activity1. Before starting activity1 you get the values out of your array and add them as extras to the input.
You can have the data added to a JSONObject and use a serializer so you don't have to add your items all by yourself.
If you want to pass your data to activity1 without starting it,so activity1 processes the data, that is not possible. Activity doesnt execute anything while you are in activity2, for such cases you use fragments.
If you use fragments you can put all data in a viewmodel which is bound to the activity instead of each fragment.
There are several ways you can achieve this pending on what type of data you're looking at passing.
If it's an entire class object then make the class parcable. You can copy and paste the class in this website http://www.parcelabler.com/ and it auto formats it for you. All you do is pass it as an intent extra.
If you're looking at data that needs an action performed on it and then passed to another activity I would suggest using and intent service. You can perform certain actions pending the intents received in the service.
If you're looking at performing certain actions only after XYZ has occurred in your application then used shared preferences. These can be accessed anywhere quite easily.
Lastly, if you're using bulk data consistently that needs to remain persistent, use a local database storage and just query when you need to.
You can use SharedPreferences or static variables/fields for that.
I'm trying to send messages through in built sms app through Intent. Its working fine. Here is my code
public class Main_Act extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button startBtn = (Button) findViewById(R.id.button);
startBtn.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
if(sendSMS()) {
Intent intent = new Intent(Main_Act.this, Sample.class);
startActivity(intent);
}
}
});
}
protected boolean sendSMS() {
ArrayList<String> nums = new ArrayList<String>();
nums.add("111111111");
nums.add("222222222");
Log.i("Send SMS", "");
Intent smsIntent = new Intent(Intent.ACTION_VIEW);
smsIntent.setData(Uri.parse("smsto:"));
smsIntent.setType("vnd.android-dir/mms-sms");
smsIntent.putExtra("address" ,nums);
smsIntent.putExtra("sms_body" , "Test ");
try {
startActivity(smsIntent);
finish();
return true;
}
catch (android.content.ActivityNotFoundException ex) {
Toast.makeText(Main_Act.this,
"SMS faild, please try again later.", Toast.LENGTH_SHORT).show();
return false;
}
}
}
But the problem is it gets navigated to another activity without clicking send button in sms application. It should goto another activity only after clicking the send button in messaging app. Can anyone help me with this problem, Thanks in advance.
Let's clear out a slight misunderstanding in your code:
You should not try to start both intents in the same part/run of the code as you do here.
A startActivity will not execute directly going to the activity and then return to the same place in the code when activity execution finishes. In stead it asynchronously queues the intent for execution. Then your code queues another intent for execution. After the current code finishes (in this case when the button onClick() method ends) Android queue mgmt can start picking off the queue. Probably the first intent is executed shortly and then directly overrun by an immediate execution of the second.
So what happens in summary is that you first add one intent to the queue in sendSMS and then add intent 2 to the queue in onClick, before leaving. Now both the intents are executed.
What you need to do is to change the sendSMS code to something like:
Intent smsIntent = new Intent(Intent.ACTION_VIEW);
smsIntent.setData(Uri.parse("smsto:"));
smsIntent.setType("vnd.android-dir/mms-sms");
smsIntent.putExtra("address" ,nums);
smsIntent.putExtra("sms_body" , "Test ");
// To force the SMS app to return immediately after sent SMS
smsIntent.putExtra("exit_on_sent", true);
startActivityForResult(smsIntent, MY_SMS_REQUEST_RESPONSE_CODE);
Note the startActivityForResult() method that indicates that we expect Android to return and the "exit_on_sent" extra, to force a swift return.
MY_SMS_REQUEST_RESPONSE_CODE is just any random code you select to recognize the returning result in the callback method (even if you currently do not expect any other returning results, you may have some in the future).
Next thing to do is to remove the second intent creation and queuing. In stead you implement the following callback method (added to this activity):
#Override
protected void onActivityResult(
int callbackIdentifier, int resultCode, Intent intent) {
// Is this the expected sendSMS callback ?
if (callbackIdentifier== MY_SMS_REQUEST_RESPONSE_CODE) {
if (resultCode == RESULT_OK) {
// Continue where you left off (e.g. execute intent 2)
Intent intent = new Intent(Main_Act.this, Sample.class);
startActivity(intent);
} else if (resultCode == RESULT_CANCELED) {
// Error handling/retrying etc
}
}
// Support inherited callback functions
super.onActivityResult(callbackIdentifier,resultCode,intent);
}
Note: if you want to pass data and type don't call method separately because will delete each other you must pass it in one method
wrong
smsIntent.setData(Uri.parse("smsto:"));
smsIntent.setType("vnd.android-dir/mms-sms");
true
smsIntent.setDataAndType(Uri.parse("smsto:"),"vnd.android-dir/mms-sms");
I'm new to android and is currently developing a quest/tresurehunt application. It is a prototype and is going to be evaluated in the field and i would therefore like to implement some sort of cheat to skip checkpoints if the application should crash during the tests.
My application work the way that when you select a quest a activity will be loaded to handle all checkpoints and the user location(ActivityAdapter.java). This activity will open the diffrent navigation tool activities and pass information to them based on the next checkpont using intent. I have implemented a long press event in the app i would like to activate the skip/cheat. My problem is that i can't figure out how to do this.
Location changed event of ActivityAdapter.java:
public void onLocationChanged(Location location) {
location.distanceBetween(location.getLatitude(), location.getLongitude(), lat, lng, dist);
if (dist[0]<= 10) {
if (cid == checkpoints.size()) {
Intent intent = new Intent(ActivityAdapter.this, SuccessActivity.class);
intent.putExtra("title", checkpoints.get(cid).get("title"));
startActivity(intent);
} else {
new loadAndStartQuest().execute();
}
}
}
loadAndStartQuest() just find the next checkpoint and start the right activity (navigationtool). I have tryed creating a object of the ActivityAdapter and set a variable and add it to the the if statement which did not work. I guess it is because it will create another instance of the activity and not affect the current/running one. So how would you communicate between two running activities?
To send data from Activity1 to running Activity2, you must pass through the next steps:
In Manifest.xml set launch mode "singleTask" for Activity2
<activity android:name="Activity2" android:launchMode="singleTask">
Put extras and start Activity2 from Activity1 (if Activity2 was started before, intent will be sended to existing instance).
Intent intent = new Intent(getContext(), Activity2.class);
intent.putExtra("CHECK_POINT", checkPointData);
startActivity(intent)
Override method onNewIntent() in Activity2
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
onNewCheckPoint();
}
private void onNewCheckPoint(){
Intent intent = getIntent();
Bundle extras = intent.getExtras();
//in this moment, you can process data, like you want.
}
In an Android I would like to pass an Intent Object to a function, but consistently get a NullPointerException.
I could not find any source citing that this is not possible.
basically I have this:
public Intent intent;
/**
* Called when the activity is first created.
*/
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
intent = getIntent();
int check = elsewhere.chk_intent(intent); //<=THROWS ERROR
}
chk_intent() performs some functions on data transmitted with the intent, especieally if some extra fields are present.
I tried to move getIntent() into this function, but this is not allowed.
Any help would be much appreciated
Is this activity called by another activity? The intent will not be null only if previous activity supplies an intent to the current activity:
// previous activity
Intent intent = new Intent(FirstActivity.class, SecondActivity.class);
int value = 10;
intent.putIntExtra("key", value);
startActivity(intent);
// use this if want to return data
//startActivityForResult(intent);
If this activity is the starting (main) activity or it is not called by any previous activity, then getIntent() is null, you need to initialize your own new Intent object.
// current activity in onCreate() method
if(getIntent() == null) {
Intent intent = new Intent();
int check = elsewhere.chk_intent(intent);
}