I've searched on many SO questions , they are to old and can't find better solution on docs.oracle.com , i don't want to convert Each StringBuilder to string to pass an string array so how to achieve it ?
From inside the source Activity:
Intent intent = new Intent(this, DestActivity.class);
intent.putCharSequenceArrayListExtra("strings", myStringBuilders);
startActivity(intent);
You might have to do something like new ArrayList(Arrays.asList(myStringBuilders));
Make it into a Collection and then pass it through an intent, and then convert it back to an Array.
To pass an StringBuilder array you can use the putExtra of Intent, like this:
Intent it = new Intent(this, YourActivity.class);
StringBuilder[] sbAr = new StringBuilder[4];
sbAr[0] = new StringBuilder("Array0");
sbAr[1] = new StringBuilder("Array1");
it.putExtra("sbParam", sbAr);
however I do not know exactly why when you will retrieve the value in activity targets the StringBuilder array is recovered as CharSequence array.
CharSequence[] csA = (CharSequence[]) getIntent().getExtras().get("sbParam");
I hope this helps
The best way I've seen to pass around objects without bundling is to use an EventBus (I recommend greenrobot/EventBus).
An EventBus can be much faster than bundling. See this article.
The only down side I can see is that if your Activity/process is destroyed because of low memory it will lose the data when it's recreated; Whereas, if you store data in a bundle, the bundle will be resupplied to the Activity when it is recreated (could be wrong here).
Here's how it's done:
Create a POJO to store the StringBuilder for the event:
public class SaveStringBuilderEvent {
public StringBuilder sb;
public SaveStringBuilderEvent(StringBuilder sb){ this.sb = sb; }
}
Create first Activity, and post a StickyEvent before starting the next Activity (a 'StickyEvent' will keep the last event in memory until it is manually removed):
public class Activity1 extends Activity {
private StringBuilder sb;
...
// Function for loading the next activity
private void loadNextActivity(){
EventBus.getDefault().postSticky(new SaveStringBuilderEvent(sb));
Intent intent = new Intent(this, Activity2.class);
startActivity(intent);
}
...
}
Create Second Activity and remove the stick event from the EventBus:
public class Activity2 extends Activity {
StringBuilder sb = EventBus.getDefault()
.removeStickyEvent(SaveStringBuilderEvent.class)
.sb;
}
NOTE:
Personally I think it's the most proper way to handle such a situation where you don't want to bundle an object, however there are two other, less ideal, ways to maintain the state of an object between Activity life-cycles -- you could store the StringBuilder in the Application class or in a Singleton object; however, I wouldn't recommend this because:
If you store it in Application class then you liter variables from all Activities into the Application.
In addition, since the Application/Singleton have global scope, you have to make sure to null the variable so it can get garbage collected or it will stick around for the entire lifetime of the application, just wasting memory. However, using the eventBus, the variable is only stored "globally" between the postSticky and removeStickyEvent commands, so it will get garbage collected whenever those Activities do.
Related
I have 2 activities in my assignment: MainActivity and Country_Activity.
I'm trying to pass 2 inputs the user puts in MainActivity:
int counter
String Country
But the app always crashes here: (this is Country_Activity)
private void Update(){
Intent mIntent = getIntent();
int intValue = mIntent.getIntExtra("intCounter", 0);
String country = mIntent.getStringExtra("country");
counterTextView.setText(intValue);
countryTextView.setText(country);
if (country.equals("canada")){
flagView.setImageResource(R.drawable.canada);
}
else if (country.equals("us")){
flagView.setImageResource(R.drawable.us);
}
}
Specifically on the lines "setText" for each variable.
Everything else works. I can't figure out why they wouldn't.
Thanks!
Usually the extras that are passed from one activity to another are read inside on onCreate() where all the needed initialization of variables and views is made.
In your case I see that you get the extras inside another method (maybe it's called inside onCreate()?).
So you forgot to initialize the textviews:
TextView counterTextView = findViewById(R.id.countersomething);
TextView countryTextView = findViewById(R.id.countrysomething);
also another error that you will encounter later is this:
counterTextView.setText(intValue);
change it to:
counterTextView.setText(String.ValueOf(intValue));
Don't pass an integer value inside setText() because it will be treated as the id of a resource.
I am quite new to Android and facing a problem.
I have a class A from where i would like to call another activity. I have found some post saying that there is no way to pause the calling Activity and wait for the result.
public class A extends AppCompatActivity {
[...]
private List<String> list = new ArrayList<String>();
private void doSomething() {
list.add("a");
list.add("b");
for(String tmp:list) {
Intent intent = new Intent(this, OtherActivity.class);
intent.putStringExtra("TAG", tmp);
startActivityForResult(intent, 1);
}
}
This is not a complete example but basically the problem I am facing.
I have a loop and try to open another activity. The loop does not stop when i start the "OtherActivity".
The first thing i see is the OtherActivity for the last element of the list (here String "b"). When i finish this Activity i see the OtherActivity with String "a" in wrong order.
I considered a callback for this, but i am not sure how to implement it because the callback handler wouldn't be within the loop.
Again I am not sure if a callback would be a good idea because many people say i should not Pause the "calling" activity for the sub activity.
You are doing it totally wrong, if you want to send data to other activity and do some work then get the result , i would prefer that send the whole data as a list , do the work and then get the data from that activity , you shouldn't be doing it in a loop. Either pass it is as intent or save it in database then retrieve from database.
If you want to pass the whole list of string to the other activity I suggest you do this
You can pass an ArrayList the same way, if the E type is
Serializable.
You would call the putExtra (String name, Serializable value) of
Intent to store, and getSerializableExtra (String name) for retrieval.
Example:
ArrayList<String> myList = new ArrayList<String>();
intent.putExtra("mylist", myList);
In the other Activity:
ArrayList<String> myList = (ArrayList<String>) getIntent().getSerializableExtra("mylist");
Please note that serialization can cause performance issues: it takes time, and a lot of objects will be allocated (and thus, have to be garbage collected)
Source: Passing a List from one Activity to another
Or as Abdul suggested, save the data to a database and retrieve it from there in the other activity
i currently have a menu item that looks like the following
case R.id.action_settings_rate_app:
Intent intent3 = new Intent(Intent.ACTION_VIEW);
intent3.setData(Uri.parse("market://details?id=com.raptools.app.raptools"));
startActivity(intent3);
bRet=true;
break;
where it says .setData(Uri.parse i would like to call a string and place the link market://details?id=com.raptools.app.raptools in the string.... is this possible to do?
the reason i want to do this is because i have over 25 java files that all call the menu and have the same links in them..... if i could call the string i would only need to change the one string value instead of having to change all the menu items one by one
thanks in advance
It's totally possible, for that you need handle the links, see this link.
So, in your Activity you can get the parameters.
eg.:
MyActivity1
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setData(Uri.parse("my-scheme://my-domain.com/params1"));
startActivity(intent);
MyActivity2
#Override
protected void onCreate(Bundle savedInstanceState) {
...
Uri data = getIntent().getData();
String p = data.getLastPathSegment(); // Variable p is params1.
}
Look into using a Java Properties file to store this value (and possibly others) for your application. If you do this, you can just change the values in the .properties file and your code can pick up the changes.
Hi as per my understanding with your
You want to place link into string.so that it will be easy for you to change at one place
Let me know if I misunderstand your question
You can add link into String/ String builder
For example
Initialize string variable with link
Like
String urlLink="market://details?id=com.raptools.app.raptools";
case R.id.action_settings_rate_app:
Intent intent3 = new Intent(Intent.ACTION_VIEW);
intent3.setData(Uri.parse(urlLink));
startActivity(intent3);
break;
You can add string variable into separate class and declared String variable as public static into it
So that using class name you will get the urlLink wherever you want in the application
I have an array containing serializable objects and am trying to use Intent's putExtra() and Bundle's getSerializable(). However, I am getting a class cast exception and don't understand why.
Below is the code. UserInfo is my own class which implements Serializable, and I have been able to pass individual UserInfo objects between activities. I've only ran into this problem when attempting to use an array.
Code sending the serializable:
Intent intent = new Intent( JOIN_GROUP ); //JOIN_GROUP is a constant string
String user_ids[] = packet.userIDs();
int length = user_ids.length;
UserInfo users[] = new UserInfo[length];
for ( int i = 0; i < length; ++i )
users[i] = getUserByID( user_ids[i] );
intent.putExtra( USERS_IN_GROUP, users );
Code retrieving the serializable:
Bundle extra = intent.getExtras();
String action = intent.getAction();
if ( action.equals(IMService.JOIN_GROUP) )
{
//CLASS CAST EXCEPTION
UserInfo users[] = (UserInfo[]) extra.getSerializable( IMService.USERS_IN_GROUP );
}
Here is the error:
Question
I'm aware I could probably just use a different data structure, but I would like to understand why the array does not work since arrays are serializable?
EDIT: SnyersK was able to get a simpler but similar scenario to work.
So I tried the same thing, and I still get the same exception. It turned my array of Tests into an Object when retrieving the array, which results in the casting exception.
My Test object:
package types;
import java.io.Serializable;
public class Test implements Serializable {
private static final long serialVersionUID = 1L;
private String hello = "hello";
}
Code to pass the array of Test objects:
Test myArray[] = new Test[] { new Test(), new Test() };
Intent i = new Intent( this, Login.class );
i.putExtra( "key", myArray );
Code to retrieve the array of Test objects:
Bundle extras = getIntent().getExtras();
Test array[] = (Test[]) extras.getSerializable( "key" ); //Class Cast Exception
Apparently this is a bug on older versions of Android. (Version 5.0.1 is the only version tested on which it works like expected, perhaps it works from 5.0 and up)
The bug
Let's say we have an Array of an object called User which implements Serializable.
User[] users;
When we try to pass this array to another activity through an intent like this
intent.putExtra("myKey", users);
our users will get converted to Object[].
If we try to get our array from the intent in the second activity like so
User[] users = getIntent().getSerializableExtra("myKey");
We will get a ClassCastException.
From the docs, we can conclude that this shouldn't be a problem since Array is a serializable class, and putExtra(String key, Serializable value) has been added since api 1.
If you want to pass an Array through an intent on Android versions prior to Android 5.0.1 (maybe some older versions work aswell, but up to Android 4.3 it is NOT working)
You'll have to work around it. You could do this by converting your Array to an ArrayList.
EDIT
another workaround is copying your extra to a new array, thus, not having to cast it. I'm not sure about the positive/negative consequences of the method though. It would look like this:
Object[] array = (Object[]) getIntent().getSerializableExtra("key");
User[] parsedArray = Arrays.copyOf(array, array.length, User[].class);
I found this method here: How to convert object array to string array in Java.
Replace
intent.putExtra( USERS_IN_GROUP, users );
with
intent.putExtra( USERS_IN_GROUP, new ArrayList<UserInfo>(Arrays.asList(users)));
try like this:
Intent intent = new Intent( JOIN_GROUP ); //JOIN_GROUP is a constant string
String user_ids[] = packet.userIDs();
int length = user_ids.length;
UserInfo users[] = new UserInfo[length];
for ( int i = 0; i < length; ++i )
users[i] = getUserByID( user_ids[i] );
Bundle bnd=new Bundle();
bnd.putSerializable(USERS_IN_GROUP, users);
while sending you are attaching to intent and while retrvng you are reading from the bundle (which is intent extras).
Is the UserInfo inner class or a separate java class file?
If it is an inner class, then the parent class also should be Serializable.
If not, make UserInfo class implement Parcelable and use
intent.putParcelableArrayListExtra(USERS_IN_GROUP, new ArrayList<UserInfo>(Arrays.asList(users)));
I have application where Activity A allows to set some options and starts (after click on button) Activity B. User can do something in B and when he finishes, he has choice (RadioButtons):
repeat - it means the B Activity will run again with the same options (taken from A),
new - it means application finishes B Activity and goes back to A, where user can set options again and start B again,
end - it goes out from application (I suppose it should finish B and then A Activity).
First I have done this way:
Intent intent = getIntent();
finish();
startActivity(intent);
Another way I could use is to clean all parameters in this Activity, but above was more quickly.
Second is just a finish().
Third is the biggest problem and i don't know how to to this. I tried with startActivityForResult(), onActivityResult() and setResult() but i saw it's impossible to set different results depending on selected RadioButton.
Other method I found is
public static void closeAllBelowActivities(Activity current) {
boolean flag = true;
Activity below = current.getParent();
if (below == null)
return;
System.out.println("Below Parent: " + below.getClass());
while (flag) {
Activity temp = below;
try {
below = temp.getParent();
temp.finish();
} catch (Exception e) {
flag = false;
}
}
}
source
But don't know how to put in current Activity.
Could you help me with this?
"i saw it's impossible to set different results depending on selected RadioButton" isn't really clear to me. Anyway, I suggest you what I would do: Activity A starts Activity B with startActivityForResult() and A wait for a bundle coming from B. When you build the exit function from B to A, create a bundle with your result. In A, you will analyze the bundle coming from B and decide what to do with. If you would exit, call finish().
Edit: Ok this could be your case:
Activity A:
public class XY extends Activity {
// you need that as a flag to go back and forth:
protected static final int SUB_ACTIVITY_REQUEST_CODE_04 = 5337; // choose the number you want...
int result_from_B; // I usually use an int, choose as you want....
static final String KEY_FROM_B = "mKey";
#Override
protected void onActivityResult(int result,int resultCode,Intent data) {
super.onActivityResult(result, resultCode, data);
if (result == SUB_ACTIVITY_REQUEST_CODE_04) {
if (data!=null){
Bundle extras = data.getExtras();
result_from_B = extras.getInt(XY.KEY_FROM_B);
if (result_from_B==1) {
// do what you want
} else {
// do somthing else...
}
}
To call the Activity B, use this:
Intent i = new Intent(this,
ActB.class);
this.startActivityForResult(i,SUB_ACTIVITY_REQUEST_CODE_04);
In the Activity B:
public class ActB extends Activity{
protected final int SUCCESS_RETURN_CODE = 1; // you need it to come back
int result; // this is the result to give to activity A
}
// in the function to build the output:
// I suppose you have already put something in result:
Bundle bundle = new Bundle();
bundle.putInt(XY.KEY_FORM_B, result);
Intent mIntent = new Intent();
mIntent.putExtras(bundle);
ActB.this.setResult(SUCCESS_RETURN_CODE,mIntent);
finish();
This is basic. You can manage also booleans back and forth, arrays, all you want (admitted by a bundle). Just put it in a bundle and go :)
Don't forget to declare your classes (activities) in the Manifest otherwise it will throw an exception runtime.
First of all, you need to keep track of the Intent used to call B. Try the putExtra() method of the intent to B. You can also package everything into a Bundle and restore it with getExtras() (if I recall correctly, that's the method name). When on B, read the Intent used to call it and save the parameters. You also need to startActivityForResult(B) for the following to work.
repeat - it means the B Activity will run again with the same options
(taken from A),
You probably want to call, from B, Activity B again using the FLAG_ACTIVITY_SINGLE_TOP flag in this case. I assume you don't want to have two B instances. Otherwise, just don't use the flag.
Put the Bundle you received from the Intent (from A) again, and catch it (if using single top) in the onNewIntent() method (or just normally, onCreate, if not single top). It goes like this: B -> B onPause() -> B onNewIntent() -> B onResume().
new - it means application finishes B Activity and goes back to A,
where user can set options again and start B again,
Depending on the exact behavior you want, you could call A with FLAG_ACTIVITY_REORDER_TO_FRONT. In this case, you end up with A in the foreground and B in the background (pressing back will go back to B).
Or you could call finish() if you just don't want B anymore, and want to go back to A.
end - it goes out from application (I suppose it should finish B and
then A Activity).
Do nothing on B, setResult() to something like "RESULT_FINISH_EVERYTHING", and when taking care of the results in A (override "onActivityResult()", IIRC), finish activity A also.
but i saw it's impossible to set different results depending on
selected RadioButton.
You could setResult() depending on thw button checked in the radio button. You can set listeners to the radio group and read which button is selected. See RadioGroup.OnCheckedChangeListener or View.OnClickListener if you need actions for eadch individual radio button.
Really, not too complicated. It just depends on what you want. I can clarify all this if you want.
Good luck!