Fragment replacing in RecyclerView item

Solution 1:

I finnaly found solution. The problem is I set a common container id. But in recycler view need to set unique container id for each item.

So, my code now this:

MyFragment fragment = MyFragment.newInstance("fragment1");
fragmentManager.beginTransaction().replace(UNIQUE_CONTAINER_ID, fragment).commit();

If someone will be useful, here is my complete code (implementation fragment in recycler view):

public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) 
{

...

// Delete old fragment
int containerId = holder.mediaContainer.getId();// Get container id
Fragment oldFragment = fragmentManager.findFragmentById(containerId);
if(oldFragment != null) {
    fragmentManager.beginTransaction().remove(oldFragment).commit();
}

int newContainerId = View.generateViewId();// Generate unique container id
holder.mediaContainer.setId(newContainerId);// Set container id

// Add new fragment
MyFragment fragment = MyFragment.newInstance("fragment1");
fragmentManager.beginTransaction().replace(newContainerId, fragment).commit();

...

}

Upd.: Instead of using your own method to generate a unique id, it is recommended to use View.generateViewId()

Solution 2:

Thanks to Mikhali, I'm able to provide to you a complete running example. Pay special attention on the comments in onBindViewHolder()

    public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewLedgerAdapter.ViewHolder>{
        private final String TAG = RecyclerViewAdapter.class.getSimpleName();

        private final float FINAL_OPACITY = 0.3f;
        private final float START_OPACITY = 1f;

        private final int ANIMATION_TIME = 500;
        private final int TYPE_ITEM = 0;
        private final int TYPE_DATE = 1;
        private final int TYPE_TRANSACTION = 2;
        private final int TYPE_PENDING = 3;

        private HashMap<Integer, Integer> mElementTypes;
        private List<Operation> mObjects;
        private Context mContext;
        private Utils.CURRENCIES mCurrencySelected; // Which currency is already selected
        private boolean mCurrencyFilter; // Defines if a currency is already selected to apply filter
        private Animation mAnimationUp;
        private Animation mAnimationDown;

        public RecyclerViewLedgerAdapter(List<Operation> objects, Context context) {
            mElementTypes = new HashMap<Integer, Integer>();
            mObjects = objects;
            mContext = context;
            mCurrencyFilter = false;
            mCurrencySelected = null;
            mAnimationUp = AnimationUtils.loadAnimation(context, R.anim.slide_up);
            mAnimationDown = AnimationUtils.loadAnimation(context, R.anim.slide_down);
        }

        ...
        ...
            Not needed methods
        ...
        ...

        @Override
        public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.rv_element_ledger, parent, false);
            return new ViewHolder(view);
        }

        @Override
        public void onBindViewHolder(final ViewHolder holder, final int position) {
            Operation operation = mObjects.get(position);
            holder.setAppUserActivity(userActivityOperation);

            // Remember that RecyclerView does not have onClickListener, you should implement it
            holder.getView().setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    // Hide details
                    // iDetailsContainer object could be checked on inner class ViewHolder
                    if(holder.iDetailsContainer.isShown()){
                        holder.iDetailsContainer.setVisibility(View.GONE);
                    }else{
                        // Show details
                        // Get fragment manager inside our fragment
                        FragmentManager fragmentManager = ((UserActivity)mContext).getSupportFragmentManager();

                        // Delete previous added fragment
                        int currentContainerId = holder.iDetailsContainer.getId();
                        // Get the current fragment
                        Fragment oldFragment = fragmentManager.findFragmentById(currentContainerId);
                        if(oldFragment != null) {
                            // Delete fragmet from ui, do not forget commit() otherwise no action
                            // is going to be observed
                            ragmentManager.beginTransaction().remove(oldFragment).commit();
                        }

                        // In order to be able of replacing a fragment on a recycler view
                        // the target container should always have a different id ALWAYS
                        int newContainerId = getUniqueId();
                        // Set the new Id to our know fragment container
                        holder.iDetailsContainer.setId(newContainerId);

                        // Just for Testing we are going to create a new fragment according
                        // if the view position is pair one fragment type is created, if not
                        // a different one is used
                        Fragment f;
                        if(position%2 == 0) {
                            f = new FragmentCard();
                        }else{
                            f=new FragmentChat();
                        }

                        // Then just replace the recycler view fragment as usually
                        manager.beginTransaction().replace(newContainerId, f).commit();

                        // Once all fragment replacement is done we can show the hidden container
                        holder.iDetailsContainer.setVisibility(View.VISIBLE);
                    }
                }

                // Method that could us an unique id
                public int getUniqueId(){
                    return (int)SystemClock.currentThreadTimeMillis();
                }
            });
        }


        public class ViewHolder extends RecyclerView.ViewHolder{
            private View iView;
            private LinearLayout iContainer;
            public LinearLayout iDetailsContainer;
            private ImageView iOperationIcon;
            private ImageView iOperationActionImage;
            private TextView iOperation;
            private TextView iAmount;
            private TextView iTimestamp;
            private TextView iStatus;

            private UserActivityOperation mUserActivityOperation;

            public ViewHolder(View itemView) {
                super(itemView);
                iView = itemView;
                iContainer = (LinearLayout) iView.findViewById(R.id.operation_container);
                iDetailsContainer = (LinearLayout) iView.findViewById(R.id.details_container);
                iOperationIcon = (ImageView) iView.findViewById(R.id.ledgerOperationIcon);
                iOperationActionImage = (ImageView) iView.findViewById(R.id.ledgerAction);
                iOperation = (TextView) iView.findViewById(R.id.ledgerOperationDescription);
                iAmount = (TextView) iView.findViewById(R.id.ledgerOperationCurrencyAmount);
                iTimestamp = (TextView) iView.findViewById(R.id.ledgerOperationTimestamp);
                iStatus = (TextView) iView.findViewById(R.id.ledgerOperationStatus);

                // This linear layout status is GONE in order to avoid the view to use space
                // even when it is not seen, when any element selected the Adapter will manage the
                // behavior for showing the layout - container
                iDetailsContainer.setVisibility(View.GONE);
            }

            ...
            ...
                Not needed methods
            ...
            ...
        }
    }

Layout

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/operation_container_maximum"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginBottom="11dp"
    android:layout_marginLeft="30dp"
    android:layout_marginRight="30dp"
    android:layout_marginTop="11dp"
    android:orientation="vertical">


    <LinearLayout
        android:id="@+id/operation_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal">

        <FrameLayout
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginRight="14dp">

            <ImageView
                android:id="@+id/ledgerOperationIcon"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:src="@drawable/fondear" />

            <ImageView
                android:id="@+id/ledgerAction"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="bottom|right"
                android:src="@drawable/operation_trade" />


        </FrameLayout>

        <LinearLayout
            android:layout_width="wrap_content"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:orientation="vertical"
            android:weightSum="2">

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_gravity="center_vertical"
                android:layout_weight="1"
                android:orientation="horizontal">

                <TextView
                    android:id="@+id/ledgerOperationDescription"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:text="Descripcion"
                    android:textColor="@color/ledger_desc" />

                <TextView
                    android:id="@+id/ledgerOperationCurrencyAmount"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_marginRight="2dp"
                    android:text="5000 BTC" />
            </LinearLayout>

            <LinearLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_gravity="center_vertical"
                android:layout_weight="1"
                android:orientation="horizontal">

                <TextView
                    android:id="@+id/ledgerOperationTimestamp"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_weight="1"
                    android:text="Fecha/Hora"
                    android:textColor="@color/ledger_timestamp" />

                <TextView
                    android:id="@+id/ledgerOperationStatus"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="Status" />
            </LinearLayout>
        </LinearLayout>
    </LinearLayout>


    <LinearLayout
        android:id="@+id/details_container"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">



        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_gravity="center_horizontal"
            android:text="Something hidden" />

        <ImageView
            android:layout_marginTop="15dp"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:src="@drawable/user_btc"
            android:layout_gravity="center_horizontal"/>

    </LinearLayout>

</LinearLayout>

Fragment

    // This is one of the fragments used in the RecyclerViewAdapterCode, and also makes a HTTPRequest to fill the
    // view dynamically, you could laso use any of your fragments.
    public class FragmentCard extends Fragment {

        TextView mTextView;

        @Override
        public void onCreate(@Nullable Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
        }

        @Nullable
        @Override
        public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
            View view = inflater.inflate(R.layout.fragment_card, container, false);

            mTextView = (TextView) view.findViewById(R.id.tv_fragment_two);
            new UserActivityAsyncTask().execute();
            return view;
        }

        private UserActivityOperation[] asyncMethodGetPendingWithdrawals(){
            BitsoWithdrawal[] userWithdrawals = HttpHandler.getUserWithdrawals(getActivity());
            int totalWithDrawals = userWithdrawals.length;
            UserActivityOperation[] appUserActivities = new UserActivityOperation[totalWithDrawals];
            for(int i=0; i<totalWithDrawals; i++){
                appUserActivities[i] = new UserActivityOperation(userWithdrawals[i], getActivity());
            }
            return appUserActivities;
        }

        private class UserActivityAsyncTask extends AsyncTask<String, Void, Integer> {
            @Override
            protected void onPreExecute() {
                super.onPreExecute();
            }

            @Override
            protected Integer doInBackground(String... strings) {
                // Precess Compound balance
                UserActivityOperation[] compoundBalanceProcessed = asyncMethodGetPendingWithdrawals();
                return compoundBalanceProcessed.length;
            }

            @Override
            protected void onPostExecute(Integer result) {
                super.onPostExecute(result);
                mTextView.setText(result.toString());
            }
        }
    }