Having a little trouble when trying to return a byte array from an activity. The return code is:
private void returnLocation(byte[] mapImage) {
Intent intent = new Intent();
intent.putExtra("mapImage", mapImage);
setResult(RESULT_OK, intent);
finish();
}
EDIT: This is how I call and try to receive it in the parent activity:
....
Intent i = new Intent(getActivity(), ChildActivity.class);
ParentFragment.this.startActivityForResult(i, 255);
...
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode == 255) {
if(resultCode == Activity.RESULT_OK) {
mImage = data.getByteArrayExtra("mapImage");
}
}
}
I've a breakpoint on the onActiviyResult that never gets hit when i try returning a byte array.
However, when trying to return the intent it goes back to the first activity (not the one that called it). I can't see anything that suggests a problem in the logger.
If I change the Extra value to '5' (an integer), it returns fine.
Is there something I'm missing when trying to pass back a byte array?
Thanks
Android has a limit on the size of a Bundle, which is what the Intent uses internally. If the data exceeds the bundle size it will display ERROR/JavaBinder(7881): !!! FAILED BINDER TRANSACTION !! in the logs, but it won't throw an exception.
Try writing the byte array to a temp file and passing the file name in the Intent.
I figured that you are calling startActivityForResult(i, 255) from a Fragment.
Instead of calling ParentFragment.this.startActivityForResult(i, 255);
you should call : startActivityForResult(i, 255);
If the above approach doesnt work, try the following:
Since the Activity that is hosting your fragment gets onActivityResult() result so you need to override activity's onActivityResult(), call super.onActivityResult() in your fragment to propagate to respective fragment for unhandled results codes or for all.
Related
I am developing an android app which is used to add text on image and do some editing. I have the main image editing activity (mainEditActivity) where I have my image, textview and editing panel. I can change the selected image in two ways
Select one from the gallery which used the following code
pickGalleryBtn.setOnClickListener((View view) -> {
Intent intent = new Intent();
intent.setType("image/*");
intent.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(intent, "Select Picture"), PICK_IMAGE);
});
and on activity result
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == PICK_IMAGE && null != data) {
Uri selectedImageUri = data.getData();
Intent intent = new Intent(mainEditActivity, ImageCropActivity.class);
intent.putExtra("image.url", selectedImageUri.toString());
mainEditActivity.startActivity(intent);
} else {
Toast.makeText(getContext(), "There was an error reading the file", Toast.LENGTH_LONG);
}
}
ImageCropActivity will start the MainEditActivity after cropping the image
The user can also download an image by going to another page, which will again go through ImageCropActivity and land on MainEditActivity.
My problem is when user is changing the image through any of the above ways, the preferences (such as, text size, position, color, font ..) set on the textview is getting lost as the MainEditActivity restarts.
Is there any way I can save the textView itself (not just the text) so the user will not lose the preferences. I have tried, passing data intent, sharedprefrences, savedinstancestate etc but they will only allow String or Serializable object (TextView is not serializable)
Thanks Manish
I realized that there is no need to pass/save TextView object. I can consider the MainEditActivity as a parent activity for all other activities where the control is passed to other activities, but not completely. Before I used to start the activity using startActivity method which causes to lose all the data in that activity. Now I have changed the way I am calling the activities using startActivityForResult so that I will set the necessary data from other activities in MaindEditActivity.
I'm trying to port an Android app to the new support library (support-v4:21.0.0) and I'm having trouble starting Activities from Fragments with a transition.
In my Activities, I've been doing something like:
Bundle options = ActivityOptionsCompat.makeSceneTransitionAnimation(this).toBundle();
ActivityCompat.startActivityForResult(this, intent, REQUEST_SOMETHING, options);
which works fine for Activities. However, if I try to do something similar with Fragments, like:
Activity activity = getActivity();
Bundle options = ActivityOptionsCompat.makeSceneTransitionAnimation(activity).toBundle();
ActivityCompat.startActivityForResult(activity, intent, REQUEST_SOMETHING, options);
it turns out that onActivityResult() is not called for the Fragment, but only the enclosing Activity. I haven't found anything in the support library to pass the options Bundle as a parameter to startActivityForResult() on an actual Fragment and have it call back to onActivityResult() in that Fragment. Is this possible?
The simplest solution would be to handle all onActivityResult() calls in the Activity itself, but I'd rather not do that because I have a ton of possible Fragments that may be receiving that callback.
Help is appreciated. Thanks!
Sadly, ActivityCompat.startActivityForResult() doesn't work quite right in Fragments (see Alex Lockwood's answer). For several weeks I marvelled at how Google never gave us an ActivityCompat method equivalent to Fragment's implementation of startActivityForResult(). What were they thinking?! But then I had an idea: Let's take a look at how the method is actually implemented.
As a matter of fact, startActivityForResult() in Fragment is different from the one in Activity (see here):
public void startActivityForResult(Intent intent, int requestCode) {
if (mActivity == null) {
throw new IllegalStateException("Fragment " + this + " not attached to Activity");
}
mActivity.startActivityFromFragment(this, intent, requestCode);
}
Now startActivityFromFragment() looks like this (see here):
public void startActivityFromFragment(Fragment fragment, Intent intent,
int requestCode) {
if (requestCode == -1) {
super.startActivityForResult(intent, -1);
return;
}
if ((requestCode&0xffff0000) != 0) {
throw new IllegalArgumentException("Can only use lower 16 bits for requestCode");
}
super.startActivityForResult(intent,
((fragment.mIndex + 1) << 16) + (requestCode & 0xffff));
}
Google uses some odd byte shifting on the request code to make sure only the calling Fragment's onActivityResult() is called afterwards. Now since ActivityCompat doesn't provide any startActivityFromFragment(), the only option left is to implement it yourself. Reflection is required to access the package private field mIndex.
public static void startActivityForResult(Fragment fragment, Intent intent,
int requestCode, Bundle options) {
if (Build.VERSION.SDK_INT >= 16) {
if ((requestCode & 0xffff0000) != 0) {
throw new IllegalArgumentException("Can only use lower 16 bits" +
" for requestCode");
}
if (requestCode != -1) {
try {
Field mIndex = Fragment.class.getDeclaredField("mIndex");
mIndex.setAccessible(true);
requestCode = ((mIndex.getInt(this) + 1) << 16) + (requestCode & 0xffff);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new RuntimeException(e);
}
}
ActivityCompat.startActivityForResult(fragment.getActivity(), intent,
requestCode, options);
} else {
fragment.getActivity().startActivityFromFragment(this, intent, requestCode);
}
}
Copy that method anywhere you like and use it from your Fragment. Its onActivityResult() will be called as it should.
UPDATE:
Support library v23.2 was released and it seems startActivityFromFragment(Fragment fragment, Intent intent, int requestCode, Bundle options) does the job now :)
The ActivityCompat#startActivityForResult() method is just a proxy for the activity's startActivityForResult(Intent, Bundle) method. Calling the method from inside a fragment class doesn't mean that the Fragment's onActivityResult() will eventually be called as I'm sure you've found out. The framework has know way of knowing from which class the call originated... the only correct behavior would be to call the Activity's onActivityResult() method in this case.
It sounds like the best option would be to handle everything in the activity's onActivityResult() method as you suggested in your post.
You can create a listener interface or simply a public function in your fragment and passing the arguments from which you are getting in onActivityResult() of the activity to the listener or the public method of the fragment and do your desired work over there.
A simple way:
in Fragment:
ActivityOptionsCompat options = ActivityOptionsCompat.makeSceneTransitionAnimation();
this.startActivityFromFragment(this, intent, requestCode, options);
I'm trying to take apicture and I want to pass this picture to another activity to be displayed in it.
OnClickListener listener_TakePic = new OnClickListener() {
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
intent = new Intent(android.provider.MediaStore.ACTION_IMAGE_CAPTURE);
startActivityForResult(intent, CAMERA_PIC_REQUEST);
}
};
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == CAMERA_PIC_REQUEST && resultCode == RESULT_OK) {
Bitmap image = (Bitmap) data.getExtras().get("data");
}// End IF
}// End of Method
Please tell me what should I do or modify to achieve what I want..
Actually, i have created an application class "base class" in which, I have defined an "bitmap cameraPic" and "static final int CAMERA_PIC_REQUEST = 1;"
Now, I have an activity classed named "AddLocation" from which I call startActivityForResult(intent, CAMERA_PIC_REQUEST);
but I want the result of the camera Picture to appear in another activity called "MPActivity"
My question is, should I call "onActivityResult(int requestCode, int resultCode, Intent data)" method from "MPActivity" or there is no need to call it...
i'm really confused please clarify..
There are more than one way to tackle the task you are doing.
you can build a java class and put populates its one of property by the desired image. Then you can just get stuff that into an arraylist and pass that to a global arraylist.
you can use Application class and make a global image variable that can be accessed in every class in your activity.
etc ...
I am new to android so please excuse the newbie question. I have a game I am trying to port from an old Java applet to android. My goal is to get this functional and then post an article on a site like CodeProject (or a better one if there are ones more appropriate). The idea is to show that a person brand new to android development can create an app in a reasonable amount of time.
I am making some progress but have run into a problem. I have the main activity in which the user interacts with. I then created a menu item that in turn starts a second activity (call it child) with a modest number of checkbox's, seekbar's etc to fill in parameters. I can successfully pass the class containing all the options from main to child. But I cannot get the child to pass this data back to the main.
First here is my main code that starts the child activity:
public void addBalls()
{
Intent myIntent = new Intent(this, GameOptions.class);
Bundle b = new Bundle();
b.putSerializable("options", gameParams);
myIntent.putExtras(b);
startActivityForResult(myIntent,STATIC_OPTIONS_VALUE);
}
The data passed to the child (and hopefully back again) is:
public class GameOptionParams implements Serializable
{
private static final long serialVersionUID = 1L;
public int speedBarPosition;
public int vgravityBarPosition;
public int mgravityBarPosition;
public int viscosityBarPosition;
public int restititionBarPosition;
public boolean trace;
public boolean collide;
public boolean mush;
public boolean wrap;
public boolean flicker;
}
And here is the expected return (again in main)
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
switch(requestCode)
{
case (STATIC_OPTIONS_VALUE) :
{
if (resultCode == Activity.RESULT_OK)
{
//retrieve intended options
Bundle b = data.getExtras();
gameParams = (GameOptionParams) b.getSerializable("options");
}
break;
}
}
}
The child activity successfully receives the gameParams data. It then interacts with the user to update the values and then I attempt to return it but it does not seem to get sent to main. Here is the child code in the onStop() override.
Maybe this code should not be in the onStop() override but I can't determine where else to place it.
#Override
public void onStop()
{
super.onStop();
//read widget values
gameParams.speedBarPosition = speedBar.GetPosition();
gameParams.vgravityBarPosition = vgravityBar.GetPosition();
gameParams.mgravityBarPosition = mgravityBar.GetPosition();
gameParams.viscosityBarPosition = viscosityBar.GetPosition();
gameParams.restititionBarPosition = restititionBar.GetPosition();
//todo save to persistent
Intent resultIntent = new Intent(this, TiltBall2ImpactActivity.class);
Bundle b = new Bundle();
b.putSerializable("options", gameParams);
resultIntent.putExtras(b);
setResult(Activity.RESULT_OK, resultIntent);
}
Back in the main onActivityResult override I always see requestCode=0, resultCode=0, data=null. I assume this is a typical newbie problem, I have been reading the sdk documentation, user forums etc and have come close to a solution but just not quite there yet. Any help would be appreciated.
Since this is sort of a setting menu for the game, I assume you are going to need these values for more than one activity. If so you extend the android.app.Application class.
In that class you can create attributes to hold your values. In any activity you can call
MyApplication myApp = (MyApplication)getApplicationContext();
where myApp is a singleton. So you will get the values you set from another activity.
You will need to add this code to your application tag in the manifest file for it to work
android:name=".MyApplication"
If you need to keep these values for next startup of the application, you need to use SharedPreferences. This is a good tutorial for that
http://saigeethamn.blogspot.com/2009/10/shared-preferences-android-developer.html
Assuming in your 'child' activity, the user has to press an 'OK' or 'Save' button then put the code to set the gameParams parameters in the button's onClick(...) handler.
Use the default constructor for instantiating the Intent, example...
Intent resultIntent = new Intent();
...then after creating the Bundle and adding gameParams to it and calling setResult(...), simply call finish() to terminate the 'child' activity. There aren't many occasions that I can think of to override onStop() and I suspect you don't want to be using it to attempt returning the Intent.
I need some help creating a properties page in Android.
I have created an Activity and have a TableLayout with a title, 5 properties that include a Spinner to select a property class and a EditText that the user can type into, followed by a couple of buttons reading Accept and Cancel.
I am launching the activity by creating a new Intent with that class and using a StartActivityForResult, where I need to Bundle all of the properties back to my main activity. I have an OnActivityResult defined in the main class. I am having difficulty in the properties page on how to return the activity result from the button callback and how to package and return the Bundle. Any not so simple examples would be appreciated.
on the Activity that is returning the result you would do something like this
Intent i = new Intent();
i.putExtra("value_a", someValue);
i.putExtra("value_b", anothervalue);
setResult(RESULT_OK, i);
finish();
then in the activity that is waiting for the result you would do something like this
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (resultCode == Activity.RESULT_OK && requestCode == 0) // 0 would be whatever id you gave this when you started the activity for result
{
Bundle extras = data.getExtras();
String property_a = extras.getString("value_a");
String property_b = extras.getString("value_b");
// ... whatever else you need to with the results, maybe they are not strings...??
}
}
You can use Preference Activity to store yours application settings