Search code examples
androidsectionedrecyclerviewadapter

SectionedRecyclerViewAdapter inside Fratment refresh fragment on data changed


I'm using SectionedRecyclerViewAdapter to create multiple sections in the recyclerview. The issue is when i trigger switchcompat i want both sections to get updated. It means whenever i change switchcompat state to checked i want the item to get removed from all apps list and get added to locked apps list and vice versa. In other words i want my fragment to get updated whenever i trigger switchcompat.

What is the best way to achieve it?

Fragment

public class AppListFragment extends Fragment {

    Context mContext;
    RecyclerView recyclerView;
    RecyclerView.Adapter adapter;
    RecyclerView.LayoutManager recyclerViewLayoutManager;

    private SectionedRecyclerViewAdapter sectionAdapter;

    public AppListFragment() {
        // Required empty public constructor
    }

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

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment

        View appListView = inflater.inflate(R.layout.fragment_app_list,container,false);

        sectionAdapter = new SectionedRecyclerViewAdapter();

        List<AppItem> lockedAppItemList = getLockedAppList(inflater.getContext());
        List<AppItem> allAppItemList = getAllAppList(inflater.getContext());

        sectionAdapter.addSection(new SectionLockedApps("Locked Apps", inflater.getContext(),new AppManager(inflater.getContext()).getAllInstalledApkInfo(), lockedAppItemList,sectionAdapter));
        sectionAdapter.addSection(new SectionAllApps("All Apps", inflater.getContext(),new AppManager(inflater.getContext()).getAllInstalledApkInfo(), allAppItemList,sectionAdapter));

        try {
            recyclerView = (RecyclerView) appListView.findViewById(R.id.rv_applist);
            recyclerViewLayoutManager = new LinearLayoutManager(this.getContext());
            recyclerView.setLayoutManager(recyclerViewLayoutManager);
            //adapter = new AppsAdapter(inflater.getContext(), new AppManager(inflater.getContext()).getAllInstalledApkInfo());
            recyclerView.setAdapter(sectionAdapter);

        }catch (Exception ex){
            Log.i("exception",ex.getMessage());
        }

        return appListView;
    }

    @Override
    public void onResume() {
        super.onResume();

        if (getActivity() instanceof AppCompatActivity) {
            AppCompatActivity activity = ((AppCompatActivity) getActivity());
            if (activity.getSupportActionBar() != null) {
                activity.getSupportActionBar().setTitle(R.string.app_name);
            }
        }
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);

        mContext = context;
    }

    private List<AppItem> getLockedAppList(Context ctx) {
        AppManager appManager = new AppManager(ctx);
        List<AppItem> appItemList = new ArrayList<>();
        List<String> apkPackInfoList = appManager.getAllInstalledApkInfo();

        for(String apkPackInfo:apkPackInfoList){
            String appName = appManager.getAppName(apkPackInfo);
            Drawable imageDrawable = appManager.getAppIconByPackageName(apkPackInfo);
            Boolean isLocked = appManager.isGuardEnabled(apkPackInfo);
            if(isLocked){
                appItemList.add(new AppItem(imageDrawable,appName,apkPackInfo,isLocked));
            }
        }

        return appItemList;
    }

    private List<AppItem> getAllAppList(Context ctx) {
        AppManager appManager = new AppManager(ctx);
        List<AppItem> appItemList = new ArrayList<>();
        List<String> apkPackInfoList = appManager.getAllInstalledApkInfo();

        for(String apkPackInfo:apkPackInfoList){
            String appName = appManager.getAppName(apkPackInfo);
            Drawable imageDrawable = appManager.getAppIconByPackageName(apkPackInfo);
            Boolean isLocked = appManager.isGuardEnabled(apkPackInfo);
            if(!isLocked){
                appItemList.add(new AppItem(imageDrawable,appName,apkPackInfo,isLocked));
            }
        }

        return appItemList;
    }
}

Locked Apps Section

public class SectionLockedApps extends StatelessSection {

    private SectionedRecyclerViewAdapter sectionAdapter;

    String title;
    boolean isGuardEnabled;
    Context ctxAppList;
    List<String> stringList;
    List<AppItem> appItemList;

    public SectionLockedApps(String title, Context ctx, List<String> stringList, List<AppItem> appItemList, SectionedRecyclerViewAdapter sectionAdapter) {
        super(SectionParameters.builder()
                .itemResourceId(R.layout.cardview_layout_applist)
                .headerResourceId(R.layout.section_header)
                .build());

        this.title = title;
        this.ctxAppList = ctx;
        this.stringList = stringList;
        this.appItemList = appItemList;
        this.sectionAdapter = sectionAdapter;
    }

    @Override
    public int getContentItemsTotal() {
        return appItemList.size();
    }

    @Override
    public RecyclerView.ViewHolder getItemViewHolder(View view) {
        return new ItemViewHolder(view);
    }

    @Override
    public void onBindItemViewHolder(RecyclerView.ViewHolder holder, final int position) {

        final AppManager appManager = new AppManager(ctxAppList);
        final String applicationPackageName = appItemList.get(position).getPackageName();
        isGuardEnabled = appManager.isGuardEnabled(applicationPackageName);

        if (appItemList.size() > 0) {
            String ApplicationLabelName = appItemList.get(position).getAppName();
            Drawable drawable = appItemList.get(position).getImageDrawable();



            final ItemViewHolder itemHolder = (ItemViewHolder) holder;

            itemHolder.textView_App_Name.setText(ApplicationLabelName);

            //viewHolder.textView_App_Package_Name.setText(applicationPackageName);

            itemHolder.imageView.setImageDrawable(drawable);

            itemHolder.switchCompat.setChecked(isGuardEnabled);

            //Adding click listener on CardView to open clicked application directly from here .
            itemHolder.rootView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {

                    Intent intent = ctxAppList.getPackageManager().getLaunchIntentForPackage(applicationPackageName);
                    if (intent != null) {

                        ctxAppList.startActivity(intent);

                    } else {

                        Toast.makeText(ctxAppList, applicationPackageName + " Error, Please Try Again.", Toast.LENGTH_LONG).show();
                    }
                }
            });

            itemHolder.switchCompat.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                    appManager.setGuard(applicationPackageName, isChecked);
                    //appItemList.get(position).setLocked(isChecked);

                }
            });
        }

    }

    @Override
    public RecyclerView.ViewHolder getHeaderViewHolder(View view) {
        return  new HeaderViewHolder(view);
    }

    @Override
    public void onBindHeaderViewHolder(RecyclerView.ViewHolder holder) {
        HeaderViewHolder headerHolder = (HeaderViewHolder) holder;

        if(appItemList.size()>0){
            headerHolder.tvTitle.setText(title);
        }else {
            headerHolder.tvTitle.setVisibility(View.GONE);
        }



    }

    private class HeaderViewHolder extends RecyclerView.ViewHolder {

        private final TextView tvTitle;

        HeaderViewHolder(View view) {
            super(view);
            tvTitle = (TextView) view.findViewById(R.id.tvTitle);
        }
    }

    private class ItemViewHolder extends RecyclerView.ViewHolder {

        private final View rootView;

        public TextView textView_App_Name;
        public ImageView imageView;
        public SwitchCompat switchCompat;

        ItemViewHolder(View view) {
            super(view);

            rootView = view;

            textView_App_Name = (TextView) view.findViewById(R.id.Apk_Name);
            imageView = (ImageView) view.findViewById(R.id.imgApplist);
            switchCompat = (SwitchCompat) view.findViewById(R.id.compatSwitch);

        }
    }

}

All Apps Section

public class SectionAllApps extends StatelessSection {

    String title;
    boolean isGuardEnabled;
    Context ctxAppList;
    List<String> stringList;
    List<AppItem> appItemList;
    String applicationPackageName;
    AppManager appManager;

    private SectionedRecyclerViewAdapter sectionAdapter;

    public SectionAllApps(String title, Context ctx, List<String> stringList, List<AppItem> appItemList, SectionedRecyclerViewAdapter sectionAdapter) {
        super(SectionParameters.builder()
                .itemResourceId(R.layout.cardview_layout_applist)
                .headerResourceId(R.layout.section_header)
                .build());

        this.title = title;
        this.ctxAppList = ctx;
        this.stringList = stringList;
        this.appItemList = appItemList;
        this.sectionAdapter = sectionAdapter;
    }

    @Override
    public int getContentItemsTotal() {
        return appItemList.size();
    }

    @Override
    public RecyclerView.ViewHolder getItemViewHolder(View view) {
        return new ItemViewHolder(view);
    }

    @Override
    public void onBindItemViewHolder(RecyclerView.ViewHolder holder, final int position) {

        final AppManager appManager = new AppManager(ctxAppList);
        final String applicationPackageName = appItemList.get(position).getPackageName();
        isGuardEnabled = appManager.isGuardEnabled(applicationPackageName);

        if (appItemList.size() > 0) {
            String ApplicationLabelName = appItemList.get(position).getAppName();
            Drawable drawable = appItemList.get(position).getImageDrawable();



            final SectionAllApps.ItemViewHolder itemHolder = (SectionAllApps.ItemViewHolder) holder;

            itemHolder.textView_App_Name.setText(ApplicationLabelName);

            //viewHolder.textView_App_Package_Name.setText(applicationPackageName);

            itemHolder.imageView.setImageDrawable(drawable);

            itemHolder.switchCompat.setChecked(isGuardEnabled);

            //Adding click listener on CardView to open clicked application directly from here .
            itemHolder.rootView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {

                    Intent intent = ctxAppList.getPackageManager().getLaunchIntentForPackage(applicationPackageName);
                    if (intent != null) {

                        ctxAppList.startActivity(intent);

                    } else {

                        Toast.makeText(ctxAppList, applicationPackageName + " Error, Please Try Again.", Toast.LENGTH_LONG).show();
                    }
                }
            });

            itemHolder.switchCompat.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                    appManager.setGuard(applicationPackageName, isChecked);

                    //appItemList.get(position).setLocked(isChecked);

                }
            });
        }
    }

    @Override
    public RecyclerView.ViewHolder getHeaderViewHolder(View view) {
        return new HeaderViewHolder(view);
    }

    @Override
    public void onBindHeaderViewHolder(RecyclerView.ViewHolder holder) {
        HeaderViewHolder headerHolder = (HeaderViewHolder) holder;

        headerHolder.tvTitle.setText(title);
    }

    private class HeaderViewHolder extends RecyclerView.ViewHolder {

        private final TextView tvTitle;

        HeaderViewHolder(View view) {
            super(view);
            tvTitle = (TextView) view.findViewById(R.id.tvTitle);
        }
    }

    private class ItemViewHolder extends RecyclerView.ViewHolder {

        private final View rootView;
        public ImageView imageView;
        public TextView textView_App_Name;
        public SwitchCompat switchCompat;


        ItemViewHolder(View view) {
            super(view);

            rootView = view;

            imageView = (ImageView) view.findViewById(R.id.imgApplist);
            textView_App_Name = (TextView) view.findViewById(R.id.Apk_Name);
            switchCompat = (SwitchCompat) view.findViewById(R.id.compatSwitch);
        }
    }
}

appManager.SetGuard() basically saves switchcompat's last state.


Solution

  • After some research I've found a solution for my issue. The solution was not to work with list of apps but to refresh the fragment. Basically I've created an interface that is used for both of my sections on scenario execute with method refresh(); and made an implementation inside my fragment

    Codes are written below:

    Interface

    public interface IFragmentOperation {
        public void refresh();
    }
    

    Modifications in fargment

    public class AppListFragment extends Fragment implements IFragmentOperation {
    ....
    
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        ...
    
        sectionAdapter.addSection(new SectionLockedApps("Locked Apps", inflater.getContext(),lockedAppItemList,this));
        sectionAdapter.addSection(new SectionAllApps("All Apps", inflater.getContext(),allAppItemList,this));
    
        ...
    }
    
    //Refresh fragment on switchcompat touched
    @Override
    public void refresh() {
        FragmentTransaction fragmentTransaction = getActivity().getSupportFragmentManager().beginTransaction();
        fragmentTransaction.detach(this).attach(this).commit();
    }
    

    }

    As you can see I've implemented an interface with method refresh() and added an extra parameter this inside my sections cunstructor. This way I'm sending an interface implementation into my section classes.

    Then in my section I simply create IFragmentOperation fragmentOperation; and assigning the value of fragmentOperation inside constructor

    IFragmentOperation fragmentOperation;
    
    public SectionLockedApps(String title, Context ctx,List<AppItem> appItemList,IFragmentOperation fragmentOperation) {
        super(SectionParameters.builder()
                .itemResourceId(R.layout.cardview_layout_applist)
                .headerResourceId(R.layout.section_header)
                .build());
    
        this.title = title;
        this.ctxAppList = ctx;
        this.appItemList = appItemList;
        this.fragmentOperation = fragmentOperation;
    }
    

    and use it wherever is needed like this fragmentOperation.refresh();

    itemHolder.switchCompat.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
            appManager.setGuard(applicationPackageName, isChecked);
            //appItemList.get(position).setLocked(isChecked);
            fragmentOperation.refresh();
    
        }
    });
    

    That's it. Hope it will help someone with related issue.