onActivityResult not call in the Fragment - android

The structure of the app is like this:
tabHost (in Activity) -> contains -> TabFragment(extend base container fragment)
1. The code in Activity:
tabHost.addTab(
tabHost.newTabSpec("home").setIndicator("",
getResources().getDrawable(R.drawable.btn_home)),
HomeFragment.class, null);
2. The code in HomeFragment
(Notice that HomeFragment is not the actual function but a container like this, and it extend BaseContainerFragment):
public class HomeFragment extends BaseContainerFragment {
public Home homeFrag;
private boolean mIsViewInited;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.container_fragment, null);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (!mIsViewInited) {
mIsViewInited = true;
initView();
}
}
private void initView() {
homeFrag = new Home();
replaceFragment(homeFrag, false);
}
}
3. BaseContainerFragment
public class BaseContainerFragment extends Fragment {
public void replaceFragment(Fragment fragment, boolean addToBackStack) {
FragmentTransaction transaction = getChildFragmentManager().beginTransaction();
if (addToBackStack) {
transaction.addToBackStack(null);
}
transaction.replace(R.id.container_framelayout, fragment);
transaction.commit();
}
public boolean popFragment() {
boolean isPop = false;
if (getChildFragmentManager().getBackStackEntryCount() > 0) {
isPop = true;
getChildFragmentManager().popBackStack();
}
return isPop;
}
}
4. In the Home (The actual content of the fragment)
UploadType fragment = new UploadType();
Bundle bundle = new Bundle();
bundle.putString("form_type", "request");
fragment.setArguments(bundle);
((BaseContainerFragment)getParentFragment()).replaceFragment(fragment, true);
5. And in the UploadType , I call the camera activity but onActivityResult is only return in the main activity.
startActivityForResult(intent, REQUEST_CAMERA);
public void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.d("test1", "result2");
super.onActivityResult(requestCode, resultCode, data);
}
How can I trigger the onActivityResult at UploadType? Thanks for help.

The reason why this doesn't work is because you are calling startActivityForResult() from within a nested fragment. Android is smart enough to route the result back to an Activity and even a Fragment, but not to a nested Fragment hence why you don't get the callback.
(more information to why that doesn't work here or on stackoverflow)
Now in order to make it work I suggest you manually route the callback to the ChildFragment (=UploadType) in the ParentFragment (=BaseContainerFragment):
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Fragment uploadType = getChildFragmentManager().findFragmentById(R.id.container_framelayout);
if (uploadType != null) {
uploadType.onActivityResult(requestCode, resultCode, data);
}
super.onActivityResult(requestCode, resultCode, data);
}

In my case, I've done by adding following code in my MainActivity.java
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
for (Fragment fragment : getSupportFragmentManager().getFragments()) {
fragment.onActivityResult(requestCode, resultCode, data);
}
}

In your Activity Override onActivityForResult() like this
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
}
Now in your fragment u can get the activity result inside this
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Log.d("test1", "result2");
}
Make sure when your are calling start ActivityForResult in your frragment it should be like this
startActivityForResult(intent, REQUEST_CAMERA);

For NavHostFragment of Navigation Architecture Component
If you are using single activity and have fragments inside the NavHostFragment, there is an issue of onActivityResult() of the child fragment of NavHostFragment not getting called.
To fix this issue, you need to call the onActivityResult() of the child fragments manually from inside the onActivityResult() of the host activity. The host activity is the activity that hosts your NavHostFragment.
Here's the Kotlin code for onActivityResult() of your host activity:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
val navHostFragment = supportFragmentManager.findFragmentById(R.id.your_nav_host_fragment)
val childFragments = navHostFragment?.childFragmentManager?.fragments
childFragments?.forEach { it.onActivityResult(requestCode, resultCode, data) }
}

TabActivity->ActivityA->FragmentB, it's not work.
use a bad bad bad way:
ActivityA.java
public void onSelectSomething(){
...
startActivityForResult(intent, 22222);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (mFragment != null) {
mFragment.onActivityResult(requestCode, resultCode, data);
}
}
FragmentB.java
if(getActivity() instanceof ActivityA) {
((RepairerListActivity)getActivity()).onSelectSomething();
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 22222) {
// do things
}
}

#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// Loop through all child fragments of the activity
for (Fragment fragment : getSupportFragmentManager().getFragments()) {
// check if the current fragment is YourFragment
if (fragment instanceof YourFragment ) {
fragment.onActivityResult(requestCode, resultCode, data);
}
}
}

Related

onActivityResult from Activity to Fragment

I have a problem regarding onActivityResult. First, I opened the Add New Message Fragment to select the image. When I select the image, it doesn't return the result to my current fragment. I put onActivityResult in both my MainActivity and AddMessageFragment but it doesn't call the result in my fragment. My MainActivity is used to set up the Navigation Controller. I use Matisse library for my image picker. Can someone please help me with me? Been stuck for the whole day with this issue.
MainActivity
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
}
AddMessageFragment
#OnClick({R.id.addImage})
public void openGallery()
{
permission.addOnStorageListener(new Permission.OnStorageSuccess()
{
#Override
public void OnStorageSuccess()
{
permission.requestCamera();
}
});
permission.addOnCameraListener(new Permission.OnCameraSuccess()
{
#Override
public void OnCameraSuccess()
{
Matisse.from(getActivity())
.choose(MimeType.of(MimeType.JPEG, MimeType.PNG))
.countable(false)
.capture(true)
.captureStrategy(new CaptureStrategy(true, "com.gprop.users.fileprovider"))
.maxSelectable(1)
.restrictOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT)
.thumbnailScale(0.85f)
.imageEngine(new Glide4Engine())
.originalEnable(false)
.forResult(99);
}
});
permission.requestStorage();
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
if(requestCode == 99 && resultCode == Main.RESULT_OK)
{
mSelected = Matisse.obtainPathResult(data);
if(mSelected.size() > 0)
{
Glide.with(this).load(mSelected.get(0)).into(addImage);
Luban.compress(new File(mSelected.get(0)), getActivity().getFilesDir())
.putGear(Luban.THIRD_GEAR)
.asObservable()
.subscribe(new Consumer<File>()
{
#Override
public void accept(File file) throws Exception
{
newfile = file;
}
}, new Consumer<Throwable>()
{
#Override
public void accept(Throwable throwable) throws Exception
{
throwable.printStackTrace();
Toast.makeText(getActivity(), throwable.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
else
{
Toast.makeText(getActivity(), "No image selected", Toast.LENGTH_SHORT).show();
}
}
}
You are calling Matisse.from() on the Activity which you are getting from the getActivity() method, tit must be returning you your MainActivity and the onActivityResult will be called for the MainActivity where you are doing nothing and calling super.onActivityResult().
Possible Solutions: .
Shift your onActivityResult code logic from your AddMessageFragment to MainActivity
Change you Matisse call from Matisse.from(getActivity()) to Matisse.from(this), because looking at the source code of Matisse it also supports Fragment context.
Using the second solution you should get your onActivityResult callback in the fragment and you won't need to change/shift any other code logic.
Hope this helps :)
An explicit call from fragment to the onActivityResult function is as follows.
In the parent Activity class, override the onActivityResult() method and even override the same in the Fragment Class and call as the following code.
In MainActivity class:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.layoutContainer);
fragment.onActivityResult(requestCode, resultCode, data);
}
In AddMessageFragment class:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// In fragment class callback
}
Replace your activity onActivityResult method by below code
public void onActivityResult(int requestCode, int resultCode, Intent intent) {
super.onActivityResult(requestCode, resultCode, intent);
Fragment fragment = (Fragment) getChildFragmentManager().findFragmentByTag(childTag);
if (fragment != null) {
fragment.onActivityResult(requestCode, resultCode, intent);
}
}
It will call your fragment onActivityResult after this execute.
OnActivityResult() function works on Activity. I suggest you call this function on your activity and implement your logic inside your fragment onResume() function. In order to get data from Activity use global val.

resultCode 0 and data zero in onActivityResult

I have activity with one fragment, and then that fragment call some activity which that activity will give some value into first activity. i use onActivityResult but i don't know why resultCode always 0 and data always zero,.
on Activity One i have
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Log.d(TAG, "onActivityResult: "+ requestCode +" "+resultCode+" "+data);
}
Activity one have some fragmentX which call activity two
private final int REQUEST_CODE = 10;
private void start (){
Intent intent = new Intent(getContext(),Main2Activity.class);
intent.putExtra("xxx","test1");
getActivity().startActivityForResult(intent,REQUEST_CODE);
}
then in Activity Two, when i touch onBackpress, will pass some value.
public class Main2Activity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
}
#Override
public void onBackPressed() {
super.onBackPressed();
Intent intent = getIntent().putExtra("yyy","test2");
setResult(RESULT_OK,intent);
}
}
but, i don't know why, onActivityResult i can't get the data.
my final purpose is, i want to setArgument that data to fragmentX.
1.You can call onActivityResult in the fragment
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
Log.d(TAG, "onActivityResult: "+ requestCode +" "+resultCode+" "+data);
}
2.Use super.onBackPressed(); after setResult in your method
#Override
public void onBackPressed() {
Intent intent = getIntent().putExtra("yyy","test2");
setResult(RESULT_OK,intent);
super.onBackPressed();
}
In first activity write the below code:
1st method:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
for (Fragment fragment : getSupportFragmentManager().getFragments()) {
fragment.onActivityResult(requestCode, resultCode, data);
}
}
In Fragment
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// In fragment write your logic here
}
2nd method: (I didn't try but as per doc may be this is one of the reason try once) if it will not work go 1st method its 100 percent solution
Here when your calling second activity using getContext()
getContext() - Returns the context view only current running activity.
getActivity()- Return the Activity this fragment is currently associated with.
Try instead of getContext() use getActivity() when you calling intent to next activity
Ex:
private final int REQUEST_CODE = 10;
Intent intent = new Intent(getActivity(),Main2Activity.class);
intent.putExtra("xxx","test1");
getActivity().startActivityForResult(intent,REQUEST_CODE);
For start new activity
private final int REQUEST_CODE = 10;
private void start (){
Intent intent = new Intent(getContext(),Main2Activity.class);
intent.putExtra("xxx","test1");
getActivity().startActivityForResult(intent,REQUEST_CODE);
}
From Second activity
public class Main2Activity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
}
#Override
public void onBackPressed() {
super.onBackPressed();
Intent intent = getIntent().putExtra("yyy","test2");
setResult(10,intent);
}
}
you have to set the integer code using which you have started second activity. you have started second activity with the code "10".so use the same value when you setResult(10,intent);
onActivityResult you need to check Request code
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if(requestCode==10){
if(data!=null)
{
//you have to manage your own list of fragments for activity because getSupportFragmentManager().getFragments() is deprecated now.
//Send data to fragments
if (arrayFragments != null) {
for (Fragment fragment : arrayFragments) {
fragment.onActivityResult(requestCode, resultCode, data);
}
}
}
}
}
Remember you have to manage your own list of fragments using ArrayList or HashMap.
Hope this will help you if you need any other help inform me.
if you wants to send return data in onActivityResult then you should use super.onBackPressed() after data set in setResult() method
example:
#Override
public void onBackPressed() {
val intent = Intent()
intent.putExtra("IsReturnData", true)
setResult(RESULT_OK,intent);
super.onBackPressed(); //write this line at the end of method
}

issue in onActivityResult with sony xperia

i start activity for result to open GPS
then recieve in OnACtivityResult .. it is work fine in some mobiles , but with sony not work , i don't know why
i use nested fragment
start activity
Intent callGPSSettingIntent = new Intent(
android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
startActivityForResult(
callGPSSettingIntent, openGPSRequest);
then receive in fragment
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == openGPSRequest) {
try {
activity.hideProgress();
} catch (Exception e) {
}
activity.replaceCurrentFragment(
FramentNavigationMapInside.getInstance(branche), true, true);
}
}
in main activity
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
}
and in every fragment override onActivityResult
and i test it in lenove and samsung and work fine ,, but with sony xperia not work, only onActivityResult which in main activity call
solve my issue by
One of the common problem we always meet in the world of Fragment is: although we could call startActivityForResult directly from Nested Fragment but it appears that onActivityResult would never been called which brought a lot of trouble to handle Activity Result from Nested Fragment.
the solution
So we will call getActivity().startActivityForResult(...) from Fragment instead of just startActivityResult(...) from now on. Like this:
// In Fragment
Intent intent = new Intent(getActivity(), SecondActivity.class);
getActivity().startActivityForResult(intent, 12345);
As a result, all of the result received will be handled at the single place: onActivityResult of the Activity that Fragment is placed on.
Question is how to send the Activity Result to Fragment?
Due to the fact that we couldn't directly communicate with all of the nested fragment in the normal way, or at least in the easy way. And another fact is, every Fragment knows that which requestCode it has to handled since it is also the one that call startActivityForResult. So we choose the way to "broadcast to every single Fragment that is active at time. And let those Fragments check requestCode and do what they want."
Talk about broadcasting, LocalBroadcastManager could do the job but the mechanic is the way too old. I choose another alternative, an EventBus, which has a lot of choices out there. The one that I chose was Otto from square. It is really good at performance and robustness.
dependencies {
compile 'com.squareup:otto:1.3.6'
}
In the Otto way, let's create a Bus Event as a package carry those Activity Result values.
import android.content.Intent;
/**
* Created by nuuneoi on 3/12/2015.
*/
public class ActivityResultEvent {
private int requestCode;
private int resultCode;
private Intent data;
public ActivityResultEvent(int requestCode, int resultCode, Intent data) {
this.requestCode = requestCode;
this.resultCode = resultCode;
this.data = data;
}
public int getRequestCode() {
return requestCode;
}
public void setRequestCode(int requestCode) {
this.requestCode = requestCode;
}
public int getResultCode() {
return resultCode;
}
public void setResultCode(int resultCode) {
this.resultCode = resultCode;
}
public Intent getData() {
return data;
}
public void setData(Intent data) {
this.data = data;
}
}
import android.os.Handler;
import android.os.Looper;
import com.squareup.otto.Bus;
/**
* Created by nuuneoi on 3/12/2015.
*/
public class ActivityResultBus extends Bus {
private static ActivityResultBus instance;
public static ActivityResultBus getInstance() {
if (instance == null)
instance = new ActivityResultBus();
return instance;
}
private Handler mHandler = new Handler(Looper.getMainLooper());
public void postQueue(final Object obj) {
mHandler.post(new Runnable() {
#Override
public void run() {
ActivityResultBus.getInstance().post(obj);
}
});
}
}
And in activity
public class MainActivity extends ActionBarActivity {
...
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
ActivityResultBus.getInstance().postQueue(
new ActivityResultEvent(requestCode, resultCode, data));
}
...
}
and in the end handle back data onActivityResult in fragment
public class BodyFragment extends Fragment {
...
#Override
public void onStart() {
super.onStart();
ActivityResultBus.getInstance().register(mActivityResultSubscriber);
}
#Override
public void onStop() {
super.onStop();
ActivityResultBus.getInstance().unregister(mActivityResultSubscriber);
}
private Object mActivityResultSubscriber = new Object() {
#Subscribe
public void onActivityResultReceived(ActivityResultEvent event) {
int requestCode = event.getRequestCode();
int resultCode = event.getResultCode();
Intent data = event.getData();
onActivityResult(requestCode, resultCode, data);
}
};
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
// Don't forget to check requestCode before continuing your job
if (requestCode == 12345) {
// Do your job
tvResult.setText("Result Code = " + resultCode);
}
}
...
}
hope this code help any one face this problem

onActivityResult not being called in custom Fragment or anywhere else attempted

There have been many successful answers to this question, but there's still something I'm not understanding or that I'm doing incorrectly. One answer is implementing onActivityResult in the host Activity, but I guess I don't know which one that is or I'm following it wrong.
And no, I'm not calling getActivity.startActivityForResult(), just startActivityForResult().
Depending on a selection made in FirstActivity, one or more other selections are possible, created using Fragments. One Fragment is ButtonFragment, which when selected, starts OptionsActivity, like so:
public class ButtonFragment extends Fragment
{
.....
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
if(resultCode != Activity.RESULT_CANCELED)
{
if(requestCode == OPTIONS_REQUEST_CODE)
{
Bundle extras = data.getExtras();
if (extras != null) {
String selection = (String) extras.get("optionsSelection");
data.setText(selection);
}
}
}
}
private void openOptionsActivity()
{
Intent intent = new Intent(getActivity(), OptionsActivity.class);
intent.putExtra("optionsArray", options);
startActivityForResult(intent, OPTIONS_REQUEST_CODE);
}
}
This fragment is being added in BaseActivity:
public class BaseActivity extends FragmentActivity
{
.....
fm.beginTransaction().add(
R.id.FragmentContainer, frag).commitAllowingStateLoss();
fm.executePendingTransactions();
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
finish();
}
}
Inside OptionsActivity:
public class OptionsActivity extends BaseSpinnerActivity
{
.....
private class OptionsAdapter extends BaseSpinnerAdapter
{
public OptionsAdapter(Context context, Object[] values)
{
super(context, values);
}
protected void fillRow(ViewHolder holder, int position)
{
String option = options[position];
if(option != null) {
holder.text.setText(option);
}
}
protected void onRowSelect(View v)
{
Intent returnIntent = new Intent();
String optionSelection = (String)v.getTag();
returnIntent.putExtra("optionSelected", optionSelection);
setResult(RESULT_OK, returnIntent);
finish();
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
finish();
}
}
The same thing is done inside BaseSpinnerActivity, which extends from ListActivity. (I know, should use FragmentActivity, but I haven't had a chance to convert it yet.)
None of these onActivityResult()'s are being called.
What am I missing or doing wrong? Any help is appreciated!

Xamarin.Android OnActivityResult not being called inside a Fragment

It appears as if OnActivityResult does not get called after accepting the picture taken from the camera.
Am I calling StartActivityForResult() wrong?, or is there something I am missing.
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Android.OS.Bundle savedInstanceState)
{
var m_View = inflater.Inflate (Resource.Layout.Feed, null);
btnCamera = m_View.FindViewById<Button> (Resource.Id.btnCamera);
btnGallery = m_View.FindViewById<Button> (Resource.Id.btnGallery);
ivPicture = m_View.FindViewById<ImageView> (Resource.Id.imageView1);
btnCamera.Click += (sender, e) => {
//launch gallery
//allow photo editing/saving
var mediaPicker = new MediaPicker (Activity);
if (!mediaPicker.IsCameraAvailable){
// Console.WriteLine ("No Camera!");
}else {
Intent intent = new Intent(MediaStore.ActionImageCapture);
StartActivityForResult(intent, 0);
}
};
btnGallery.Click += (sender, e) => {
//launch gallery
//allow photo editing/saving
var imageIntent = new Intent ();
imageIntent.SetType ("image/*");
imageIntent.SetAction (Intent.ActionGetContent);
StartActivityForResult (
Intent.CreateChooser (imageIntent, "Select photo"), 0);
};
return m_View;
}
protected virtual void OnActivityResult (int requestCode, Result resultCode, Intent data)
{
System.Console.WriteLine ("WOOOOOOOOOOOOOOOOOOOOOOOOOOOO");
Uri contentUri = data.Data;
ivPicture.SetImageURI (data.Data);
}
Hmm.. I created a sample and it worked just fine for me. The only difference I see is that it looks like your override is not correct. It should be public override void OnActivityResult()
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
var rootView = inflater.Inflate(Resource.Layout.MainFragment, container, false);
var button = rootView.FindViewById<Button>(Resource.Id.button_camera);
button.Click += (sender, args) =>
{
var intent = new Intent(MediaStore.ActionImageCapture);
StartActivityForResult(intent, 0);
};
return rootView;
}
public override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
Log.Debug("TestFragment", "Got result");
// do what you want with the result here
}
Try changing the data type of resultCode to int, instead of Result and making the overridden function public.
e.g.
public override void OnActivityResult(int requestCode, int resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
}
For the people that use Android.Support.V4.App Fragment. You can override the OnActivityResult method in your Fragment but it will never be called if you use this in combination with a FragmentActivity!
It will be the OnActivityResult of the FragmentActivity that will be called. This can be implemented like following:
protected override void OnActivityResult(int requestCode, Result resultCode, Intent data)
{
base.OnActivityResult(requestCode, resultCode, data);
}
Check for request code is same as provided for startActivityForResult(intent, 0) here 0 is request code.. eg if you put 999 here insted of 0 ..then in onActivity result method check for requestcode == 999. it is used to check if the intent is the same as asked for and nothing other than that..
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
// TODO Auto-generated method stub
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 0 && resultCode == RESULT_OK) { // ADD THIS
// Get Data and do something with it
}
}

Categories

Resources