onActivityResult from Activity to Fragment - android

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.

Related

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 call in the Fragment

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);
}
}
}

onActivityResult DialogFragment doesn't work

I'm having a problem by executing fileupload in android through fragmentDialog.Befire to test the button I made activity etc to test it, evrything works fine, but since i put it under dilogfragment nothing works:
public class UploadF extends DialogFragment{
....
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
gallery_button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent gal = new Intent();
gal.setType("image/*");
gal.setAction(Intent.ACTION_GET_CONTENT);
startActivityForResult(Intent.createChooser(gal, "Select Picture"), SELECT_IMAGE);
}
});
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult( requestCode, resultCode, data);
if (resultCode == Activity.RESULT_OK) {
if (requestCode == SELECT_IMAGE) {
....
if ( selectedImagePath != null ) {
UploadFileI task = new UploadFileI( getActivity());
task.execute( url );
}
}
}
}
}
You are right, that nothing is happening. Activity's have a method onActivityResult, and Fragment's have one as well. This might be confusing, and in order to progress, try to use the Activity context by calling:
getActivity().startActivityForResult(Intent.createChooser(gal, "Select Picture"), SELECT_IMAGE);
This way, the Activity that created your UploadF will receive the result. So you have to move your onActivityResult to your Activity:
public class YourActivity extends Activity {
...
public void onActivityResult(int requestCode, int resultCode, Intent data){}
...
}
Function outside of your UploadF and inside the parent Activity.
If this doesn't work, search for startActivityForResult inside DialogFragment

android testing onActivityResult

I am searching for a solution to get my test (which actually is an ActivityInstrumentationTextCase2) testing the onActivityResults method of my Activity with a special (mock) request- / resultcode and intent...
Code:
method should be tested:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
//In this case the user selected an image from his harddrive
case StartupActivity.PICK_IMAGE:
if (resultCode == Activity.RESULT_OK) {
this.processSelectedFile(data.getData());
}
break;
}
}
test class:
public void testOnActivityResult() {
//here I would like to call the onActivityResult method from my mActivity object.
}
To test a protected member, declare (in your test project) a new class that derives from your target:
public class TestMyActivity : MyActivity
{
//constructors
public void testOnActivityResult(int requestCode, int resultCode, Intent data) {
//call super one
super.onActivityResult(requestCode, resultCode, data);
}
}
Now in your test, create one of these and you can call the method.
Source of idea:
http://codebetter.com/karlseguin/2009/08/19/testing-protected-methods-is-easy/

Categories

Resources