Android: pass data from initial activity (launching Zxing scanner) to onActivityResult callback - java

I use the library zxing-android-embedded in my Android App. Before calling initiateScan() method to start the scanner from my activity, I set a class variable scanedItemId to know on which item I clicked to scan:
[...]
scanedItemId = currentItem.id // The current item where we clicked on.
IntentIntegrator qrCodeScanner = new IntentIntegrator(MyActivity.this);
qrCodeScanner.setOrientationLocked(false);
qrCodeScanner.initiateScan();
[...]
Then I get the result via onActivityResult method. It works well but my class variable scanedItemId is null because the activity is relaunched. Is it possible to keep my initial instance of MyActivity (with the scanedItemId well set) or to pass the value I need thru the IntentIntegrator to get it back on the new instance of MyActivity?
[...]
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
switch (requestCode) {
case IntentIntegrator.REQUEST_CODE:
// Here the scanedItemId is always null.
[...]
If possible I wouldn't like to use a hard persistence (like db or file) to get my scanedItemId value.
Hope it's clear enough

You can add more custom data like this :
scanedItemId = currentItem.id // The current item where we clicked on.
IntentIntegrator qrCodeScanner = new IntentIntegrator(MyActivity.this);
quCodeScanner.addExtra("ITEM_ID", scanedItemId);//add your data
qrCodeScanner.setOrientationLocked(false);
qrCodeScanner.initiateScan();
Because library which you used didn't return your data. You can fork that library and add some code like below:
In CaptureManager class
edit initializeFromIntent method
if (intent != null) {
data = intent.getIntExtra("ITEM_ID", 0);//save your data
}
and resultIntent method
intent.putExtra("ITEM_ID", data);//return your data
Now in onActivityResult you can get your data
IntentResult result = IntentIntegrator.parseActivityResult(resultCode, data);
if (result.getOriginalIntent().hasExtra("ITEM_ID")) {
Toast.makeText(this,"Item Id : " + String.valueOf(result.getOriginalIntent().getIntExtra("ITEM_ID",0)), Toast.LENGTH_LONG).show();
}

Related

How do I create a new object on every button click?

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.

Can the same Android getIntent() receive from two different classes?

Problem:
When I try to "reuse" so-to-speak a getIntent() with extra values by passing data to it from a second activity, the extra values return null. So I want to pass NoteAdapter Intent Extras to the ViewNote class and I also want to pass EditNote Intent Extras to the ViewNote class using the same string keys.
Something like this: User chooses note > User Views Note > User Edits Note > User Views Note corrected.
What works:
Based upon a user selection of a RecyclerView list of notes, the chosen note through a NoteAdapter has extra details passed to an Intent to a ViewNote class which in turn has a Intent n = getIntent() which these extras are received. Note details are loaded into the ViewNote activity. If the user decides this note needs corrected or updated, then the ViewNote class has an Intent that passes extras to the EditNote class. This all works great!
What doesn't work and What I'm trying to do:
I'm not sure whether this is allowed or can be done but I'm trying to pass extras back to the ViewNote class from the EditNote class using the same Intent n = getIntent() in the ViewNote class used earlier when a note was passed to it.
The ViewNote class getIntent():
Intent n = getIntent();
nNoteID = n.getIntExtra("ID", 0);
String nType = n.getStringExtra("Type");
String nSummary = n.getStringExtra("Summary");
String nSource = n.getStringExtra("Source");
String nAuthors = n.getStringExtra("Authors");
The EditNote Intent to pass extras back to the ViewNote
Intent u = new Intent(EditNote.this, ViewNote.class);
u.putExtra("ID", vNoteID);
u.putExtra("Type", ty);
u.putExtra("Summary", su);
u.putExtra("Source", so);
u.putExtra("Authors",au);
EditNote.this.startActivity(u);
What I have tried:
I've read a few posts here on stackoverflow that appeared to be similar and tried changing the context (thinking maybe that was wrong), and tried using Bundle but neither of those made any difference. I thought maybe the String array values weren't passing so I just passed String variables because the "ID" number as a String seems to pass fine but the other values still return null. I've read some of the Android Developer explanations about Intents and maybe I just don't understand Intents fully or maybe this just can't be done or is not how it should be done.
I'm working in the following:
Intellij Idea 2021.1.1
Java Android v.28 Min v.29 Max
Gradle 4.1.2
The solution was exactly what David Wasser posted in the initial comments above. I needed to use the startActivityForResult and follow the guidelines on how to do so. I did review the Android Development links and other examples online, but this video helped:
Android startActivityForResult Tutorial
These are the code segments in sequence:
ViewNote
menuIntent = new Intent(this, EditNote.class);
menuIntent.putExtra("NoteID", nNoteID);
menuIntent.putExtra("NoteDetails", new ArrayList<>(noteDetails));
if(noteFiles.size() > 0)
menuIntent.putParcelableArrayListExtra("NoteFiles", new ArrayList<>(noteFiles));
startActivityForResult(menuIntent, REQUEST_CODE); // REQUEST_CODE = 1
EditNote
Intent u = new Intent();
u.putExtra("ID", vNoteID);
u.putExtra("Type", ty);
u.putExtra("Summary", su);
u.putExtra("Source", so);
u.putExtra("Authors",au);
setResult(RESULT_OK,u);
finish();
Back to ViewNote onActivityResult
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == REQUEST_CODE){
if(resultCode == RESULT_OK) {
nNoteID = data.getIntExtra("ID", 0);
nType = data.getStringExtra("Type");
nSummary = data.getStringExtra("Summary");
nSource = data.getStringExtra("Source");
nAuthors = data.getStringExtra("Authors");
}
}
}

Why am I getting a null pointer exception when passing an ArrayList of strings from one activity to another?

I am trying to get an arraylist in ScanLocate activity from an UpdateLocation activity.
I'm using startActivityForResult method to call the scan method which populates the ArrayList wifiList, I then want to send the ArrayList to the Update Location class.
I start by calling startActivityForResult in Update Location:
private void getScan(){
//Create an intent to start ScanLocate
final Intent i = new Intent(this, ScanLocate.class);
//Start scanLocate with request code
startActivityForResult(i, REQUEST_READINGS);
}
Next, in ScanLocate I created the sendData method (note: the check confirms that the ArrayList data is intact at that point):
private void sendData(){
//create a new intent as container for the result
final Intent readings = new Intent(this, UpdateLocation.class);
//check that data is in wifiList
for(String s:wifiList){
Log.v(TAG,"List Items: " + s);
}
//create bundle for string array
Bundle b = new Bundle();
b.putStringArrayList(key, wifiList);
//add readings to send to updateLoc
readings.putExtras(b);
//set code to indicate success and attach Intent
setResult(RESULT_OK, readings);
//call finish to return
finish();
}
The final part is back in UpdateLocation with the onActivityResult:
#Override
public void onActivityResult(int requestCode, int resultCode, Intent readings){
super.onActivityResult(requestCode, resultCode, readings);
//check if request code matches the one set above
if(requestCode == REQUEST_READINGS){
//check if sendData() in ScanLocate was successful
if(resultCode == RESULT_OK){
//get the readings from the Intent
Log.v(TAG, "HERE");
result = getIntent().getExtras().getStringArrayList(ScanLocate.key);
Log.v(TAG, "HERE2");
for(String s : result) {
Log.v(TAG, "Location 5: " + s);
}
}else{
//ScanLocate was unsuccessful
}
}
}
The first "Here" is displayed however it then falls down on the next line, getStringArrayList() throws a null pointer exception.
I have looked through the documentation and at previous questions on here and I cannot see what is going wrong.
Any advice would be appreciated, thanks.
Previous questions:
startactivityforResult not working
How to pass an ArrayList to the StartActivityForResult activity
You don't need to call getIntent(), use the parameter provided by the method:
result = readings.getStringArrayListExtra(ScanLocate.key);

Updating some fields in main activity after exiting from another activity

My MainActivity has an EditText with the hint "Weight (lb)", as well as a button that goes to the SettingsActivity. In SettingsActivity, the user is able to change the units used from US to metric. Upon exiting SettingsActivity via the built-in back button on the phone, I want the hint for the EditText to immediately change from "Weight (lb)" to "Weight (kg)".
The farthest I've gotten is using the onBackPressed() method in SettingsActivity. The button press is detected, and the code inside it is executed, but I don't want to change anything related to MainActivity's inside the SettingsActivity class.
Is there an on___() method that I should be using here that I don't know about? Any help would be appreciated.
You can use startActivityForResult for SettingsActivity and after that handle the return result as:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == PICK_CONTACT_REQUEST) {
// Make sure the request was successful
if (resultCode == RESULT_OK) {
// The user picked a contact.
// The Intent's data Uri identifies which contact was selected.
// Do something with the contact here (bigger example below)
}
}
More detail: https://developer.android.com/training/basics/intents/result.html
You can use startActivityForResult for SettingsActivity and after that handle the return result as:
In your MainActivity:
public static int CALL_SETTINGS = 1000;
startActivityForResult(new Intent(this,SettingsActivity.class),CALL_SETTINGS);
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == PICK_CONTACT_REQUEST) {
// Make sure the request was successful
if (resultCode == RESULT_OK) {
// The user picked a contact.
// The Intent's data Uri identifies which contact was selected.
// Do something with the contact here (bigger example below)
}
}
In your Settings Activity:
on backpressed write this:
Intent returnIntent = new Intent();
returnIntent.putExtra("result",data);
setResult(Activity.RESULT_OK,returnIntent);
finish();
Easy option is to store the waitUnit in shared preference and on OnResume() of the Main activity read it from there and update the widget.
You can update the preferences in your Settings activity like below:
preferences = context.getSharedPreferences(context.getString(R.string.preference_file_key),
Context.MODE_PRIVATE);
preferences.edit().putString("unit", "kg");
And you can read this changed value in OnResume() of your Main Activity
preferences.getString("unit", "default unit")

How to pass String from 2 activities to one?

I have two activitys with lists.
One for tablet's and one for regular density phones.
When an item in the list is clicked it launches the same activity for either activity with list's.
The problem is when an item is clicked i have getter and setter class that gets the URL for a particular item and passes it to the launching activity like this...
private String URL = null;
try{
URL = com.fttech.AbstractFeedsActivity.feed_url;
}
catch(IllegalArgumentException e){
e.printStackTrace();
URL = com.fttech.ItemsActivity.url;
}
As you see what i tried to do is try and catch.
So if the first one isnt found then the second one will be retrieved.
But it doesnt seem to work.
It returns null each time.
For what i have describe what is the best way to implement this?
Is my way logic? Or is there a better way.
Thanks
Try this,
private String URL = null;
try{
URL = com.fttech.AbstractFeedsActivity.feed_url;
if(TextUtils.isEmpty(URL)){
URL = com.fttech.ItemsActivity.url;
// Pass this URL
}
else{
// If its not empty then it will pass the first URL
}
}
catch(IllegalArgumentException e){
e.printStackTrace();
}
No need to pass String to 2 activities, if you want to just pass strings to one or as many activities as you want, just put them in SharedPreferences or declare a variable in static class and then set/get it whenever you want.
Passing values from one Activity to another:
Intent intent = new Intent(context, CalledActivity.class);
intent.putExtra(key, value);
startActivity(intent);
If you want some data back from called Activity then you can use startActivityForResult() as:
Intent intent = new Intent(context, CalledActivity.class);
intent.putExtra(key, value);
startActivityForResult(intent, requestCode);
In called activity you can set data as:
setResult(RESULT_OK, intent);
Note: Here you set the value in intent and pass it to setResult().
On returning back to calling Activity you can get data by overriding:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(resultCode == RESULT_OK){
//Get data from Intent "data" and do your task here....
}
}
Note: You can pass primitive data type values thru Intent and if you want to pass other types then you have to use Bundle like this.
Bundle data = new Bundle();
data.putIntArray(key, value);
//same way you can set other values.......
//Now set this Bundle value to Intent as you do for primitive type....
Intent intent = new Intent(context, CalledActivity.class);
intent.putExtra(data);
startActivity(intent);
Receiving data in Activity:
//For primitive values:
DataType var_name = getIntent().getExtras().get(key);
//For Bundle values:
Bundle var_name = getIntent().getExtras().getBundle(key);

Categories