0

okay here is my problem

  1. I have a Fragment that contains RecyclerView, and of course an adapter (called ApprovalCutiCardAdapter) that hold the content.
  2. Inside that ApprovalCutiCardAdapter I set OnClickListener on the card, when Card is clicked it will launch an Activity called DetailApprovalCuti. Here is my code to launch the activity

    ((Activity) MyApplication.getmContext()).startActivityForResult(detailApprovalCutiIntent, 1);
    
  3. In DetailApprovalCuti I'm executing finishActivity(1) to get an event of onActivityResult. But that event is not being called everywhere (in Activity that host the fragment, and in the fragment)

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        Log.e("result", "ApprovalIzinCutiFragment");
        super.onActivityResult(requestCode, resultCode, data);
    }
    
  4. Here's my code to start the Acvitity

    @Override
    public void onBindViewHolder(final CutiViewHolder holder, final int position) {
    ....
    holder.cv.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Intent detailApprovalCutiIntent = new Intent(MyApplication.getmContext(), DetailApprovalCuti.class);
            Bundle b = new Bundle();
            b.putParcelable("cuti", ApprovalCutiCardAdapter.allCuti.get(position));
            b.putParcelable("process_cuti", ApprovalCutiCardAdapter.allCuti.get(position).getProcessCuti());
            detailApprovalCutiIntent.putExtras(b);
            ((Activity)MyApplication.getmContext()).startActivityForResult(detailApprovalCutiIntent,1);
        }
    });
    
    ....
    }
    
  5. Here's my code to finish the activity

    btnReject.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            new AlertDialog.Builder(DetailApprovalCuti.this)
                    .setTitle("Peringatan")
                    .setMessage("Apakah anda yakin?")
                    .setIcon(android.R.drawable.ic_dialog_alert)
                    .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
                        public void onClick(DialogInterface dialog, int whichButton) {
                            setResult(1);
                            finish();
                        }
                    }).setNegativeButton(android.R.string.no, null).show();
        }
    });
    
Lyan Dwi Pangestu
  • 463
  • 1
  • 7
  • 23
  • Your "But that event is not being called everywhere" is not clear, what do you mean exactly? What's the issue and what's the desired behavior? – ddb Jul 31 '16 at 08:45
  • I want to listen to an event that called after `DetailApprovalCuti` is closed, and that means it will be back to the fragment, but the `onActivityResult` on the fragment is not working – Lyan Dwi Pangestu Jul 31 '16 at 08:51
  • Do you get an error? Or you would like to redirect the ActivityOnResult to the Activity that hosts fragments? – ddb Jul 31 '16 at 08:54
  • I don't see any error, the `Log` that inside `onActivityResult` is not running, I want to send data from Activity that closed to the Fragment that hold `RecyclerView` – Lyan Dwi Pangestu Jul 31 '16 at 08:57
  • Did you define onActivityResult in Fragment? – ddb Jul 31 '16 at 09:03
  • yes i've tried it on Fragment and on Activity that hold the Fragment, but none of them is working – Lyan Dwi Pangestu Jul 31 '16 at 09:04
  • The Activity should be startedForResult by the Fragment direclly, so when the new Activity closeForResult your code should work – ddb Jul 31 '16 at 09:06
  • @ddb but I have to start the Activity from the RecyclerView.Adapter – Lyan Dwi Pangestu Jul 31 '16 at 09:18
  • Check this question http://stackoverflow.com/questions/17085729/startactivityforresult-from-a-fragment-and-finishing-child-activity-doesnt-c – ddb Jul 31 '16 at 09:20
  • I think the problem lies here `((Activity)MyApplication.getmContext()).startActivityForResult`. Are you sure that this context is exactly the instance of the Activity you want to listen for results in? Have you tried using `fragment.getActivity().startActivityForResult ()`? (considering that the adapter is inside Fragment) – Sufian Aug 01 '16 at 01:15
  • @Sufian I have solved this problem, I just need to extract the listener to Fragment so I can call startActivityForResult directly without getting the context, thanks man – Lyan Dwi Pangestu Aug 01 '16 at 01:33

3 Answers3

1

Your Activity should be started "for-results" by the Fragment like : startActivityForResult(detailApprovalCutiIntent, 1); instead of ((Activity) MyApplication.getmContext()).startActivityForResult(detailApprovalCutiIntent, 1);- and then in the Activity that hosts the Fragment you can handle the onActivityResult - but then you want to propagate this event to the Fragment. So you call super.onActivityResult(requestCode, resultCode, data); - you will have something like:

@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
   super.onActivityResult(requestCode, resultCode, data);   
}

Then in the Fragment you can handle the onActivityResult callback.

Please have a look at these closely related quested and try out the selected answers:

I hope this sheds some light.

Community
  • 1
  • 1
ishmaelMakitla
  • 3,784
  • 3
  • 26
  • 32
  • I can't do `startActivityForResult(detailApprovalCutiIntent, 1);` because It's called inside an adapter. `startActivityForResult` can't be called from an adapter – Lyan Dwi Pangestu Jul 31 '16 at 09:21
  • @LyanDwiPangestu you can keep a `WeakReference` to the `Activity` in a field inside your adapter. Although I feel there's a problem in the way you are finishing the next `Activity`. You must call `setResult()` and then `finish()` so that the Activity of your Adapter has its `onActivityResult()` called. – Sufian Jul 31 '16 at 09:28
  • @Sufian can you give me an example of what is `WeakReference` ? – Lyan Dwi Pangestu Jul 31 '16 at 09:33
  • @LyanDwiPangestu See [this](https://docs.oracle.com/javase/7/docs/api/java/lang/ref/WeakReference.html). Just keep a reference of `Activity` in your Adapter and it should be no problem. As I said before the problem is with the way you finish the next Activity. – Sufian Jul 31 '16 at 11:55
  • @LyanDwiPangestu also see this for WeakReference - http://stackoverflow.com/questions/299659/what-is-the-difference-between-a-soft-reference-and-a-weak-reference-in-java – Sufian Jul 31 '16 at 12:06
  • @Sufian I have changed the way I finish the Activity but it's still not working, Haven't tried it with WeakReference – Lyan Dwi Pangestu Jul 31 '16 at 12:47
  • @LyanDwiPangestu please update your question with the latest code. Show the snippets where you are doing `startActivityForResult()`, `setResult()` and `finish()`. – Sufian Jul 31 '16 at 13:06
1

The problem is that, in the following line, you're calling startActivityForResult() from an Activity which might not be the one you're expecting.

((Activity)MyApplication.getmContext()).startActivityForResult(detailApprovalCutiIntent, 1);

Considering that your adapter is set from a Fragment, you should modify the above line to:

fragment.getActivity().startActivityForResult(detailApprovalCutiIntent, 1);

Lesson learnt

Never use singletons, for Singletons are Pathological Liars.

PS: single instances are fine but singletons (like global variables) are a bad design and must be avoided.

Sufian
  • 6,405
  • 16
  • 66
  • 120
0

I think that your design is needlessly complicated, and that it couples the Activity, the Fragment, and the RecyclerView's adapter much too tightly.

Try this instead:

  • when the adapter detects a click on a card, have it communicate that to it's parent (in this case, the Fragment).
  • when the Fragment is notified of the click, have it notify it's parent (the Activity)
  • when the Activity is notified by the Fragment, have it (the Activity) launch the new Activity with startActivityForResult
  • when the Activity gets the result in on onActivityResult have it do whatever it needs to with the result. If that result is needed in the Fragment, have it communicate the result to the Fragment.

The next question is how to communicate between the Fragment and the Activity. The "standard" answer is to create a pair of interfaces, and have the Activity implement one, and the Fragment implement the other, and then use the interface methods to call back and forth.

This can be difficult to do correctly, because the Activity and the Fragment have to track each other's lifecycles carefully in order to not crash.

I find that a better, easier solution is to use a message bus (e.g. Otto) to communicate messages between them. This way, the Activity and Fragment only need to register to and deregister from the bus when they are ready, and you completely sidestep the lifecycle issues.

GreyBeardedGeek
  • 29,460
  • 2
  • 47
  • 67