I have a helper class that takes an activity and does stuff with it.
public MyClass(AppCompatActivity activity, Callbacks callbacks) {
this.activity = activity;
this.callbacks = callbacks;
}
What I do in this class is basically call other activies/libraries in a certain order and use the results. I put this in a helper class so that I can easily reuse the code.
This is the problem I have:
With the new ActivityResultLauncher it's easy to "modularize" what I need:
ActivityResultLauncher<Intent> chooseImageLauncher = activity.registerForActivityResult(...);
...
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType("image/*");
chooseImageLauncher.launch(intent);
And in the implementation of chooseImageLauncher I do whatever I want next. In this case, I will call a library.
The problem is that the library I'm calling was last updated 2020 and doesn't provide a method for an ActivityResultLauncher. It only supports the old way with onActivityResult:
MyLibrary.init().start(activity);
And the result can be caught like this:
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
if (requestCode == MyLibrary.REQUEST_CODE && resultCode == RESULT_OK) {
...
}
}
But I can only implement that in each activity itself. How can I implement here?
You could add a private class inside your helper class that extends Activity. This way you can still catch the value emitted by your library.
private class MyLibraryActivityWrapper extends AppCompatActivity {
public void init() {
MyLibrary.init().start(activity);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, #Nullable Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == MyLibrary.REQUEST_CODE && resultCode == RESULT_OK) {
}
}
}
Related
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.
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
}
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
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!
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/