this is my first question being asked on stackoverflow. My question is regarding variable use across different recyclable intents.
e is declared like this.
final Bundle e=getIntent().getExtras();
Here i am creating new intents for different setOnClickListener() and passing a different variable for each intent.
Intent info = new Intent(EItemListView.this, ItemInfo.class);
Bundle extras = new Bundle();
int[] a=new int[listview.getAdapter().getCount()];
if (i == 0) {
extras.putIntArray("img", n5x_images);
extras.putString("info", n5x_info);
extras.putInt("pc",a[0]);
} else if (i == 1) {
extras.putIntArray("img", op3_images);
extras.putString("info", op3_info);
extras.putInt("pc",a[1]);
}
info.putExtras(extras);
startActivity(info);
Now this is the OnClickListener() where i am trying to update the variables which i passed through the intent extras, but am unable to update those variables.
addtc.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
int c=e.getInt("pc");
c=c+1;
Log.i("Log","value "+c);
}
The log message which i get from the above method is always 1, i think the variable in c is always set to 0 and then increments by 1 and hence the log message shows 1.
I need the variables a[0],a[1],a[2], etc to pertain its increment operation.
To make it more clear, this is the java file i am using. The error is in the OnClickListener of addtc button at the bottom of this code.
public class ItemInfo extends AppCompatActivity {
private ViewAnimator viewanimator;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_item_info);
Button next=(Button)findViewById(R.id.bnext);
Button prev=(Button)findViewById(R.id.bprev);
viewanimator=(ViewAnimator)findViewById(R.id.viewAnimator);
TextView info=(TextView)findViewById(R.id.item_info);
Button addtc=(Button)findViewById(R.id.badd);
Button test=(Button)findViewById(R.id.button);
Bundle e=getIntent().getExtras();
int img[]=e.getIntArray("img");
for(int i=0;i<img.length;i++)
{
ImageView imgview = new ImageView(getApplicationContext());
imgview.setImageResource(img[i]);
viewanimator.addView(imgview);
}
info.setText(e.getString("info"));
next.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
viewanimator.showNext();
}
});
prev.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
viewanimator.showPrevious();
}
});
addtc.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
int c=e.getInt("pc");
c=c++;
Log.i("Log","value "+c);
}
});
}
}
Thanks in advance!!!
Your approach is wrong. You cannot do this in this way. Your understanding of what an "extra" in an Intent is incorrect.
When you do this:
extras.putInt("pc",a[1]);
This adds an "extra" to the extras Bundle. The Bundle is simply a key/value pair map and you have added an entry that contains the key "pc" and the value is whatever a[1] is. It puts a copy of the value of a[1] into the Bundle, it does not put a reference to a[1] in the Bundle.
Therefore, if a[1] is 5 when you add it to the extras Bundle, a[1] will always be 5 and will never be changed to anything else.
You can't do this in this way.
Alternative: Depending on your application architecture and what you are trying to do, you can use one of the following methods:
1) Use startActivityForResult(), pass the data from one Activity to another, have the second Activity update the data and put it back into the Intent which is then returned to the "calling" Activity by using setResult().
2) Use a static variable (basically a "global" variable) to contain the data. Both activities can then access the data directly (you don't need to put the data in the Intent.
3) Put the data in a database. Both activities can then read/write from/to the database.
First advice I can give you is debugging and posting debug result. for example, are you sure that a[0] and a[1] aren't 0?
Assuming they are not, why are you declaring the bundle as final? referring to this probably final is not what you were looking for. Try removing it or replacing with private
Another suggestion is more for readable purpose, replace c = c+1; with c++; but this doesn't change the result, it just make it more linear and easier for reading.
Now after this fix (the final keyword one) tell me if something changed please :)
Related
I need to start one Activity (say WriteAtivity), twice, but in different mode.
In MainActivity what happens.
For example:
addNote.setOnClickListener( new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent writeAct = new Intent(MainActivity.this, WriteActivity
// HERE, I DO NOT NEED OF putExtra()
startActivity(writeAct);
}
});
and
editNote.setOnClickListener( new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent visualizza = new Intent(MainActivity.this, WriteActivity.class);
// HERE INSTEAD I HAVE NEED OF putExtra()
visualizza.putExtra("posizione", position);
startActivity(visualizza);
}
});
and in onCreate() of WriteActivity
intent = getIntent().getExtras().getInt("posizione");
rifTitleNote.setText(listNote.get(posizione).getTitle());
As you can see, in one i do not need putExtra() and in second I do.
I do this because I use the WriteActivity, at first, for write a note, and then, for edit the note.
This, in any case causes IndexOutOfBoundsException: Invalid index 0, size is 0
Do you know how I can overcome this problem?
Or give me advice on how to do this?
Thanks! :D
Just use getIntExtra() with a default value, and make sure that the value is not set to the default value before using it.
Intent intent = this.getIntent();
int posizione = intent.getIntExtra("posizione", -1);
if (posizione != -1){
rifTitleNote.setText(listNote.get(posizione).getTitle());
}
Check for the existence of the extra and handle accordingly if it exists or not. See Android's Intent documentation for hasExtra.
if (getIntent().hasExtra("posizione")) {
// Do stuff with extra
}
You could also set an action on the Intent that indicates how the Activity should handle the incoming intent. This is probably the "better" approach but might be overkill depending on your project.
I'm trying to create what's basically a list of cards repeating one after another, based from an array I have via a loop.
For some reason though, setting my OnClickListener inside the loop is causing an OOB exception but from what I see it shouldn't be so I appreciate being pointed in the right direction.
My loop:
for(FAQNumber = 0; FAQNumber < questions.length; FAQNumber++){
stack.add(new FAQCard(questions[FAQNumber], answers[FAQNumber]));
(stack.get(FAQNumber)).setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Bundle bundle = new Bundle();
bundle.putSerializable("title", questions[FAQNumber]);
bundle.putSerializable("position", FAQNumber);
startActivity(new Intent(getActivity().getBaseContext(), QuestionAnswer.class).putExtras(bundle));
}
});
}
questions is an Array declared earlier in the method, containing just a few strings. And stack behaves as a List.
I'm getting the OOB error on bundle.putSerializable("title", questions[FAQNumber]); when it's trying to add the questions[5] (if my questions[] contained 5 values). But I don't understand how that happens because the loop should stop before FAQNumber is equal to 5?
All I'm trying to do with the above loop is pass the right question to the bundle so that when a card is pressed, the questions match up.
Anyway, any help is appreciated!
FAQNumber seems to be defined outside of the for-loop rather than inside. This means it continues to exist after the loop is done ... is this intentional? If there are 5 items in questions then after the loop terminates FAQNumber will be equal to 5 (due to the last FAQNumber++).
The OnClickListener's onClick(View v) method is not called until the button is actually clicked. At this time, it's looking for FAQNumber which is now equal to 5. The key thing to understand here is that when you put FAQNumber into the onClick method, it's going to actually go and look for the current value of FAQNumber at the time of the click, not at the time that you defined the method. The reason you're getting the OutOfBoundsException at this line is not because the error is happening while you're looping but because the button's click behavior is located here so this is where the error is thrown. Your loop is actually executing just fine.
Instead, you're going to want to store FAQNumber as an instance variable on the view you're clicking like so:
for(int i = 0; i < questions.length; i++) {
stack.add(new FAQCard(questions[i], answers[i]));
// Replace YourViewClass with whatever you're getting off the stack
YourViewClass obj = (stack.get(FAQNumber));
obj.setFaqNumber(i); // You'll need to add this method
obj.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Bundle bundle = new Bundle();
// You'll need to add the getFaqNumber() getter as well
bundle.putSerializable("title", questions[getFaqNumber()]);
bundle.putSerializable("position", getFaqNumber());
startActivity(new Intent(getActivity().getBaseContext(), QuestionAnswer.class).putExtras(bundle));
}
});
In addition to #hatboysam's answer I also got it working by changing to a while:
while(FAQNumber < questions.length){
final int i = FAQNumber;
final FAQCard FAQ = new FAQCard(questions[FAQNumber], answers[FAQNumber]);
FAQ.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// Create a new bundle to pass to the browser
Bundle bundle = new Bundle();
// Inform which feed item was selected
bundle.putSerializable("title", questions[i]);
bundle.putSerializable("position", i);
// Start the new activity and pass on the bundle
startActivity(new Intent(getActivity().getBaseContext(), QuestionAnswer.class).putExtras(bundle));
}
});
stack.add(FAQ);
FAQNumber++;
};
Hi everyone.
I'm new in android and I'm working on an app in which I need to recall the same activity to enter the information of a variable amount of entities (passengers).
I have the following:
btnContinue3.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
for (int i=0; i<Pssngr; i++){
passenger[i] = new
Intent(getApplicationContext(), Pasajeros.class);
startActivity(passenger[i]);
}
}
});
Pssngr is the amount of passsengers or entites that need a unique activity to get their information entered.
The trigger is the button then the activities will be called one by one following an array
I try this code but after clicking on the button the app crashed.
Please someone help me find a way to make this work.
thanks
It crashes because You are trying to start x number of Activities at once.
If You have to run new Activity for each of Passengers best in this scenario will be startActivityForResult
I beliver effect You trying to get is that user clicks on button just once and activities for each passenger will open one after another.
To do it in method onClick You will start only first activity, don't use loop.
You start consequently next activities in onActivitiyResult
In addition to what Gustek mentions above, a better way to approach this would be to have one activity and just pass the different values from the parent (PassengersAvitivty) activity through the intent as below:
final Intent intent = new Intent(PassengersAcitivty.this, PassengersEntityActivity.class);
intent.putExtra("PASSENGER_FIRSTNAME", passenger[i].getName());
intent.putExtra("PASSENGER_LASTNAME", passenger[i].getLastName());
intent.putExtra("PASSENGER_EMAIL", passenger[i].getEmail());
startActivity(intent);
and here is how you can retrieve them on your activity (PassengerEntityActivity)
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle extras = getIntent().getExtras();
if (extras != null)
{
firstname = extras.getString("PASSENGER_FIRSTNAME");
lastname = extras.getString("PASSENGER_LASTNAME");
email = extras.getString("PASSENGER_EMAIL");
}
else
{
//Log.v("NO VALUE", "OOPS");
}
I can clarify further if needed.
I am creating an application in which I scan a number of bar codes and keep extracting their values and clubbing them in a single place. As simple as this sounds I have been unable to create either an array in which I keep storing new values or a string where I keep concatenating them.
Please comment in case someone needs more code or explanation, I understand the question might not be very rich in either.
EDIT :
public class example
{
String val;
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
try
{
String list_id=ToolList3.ID;
String list_qty=ToolScanDet3.qty;
// val is returned from the barcode scanning app.
val=val+issue_id+"~"+issue_qty+";";
Log.d("Tools issued till yet...", val);
/* Club all the tool IDs together and fire a single query to issue
them all against one name. */
Intent i=new Intent(Issue.this,Issue1.class);
startActivity(i);
//Issue1 again returns a pair of id and qty which needs to be saved along with the previous set of values.
}
I am basically having trouble trying to save the returned set of values along with the previous ones, the new ones that are returned wipe out the previous values. I tried putting them in an array too but that requires a counter which again defeats the purpose because the counter will be initialized to zero and start over again.
Unless the number of elements is known and constant, it is preferred to use ArrayList instead of array. In the case when you want to keep the data when the activity is destroyed caused by orientation change, you can save them in onSavedInstanceState :
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString("temp", tempString);
}
Then retrieve it back in onCreate:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(savedInstanceState != null) {
your_arraylist = savedInstanceState.getString("temp");
}
EDIT:
According to what you want, the Scan activity should not initialize any string. It should obtain the string value which is passed to it by the main instead:
public class ScanActivity extends Activity {
String tempString;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if(savedInstanceState == null) {
tempString = getIntent().getStringExtra("temp");
} else {
// orientation change
tempString = saveInstanceState.getString("temp");
}
}
Once you have finished the scan, do
Intent output = new Intent();
output.putExtra("temp", tempString);
setResult(RESULT_OK, output);
finish();
to send back the string to your Main activity.
I could not find any solution that was feasible to my situation and thats why I had to create a local database using SQL Lite. Pushing values to the database each time needed and then retrieving the values after my work flow was over.
Comment in case anyone needs help with the creation of a local database using SQL Lite. Happy to help :)
new to droid programming. im having a small problem that im sure is simply fixed but ive done some searching and a bunch of tutorials but cant seem to find just what i need so i figured id ask. My app has 2 activites, the first activity is just a simple form where a user enters course information(class title, professor..etc.)
the first activity passes the data which is supposed to be stored in a list in the second activity. problem is that only the first course gets stored in the list, after the first time nothing new gets added to the second activity. Can someone point me in the right direction please? thanks in advance
First Activity
public class CourseDetail extends Activity {
//Course c = new Course();
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button save=(Button)findViewById(R.id.save);
save.setOnClickListener(onSave);
}
private View.OnClickListener onSave=new View.OnClickListener() {
public void onClick(View v) {
EditText course=(EditText)findViewById(R.id.course);
EditText professor=(EditText)findViewById(R.id.professor);
EditText location=(EditText)findViewById(R.id.location);
EditText officehrs=(EditText)findViewById(R.id.officehrs);
Intent i=new Intent(CourseDetail.this, CourseList.class);
i.putExtra("myCourse", course.getText().toString());
i.putExtra("myProfessor", professor.getText().toString());
i.putExtra("myLocation", location.getText().toString());
i.putExtra("myOfficehrs", officehrs.getText().toString());
startActivity(i);
}
};
}
Second Activity
public class CourseList extends Activity {
Button btnCourse;
List<Course> model = new ArrayList<Course>();
CourseAdapter adapter=null;
private String dCourse="";
private String dProfessor="";
private String dLocation="";
private String dOfficehrs="";
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.clist);
ListView list =(ListView)findViewById(R.id.courses);
adapter=new CourseAdapter();
list.setAdapter(adapter);
Course c = new Course();
Bundle extras = getIntent().getExtras();
dCourse = extras !=null ? extras.getString("myCourse") :"no value entered";
dProfessor = extras !=null ? extras.getString("myProfessor") :"no value entered";
dLocation = extras !=null ? extras.getString("myLocation") :"no value entered";
dOfficehrs = extras !=null ? extras.getString("myOfficehrs") :"no value entered";
c.setCourse(dCourse);
c.setProfessor(dProfessor);
c.setLocation(dLocation);
c.setOfficeHrs(dOfficehrs);
btnCourse =(Button)findViewById(R.id.btnCourse);
btnCourse.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
finish();
}
});
}
You are just getting the user entered value in CourseDetail activity and displaying the received value inside the CourseList activity, that means you are not storing these values permanently.
Go through this Android - Data Storage document.
When you move to 2nd activity i.e. CourseList activity, at that time fetch the data from the SQLite table and display the same. whenever you get new values from previous activity, at that time just update the list by adding the new data in ArrayList and make a call on adapter.notifyDataSetChanged()
Some suggestions:
Have your CourseList extend ListActivity instead of just Activity - check out some tutorials on that which should help you set things up correctly.
There seems to be a bit of confusion with how you're handling your lists - you have your model variable but don't seem to be doing anything with it. Again, have a look at a ListView tutorial (just google "android listview tutorial").
You seem to have figured out that you can use "intents" to pass information from one activity to another, but since you're only doing this in the onCreate() method, it's only happening once. Try doing this in your ListActivity's adapter once for each item.
Don't give up on Android, keep trying :-)
Some suggestion:
You have to add your object to the adapter: adapter.add(c); after you get the data.
Call adapter.notifyDataSetChanged() to notify the system that your data for the listView has been changed. Call list.invalidate() to refresh it.
I noticed that you set the button with the finish() method. Hmm, if you do so, the next time you get to CourseList Activity from CourseDetail, the adapter will be null again. No previously received data will be available. Is this what you really want?
The problem is you are not adding the newly added items to the List.So before setting adapter you have to add all your objects like
list.add(c);