Search code examples
androidandroid-studioandroid-fragmentsandroid-recyclerviewandroid-tablayout

Getting RecyclerView to Display in Tablayout Fragments


Actually am trying to add recyclerView to a tabLayout fragment which for a while i have not been able to get it working, as it gives an error each time i tried. AM new to android development and i dont really seem to know where am getting things messed up

XML CODES ||

Activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout 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:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:id="@+id/drawer_layout">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#F7F7F7">
        <include layout="@layout/navaction_bar"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content" />

        <com.google.android.material.tabs.TabLayout
            android:id="@+id/tb_layout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_alignParentTop="true"
            android:layout_alignParentEnd="true"
            android:layout_marginTop="253dp"
            android:layout_marginRight="16dp"
            android:layout_marginLeft="16dp"
            android:background="@drawable/tab_layout_background"
            app:tabIndicatorColor="@color/c4"
            app:tabTextColor="#000000"
            app:tabMode="fixed"
            app:tabGravity="fill"
            android:elevation="1dp">


        </com.google.android.material.tabs.TabLayout>

        <androidx.viewpager.widget.ViewPager
            android:id="@+id/v_pager"
            android:layout_width="match_parent"
            android:layout_height="600dp"
            android:layout_alignBottom="@+id/tb_layout"
            android:layout_alignParentEnd="true"
            android:layout_alignParentBottom="true"
            android:layout_marginTop="304dp"
            android:layout_marginLeft="16dp"
            android:layout_marginRight="16dp"
            android:background="#ffffff"
            android:elevation="1dp" >

        </androidx.viewpager.widget.ViewPager>


    </RelativeLayout>

    <com.google.android.material.navigation.NavigationView
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        app:menu="@menu/navigation_menu"
        android:layout_gravity="start"
        app:headerLayout="@layout/navigation_header">

    </com.google.android.material.navigation.NavigationView>

</androidx.drawerlayout.widget.DrawerLayout>

services_fragment.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="start">


    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

list_adapter.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/parent_layout"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="#fff"
    android:padding="15dp">

    <de.hdodenhof.circleimageview.CircleImageView
        android:id="@+id/circle_img"
        android:layout_width="80dp"
        android:layout_height="80dp"
        android:src="@drawable/img_20190413_083028" />

    <TextView
        android:id="@+id/image_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerVertical="true"
        android:layout_marginLeft="30dp"
        android:layout_toRightOf="@+id/circle_img"
        android:text="Courage"
        android:textColor="#000"
        android:textSize="17sp" />

</RelativeLayout>

JAVA CODES ||

MainActivity.java

package com.example.drawerlayout;

import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.drawerlayout.widget.DrawerLayout;

import android.os.Bundle;
import android.util.Log;
import android.view.MenuItem;
import android.widget.ListView;

import androidx.appcompat.widget.Toolbar;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager.widget.ViewPager;

import com.google.android.material.appbar.AppBarLayout;
import com.google.android.material.tabs.TabLayout;

import java.util.ArrayList;


public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";
    private DrawerLayout mDrawerLayout;
    private ActionBarDrawerToggle mToggle;
    private Toolbar mToolbar;
    private AppBarLayout actionLayout;
    private TabLayout tabLayout;
    private ViewPager viewPager;
    private ArrayList<String> mNames = new ArrayList<>();

    private ArrayList<String> mImageUrls = new ArrayList<>();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.d(TAG, "onCreate: started");
        /*get state id*/
        mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
        mToggle = new ActionBarDrawerToggle(this, mDrawerLayout, R.string.open, R.string.close);
        mToolbar = (Toolbar) findViewById(R.id.nav_action);
        actionLayout = (AppBarLayout) findViewById(R.id.appbar);
        tabLayout = (TabLayout) findViewById(R.id.tb_layout);
        viewPager = (ViewPager) findViewById(R.id.v_pager);


        ViewPagerAdapter viewPagerAdapter = new ViewPagerAdapter(getSupportFragmentManager());


        /*adding fragments*/
        viewPagerAdapter.AddFragment(new ServicesFragment(),"Services"); // `new ServicesFragment()` should be inside `FragmentPagerAdapter.getItem()`
        viewPagerAdapter.AddFragment(new UtilityFragment(),"Utility Bills"); // `new UtilityFragment()` should be inside `FragmentPagerAdapter.getItem()`
        viewPagerAdapter.AddFragment(new HistoryFragment(),"History"); // `new HistoryFragment()` should be inside `FragmentPagerAdapter.getItem()`


        // adapter setup
        viewPager.setAdapter(viewPagerAdapter);
        tabLayout.setupWithViewPager(viewPager);

        setSupportActionBar(mToolbar);

        mDrawerLayout.addDrawerListener(mToggle);
        mToggle.syncState();

        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setDisplayShowTitleEnabled(false);

        getSupportActionBar().setElevation(0);
        initImageBitmaps();
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {

        if (mToggle.onOptionsItemSelected(item)) return true;
        return super.onOptionsItemSelected(item);
    }


    private void initImageBitmaps(){
        Log.d(TAG, "initImageBitmaps: bitmap started");

        mImageUrls.add("https://nationalwire.com.ng/wp-content/uploads/2017/08/glo-logo.jpg");
        mNames.add("MTN LOGO");
        mImageUrls.add("https://seeklogo.com/images/M/mtn-logo-A285C69508-seeklogo.com.png");
        mNames.add("GLO LOGO");

        initRecyclerView ();
    }

    private void initRecyclerView () {
        Log.d(TAG, "initRecyclerView: init RecyclerView");
        RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recycler_view);
        RecyclerViewAdapter recyclerViewAdapter = new RecyclerViewAdapter(this, mImageUrls, mNames);
        recyclerView.setAdapter(recyclerViewAdapter);
        recyclerView.setLayoutManager(new LinearLayoutManager(this));
    }
}

ServicesFragment.java

package com.example.drawerlayout;

import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;

public class ServicesFragment extends Fragment {
    View view;
    ListView lView;
    public ServicesFragment() {
    }

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

RecyclerViewAdapter.java

  package com.example.drawerlayout;

import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import com.bumptech.glide.Glide;

import java.util.ArrayList;

import de.hdodenhof.circleimageview.CircleImageView;

public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.ViewHolder> {
    private static final String TAG = "RecyclerViewAdapter";

    private ArrayList<String> mImages = new ArrayList<>();
    private ArrayList<String> mImageNames = new ArrayList<>();
    private Context mContext;

    public RecyclerViewAdapter(Context mContext, ArrayList<String> mImages, ArrayList<String> mImageNames) {
        this.mImages = mImages;
        this.mImageNames = mImageNames;
        this.mContext = mContext;
    }

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

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, final int position) {
        Log.d(TAG, "onBindViewHolder: called.");

        Glide.with(mContext)
                .asBitmap()
                .load(mImages.get(position))
                .into(holder.image);
        holder.image_name.setText(mImageNames.get(position));

        holder.parentLayout.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Log.d(TAG, "onClick: clicked on: " + mImageNames.get(position));

                Toast.makeText(mContext, mImageNames.get(position), Toast.LENGTH_SHORT).show();
            }
        });
    }

    @Override
    public int getItemCount() {
        return mImageNames.size();
    }

    public class ViewHolder extends RecyclerView.ViewHolder {
        CircleImageView image;
        TextView image_name;
        RelativeLayout parentLayout;
        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            image = itemView.findViewById(R.id.circle_img);
            image_name = itemView.findViewById(R.id.image_name);
            parentLayout = itemView.findViewById(R.id.parent_layout);
        }
    }
}

ERROR LOG

  --------- beginning of crash
09-11 20:00:22.923 3573-3573/com.example.drawerlayout E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.drawerlayout, PID: 3573
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.drawerlayout/com.example.drawerlayout.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void androidx.recyclerview.widget.RecyclerView.setAdapter(androidx.recyclerview.widget.RecyclerView$Adapter)' on a null object reference
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2327)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2392)
        at android.app.ActivityThread.access$800(ActivityThread.java:153)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1305)
        at android.os.Handler.dispatchMessage(Handler.java:102)
        at android.os.Looper.loop(Looper.java:135)
        at android.app.ActivityThread.main(ActivityThread.java:5293)
        at java.lang.reflect.Method.invoke(Native Method)
        at java.lang.reflect.Method.invoke(Method.java:372)
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
     Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void androidx.recyclerview.widget.RecyclerView.setAdapter(androidx.recyclerview.widget.RecyclerView$Adapter)' on a null object reference
        at com.example.drawerlayout.MainActivity.initRecyclerView(MainActivity.java:97)
        at com.example.drawerlayout.MainActivity.initImageBitmaps(MainActivity.java:90)
        at com.example.drawerlayout.MainActivity.onCreate(MainActivity.java:71)
        at android.app.Activity.performCreate(Activity.java:5990)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1106)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2280)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2392) 
        at android.app.ActivityThread.access$800(ActivityThread.java:153) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1305) 
        at android.os.Handler.dispatchMessage(Handler.java:102) 
        at android.os.Looper.loop(Looper.java:135) 
        at android.app.ActivityThread.main(ActivityThread.java:5293) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at java.lang.reflect.Method.invoke(Method.java:372) 
        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698) 
09-11 20:05:23.322 3573-3573/com.example.drawerlayout I/Process: Sending signal. PID: 3573 SIG: 9

Solution

  • Getting null pointer exception in your case is because of Recyclerview which is not in activity_main xml file.

    Remove this two method from MainActivity and add in ServiceFragment

     @override
     private void onViewCreated(View view, Bundle savedInstanceState){
        Log.d(TAG, "initImageBitmaps: bitmap started");
    
        mImageUrls.add("https://nationalwire.com.ng/wp-content/uploads/2017/08/glo-logo.jpg");
        mNames.add("MTN LOGO");
        mImageUrls.add("https://seeklogo.com/images/M/mtn-logo-A285C69508-seeklogo.com.png");
        mNames.add("GLO LOGO");
        RecyclerView recyclerView = (RecyclerView) view.findViewById(R.id.recycler_view);
        RecyclerViewAdapter recyclerViewAdapter = new RecyclerViewAdapter(getActivity(), mImageUrls, mNames);
        recyclerView.setAdapter(recyclerViewAdapter);
        recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
    }
    

    Also, initialize your PagerAdapter like this:

    public class ViewPagerAdapter extends FragmentPagerAdapter {
        public ViewPagerAdapter(FragmentManager fragmentManager) {
            super(fragmentManager);
        }
    
        @Override
        public Fragment getItem(int position) {
            if(position == 0) return new ServicesFragment();
            if(position == 1) return new UtilityFragment();
            if(position == 2) return new HistoryFragment();
    
            throw new IllegalStateException("Unexpected position " + position);
        }
    
        @Override
        public int getCount() {
            return 3;
        }
    
        @Override
        public CharSequence getPageTitle(int position) {
            if(position == 0) return "Services";
            if(position == 1) return "Utility Bills";
            if(position == 2) return "History";
          
            throw new IllegalStateException("Unexpected position " + position);
        }
    }