-1

I have a fragment as part of a bottom navigation. Inside the fragment, I have a button to select an image and show in recyclerview.

I am handling the click event of this button from onBindViewHolder() of recyclerview by calling the method in the fragment class like this:

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    if (holder instanceof TrendingHeaderViewHolder){
        ((TrendingHeaderViewHolder) holder).cameraShareIV.setOnClickListener( view -> {
            TrendingFragment.newInstance().selectImage(); // this method is created in fragment class but called here in adapter
        });
    } else if (holder instanceof TrendingItemsViewHolder){
        TestTrends tre = trendsList.get(position - 1);
        Picasso.with(context)
                .load(tre.getTestImage())
                .placeholder(R.drawable.default_profile_photo)
                .into(((TrendingItemsViewHolder) holder).testImgView);
    }
}

and in fragment, the method is like below:

public void selectImage() {
    Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
    intent.setType("image/*");
    startActivityForResult(intent, GAL_REQ_CODE);
    //context.startActivityForResult(intent, GAL_REQ_CODE); // tried with Activity and Context but still crashes
}

The app crashes whenever the button is clicked. Here's the error in logcat:

java.lang.IllegalStateException: Fragment TrendingFragment{171d0a0} not attached to Activity
   at android.support.v4.app.Fragment.startActivityForResult(Fragment.java:1026)
   at android.support.v4.app.Fragment.startActivityForResult(Fragment.java:1017)
   at base.android.com.thumbsapp.UI.Fragments.TrendingFragment.selectImage(TrendingFragment.java:120)
   at base.android.com.thumbsapp.Adapters.TrendingAdapter.lambda$onBindViewHolder$0$TrendingAdapter(TrendingAdapter.java:59)
   at base.android.com.thumbsapp.Adapters.TrendingAdapter$$Lambda$0.onClick(Unknown Source)
   at android.view.View.performClick(View.java:5690)
   at android.view.View$PerformClick.run(View.java:22693)
   at android.os.Handler.handleCallback(Handler.java:836)
   at android.os.Handler.dispatchMessage(Handler.java:103)
   at android.os.Looper.loop(Looper.java:203)
   at android.app.ActivityThread.main(ActivityThread.java:6269)
   at java.lang.reflect.Method.invoke(Native Method)
   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1063)
   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:924)

Here's my activity where the bottom nav fragments are inlfated:

private final BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
        = item -> {
    FragmentTransaction ft = null;
    switch (item.getItemId()) {
        case R.id.navigation_home:
            viewpager.setCurrentItem(0);
            ft = getSupportFragmentManager().beginTransaction()
                    .replace(R.id.fragContainer, new HomeFragment());
            ft.commit();
            return true;
        case R.id.navigation_trending:
            ft = getSupportFragmentManager().beginTransaction()
                    .replace(R.id.fragContainer, new TrendingFragment());
            ft.commit();
            viewpager.setCurrentItem(2);
            return true;
        case R.id.navigation_chats:
            ft = getSupportFragmentManager().beginTransaction()
                    .replace(R.id.fragContainer, new ChatsFragment());
            ft.commit();
            viewpager.setCurrentItem(3);
            return true;
        case R.id.navigation_profile:
            ft = getSupportFragmentManager().beginTransaction()
                    .replace(R.id.fragContainer, new ProfileFragment());
            ft.commit();
            viewpager.setCurrentItem(4);
            return true;
        case R.id.navigation_search:
            ft = getSupportFragmentManager().beginTransaction()
                    .replace(R.id.fragContainer, new SearchFragment());
            ft.commit();
            viewpager.setCurrentItem(1);
            return true;
    }
    return false;
};

and the layout:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="base.android.com.thumbsapp.UI.Activities.MainActivity">

<android.support.v4.view.ViewPager
    android:id="@+id/fragments"
    android:layout_width="match_parent"
    android:layout_height="0dp"
    android:layout_weight="1"
    android:layout_above="@+id/navigation"/>

<FrameLayout
    android:id="@+id/fragContainer"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:layout_weight="1"
    android:layout_above="@+id/navigation"/>

<android.support.design.widget.BottomNavigationView
    android:id="@+id/navigation"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="?android:attr/windowBackground"
    app:itemBackground="@android:color/white"
    app:itemIconTint="@color/nav_bar_behave"
    app:itemTextColor="@color/nav_bar_behave"
    app:menu="@menu/navigation"
    android:layout_alignParentBottom="true"/>

Can someone explain why the app is crashing pls?

Andromeda
  • 230
  • 1
  • 7
  • 22

1 Answers1

0

Why is the app crashing? Because your fragment is not attached to any activity.

You should rather implement a listener in your fragment to call from your viewHolder on click event.

Inside your adapter class, define an interface

public interface OnItemClickListener {
        void onItemClick();
}

while initializing your adapter class with listener implementation

public Adapter(OnItemClickListenerener listener){
this.listener = listener;
}

inside your view-holder:

viewHolder.itemView..setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View view) {
listener.onItemClick();}
}

finally, implement this interface in your enclosing activity and then get your fragment to call the required method.

Also, you should move your onItemClick listener event code to view-holder from onBindViewHolder

Bhagat
  • 80
  • 9
  • I have tried using ((AppCompatActivity)getActivity).startActivityForResult but doesn't work too. I think the listener works bi-directionally. Can you show a sample? – Andromeda Apr 04 '18 at 07:52
  • Can you show the code where you added your fragment to activity?problem is not with startActivityForResult but with fragment not being attached to the activity. getActivity() would give null in such scenario. – Bhagat Apr 04 '18 at 08:02
  • Take a look and tell me pls. Thanks – Andromeda Apr 04 '18 at 08:23