I am currently working on a project in which I have text data retrieved from a web page displayed between 3 different tabs declared as fragments.
There's a button refresh at the bottom of each tab & whenever the user presses that button, the app retrieves the most recent data from the web site & displays it in one of the three tabs.
The logic on which the app chooses the tab to write the text into is the following:
Write data into Tab 1 (leftmost). If Tab 1 already contains data, write into Tab 2. If Tab 2 already contains data, write into Tab 3. If all tabs contain data, overwrite data in Tab 1 & start the cycle over.
Here is my code before getting into my problem. I am only posting the relevant code to avoid flooding this message.
MainActivity:
public class MainActivity extends AppCompatActivity implements 
Tab1.OnFragmentInteractionListener, Tab2.OnFragmentInteractionListener,
    Tab3.OnFragmentInteractionListener{
final static String url = "http://159.203.78.94/rpilog/weatherstation.txt";
public static TextView dataTextTab1;
public static TextView dataTextTab2;
public static TextView dataTextTab3;
static Context context;
public static TabLayout tabLayout;
public static int tabPosition;
public static boolean tab1Used = false;
public static boolean tab2Used = false;
public static boolean tab3Used = false;
public static int positionFactor = -1;
static String TAG;
public static String dataFromURL;
public static TextView test;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    //Text placeholders for the data received from the URL.
    dataTextTab1 = (TextView) findViewById(R.id.dataTextTab1);
    dataTextTab2 = (TextView) findViewById(R.id.dataTextTab2);
    dataTextTab3 = (TextView) findViewById(R.id.dataTextTab3);
    context = getApplicationContext();
    //Creating the tabs.
    tabLayout = (TabLayout) findViewById(R.id.tablayout);
    tabLayout.addTab(tabLayout.newTab().setText("No data"));
    tabLayout.addTab(tabLayout.newTab().setText("No data"));
    tabLayout.addTab(tabLayout.newTab().setText("No data"));
    tabLayout.setTabGravity(TabLayout.GRAVITY_FILL);
    //ViewPager & PagerAdapter object to allow sliding tabs.
    final ViewPager viewPager = (ViewPager) findViewById(R.id.pager);
    final PagerAdapter adapter = new PagerAdapter(getSupportFragmentManager(), tabLayout.getTabCount());
    viewPager.setAdapter(adapter);
    viewPager.setOnPageChangeListener(new TabLayout.TabLayoutOnPageChangeListener(tabLayout));
    tabLayout.setOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
        @Override
        public void onTabSelected(TabLayout.Tab tab) {
            viewPager.setCurrentItem(tab.getPosition());
        }
        @Override
        public void onTabUnselected(TabLayout.Tab tab) {
        }
        @Override
        public void onTabReselected(TabLayout.Tab tab) {
        }
    });
}
public static void receiveString(){
    RequestQueue queue = Volley.newRequestQueue(context);
    //Requests a string response from the provided URL.
    StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
            new Response.Listener<String>() {
                @Override
                public void onResponse(String response) {
                    dataFromURL = response;
                    if (positionFactor * 169 + 16 + 3 + 144 <= response.length())  {
                        if(tab1Used == false) {
                            tabPosition = 0;
                            TabLayout.Tab currentTab = tabLayout.getTabAt(tabPosition);
                            currentTab.setText(response.substring(positionFactor * 169, positionFactor * 169 + 16));
                            dataTextTab1.setText(response.substring(positionFactor * 169 + 16 + 3, positionFactor * 169 + 16 + 3 + 144));
                            tab1Used = true;
                            Log.e(TAG, "1ST TAB REACHED");
                        }
                        else if(tab1Used == true && tab2Used == false){
                            tabPosition = 1;
                            TabLayout.Tab currentTab = tabLayout.getTabAt(tabPosition);
                            currentTab.setText(response.substring(positionFactor * 169, positionFactor * 169 + 16));
                            dataTextTab2.setText(response.substring(positionFactor * 169 + 16 + 3, positionFactor * 169 + 16 + 3 + 144));
                            tab2Used = true;
                            Log.e(TAG, "2ND TAB REACHED");
                        }
                        else if(tab1Used == true && tab2Used == true && tab3Used == false){
                                tabPosition = 2;
                                TabLayout.Tab currentTab = tabLayout.getTabAt(tabPosition);
                                currentTab.setText(response.substring(positionFactor * 169, positionFactor * 169 + 16));
                                dataTextTab3.setText(response.substring(positionFactor * 169 + 16 + 3, positionFactor * 169 + 16 + 3 + 144));
                                tab3Used = true;
                                Log.e(TAG, "3RD TAB REACHED");
                        }
                        if(tab1Used == true && tab2Used == true && tab3Used == true){  //If there's data in all tabs => overwrite oldest.
                            tabPosition = 0;
                            TabLayout.Tab currentTab = tabLayout.getTabAt(tabPosition);
                            currentTab.setText(response.substring(positionFactor * 169, positionFactor * 169 + 16));
                            dataTextTab1.setText(response.substring(positionFactor * 169 + 16 + 3, positionFactor * 169 + 16 + 3 + 144));
                            Log.e(TAG, "1ST TAB OVER AGAIN");
                            tab2Used = false;
                            tab3Used = false;
                        }
                    }
                }
            }, new Response.ErrorListener() {
        @Override
        public void onErrorResponse(VolleyError error) {
            Toast.makeText(context, "Error in data retrieval", Toast.LENGTH_LONG).show();
        }
    });
    queue.add(stringRequest);
}
public void refresh(View view){             //Refresh action for FAB = onClick fct.
    MainActivity.positionFactor++;
    Toast.makeText(context, "Page refreshed", Toast.LENGTH_SHORT).show();
    receiveString();
}
@Override
public void onFragmentInteraction(Uri uri) {
}
public static void showInfoPopup() {        //Show popup info = onClick fct.
    if (Menu.infoPopupDialog != null) {
        Menu.infoPopupDialog.setContentView(R.layout.popup_layout);
        Menu.infoPopupDialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
        Menu.infoPopupDialog.show();
    }
}
public static void showLocationPopup(){     //Show popup location = onClick fct.
    if(Menu.locationPopupDialog != null){
        Menu.locationPopupDialog.setContentView(R.layout.popup_location);
        Menu.locationPopupDialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
        Menu.locationPopupDialog.show();
    }
}
PagerAdapter:
public class PagerAdapter extends FragmentStatePagerAdapter {
int mNoOfTabs;
public PagerAdapter(FragmentManager fm, int numberOfTabs){
    super(fm);
    this.mNoOfTabs = numberOfTabs;
}
@Override
public Fragment getItem(int position) {
    switch(position){
        case 0:
            Tab1 tab1 = new Tab1();
            return tab1;
        case 1:
            Tab2 tab2 = new Tab2();
            return tab2;
        case 2:
            Tab3 tab3 = new Tab3();
            return tab3;
        default:
            return null;
    }
}
@Override
public int getCount() {
    return mNoOfTabs;
}
}
Tab1:
public class Tab1 extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
private OnFragmentInteractionListener mListener;
public Tab1() {
    // Required empty public constructor
}
/**
 * Use this factory method to create a new instance of
 * this fragment using the provided parameters.
 *
 * @param param1 Parameter 1.
 * @param param2 Parameter 2.
 * @return A new instance of fragment Tab1.
 */
// TODO: Rename and change types and number of parameters
public static Tab1 newInstance(String param1, String param2) {
    Tab1 fragment = new Tab1();
    Bundle args = new Bundle();
    args.putString(ARG_PARAM1, param1);
    args.putString(ARG_PARAM2, param2);
    fragment.setArguments(args);
    return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (getArguments() != null) {
        mParam1 = getArguments().getString(ARG_PARAM1);
        mParam2 = getArguments().getString(ARG_PARAM2);
    }
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    View rootView = inflater.inflate(R.layout.fragment_tab1, container, false);
    MainActivity.dataTextTab1 = rootView.findViewById(R.id.dataTextTab1);
    return rootView;
}
// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(Uri uri) {
    if (mListener != null) {
        mListener.onFragmentInteraction(uri);
    }
}
@Override
public void onAttach(Context context) {
    super.onAttach(context);
    if (context instanceof OnFragmentInteractionListener) {
        mListener = (OnFragmentInteractionListener) context;
    } else {
        throw new RuntimeException(context.toString()
                + " must implement OnFragmentInteractionListener");
    }
}
@Override
public void onDetach() {
    super.onDetach();
    mListener = null;
}
/**
 * This interface must be implemented by activities that contain this
 * fragment to allow an interaction in this fragment to be communicated
 * to the activity and potentially other fragments contained in that
 * activity.
 * <p>
 * See the Android Training lesson <a href=
 * "http://developer.android.com/training/basics/fragments/communicating.html"
 * >Communicating with Other Fragments</a> for more information.
 */
public interface OnFragmentInteractionListener {
    // TODO: Update argument type and name
    void onFragmentInteraction(Uri uri);
  }
}
Tab2:
public class Tab2 extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
private OnFragmentInteractionListener mListener;
public Tab2() {
    // Required empty public constructor
}
/**
 * Use this factory method to create a new instance of
 * this fragment using the provided parameters.
 *
 * @param param1 Parameter 1.
 * @param param2 Parameter 2.
 * @return A new instance of fragment Tab2.
 */
// TODO: Rename and change types and number of parameters
public static Tab2 newInstance(String param1, String param2) {
    Tab2 fragment = new Tab2();
    Bundle args = new Bundle();
    args.putString(ARG_PARAM1, param1);
    args.putString(ARG_PARAM2, param2);
    fragment.setArguments(args);
    return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (getArguments() != null) {
        mParam1 = getArguments().getString(ARG_PARAM1);
        mParam2 = getArguments().getString(ARG_PARAM2);
    }
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    View rootView = inflater.inflate(R.layout.fragment_tab2, container, false);
    MainActivity.dataTextTab2 = rootView.findViewById(R.id.dataTextTab2);
    return rootView;
}
// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(Uri uri) {
    if (mListener != null) {
        mListener.onFragmentInteraction(uri);
    }
}
@Override
public void onAttach(Context context) {
    super.onAttach(context);
    if (context instanceof OnFragmentInteractionListener) {
        mListener = (OnFragmentInteractionListener) context;
    } else {
        throw new RuntimeException(context.toString()
                + " must implement OnFragmentInteractionListener");
    }
}
@Override
public void onDetach() {
    super.onDetach();
    mListener = null;
}
/**
 * This interface must be implemented by activities that contain this
 * fragment to allow an interaction in this fragment to be communicated
 * to the activity and potentially other fragments contained in that
 * activity.
 * <p>
 * See the Android Training lesson <a href=
 * "http://developer.android.com/training/basics/fragments/communicating.html"
 * >Communicating with Other Fragments</a> for more information.
 */
public interface OnFragmentInteractionListener {
    // TODO: Update argument type and name
    void onFragmentInteraction(Uri uri);
 }
}
Tab3:
public class Tab3 extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
private OnFragmentInteractionListener mListener;
public Tab3() {
    // Required empty public constructor
}
/**
 * Use this factory method to create a new instance of
 * this fragment using the provided parameters.
 *
 * @param param1 Parameter 1.
 * @param param2 Parameter 2.
 * @return A new instance of fragment Tab3.
 */
// TODO: Rename and change types and number of parameters
public static Tab3 newInstance(String param1, String param2) {
    Tab3 fragment = new Tab3();
    Bundle args = new Bundle();
    args.putString(ARG_PARAM1, param1);
    args.putString(ARG_PARAM2, param2);
    fragment.setArguments(args);
    return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    if (getArguments() != null) {
        mParam1 = getArguments().getString(ARG_PARAM1);
        mParam2 = getArguments().getString(ARG_PARAM2);
    }
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    View rootView = inflater.inflate(R.layout.fragment_tab3, container, false);
    MainActivity.dataTextTab3 = rootView.findViewById(R.id.dataTextTab3);
    return rootView;
}
// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(Uri uri) {
    if (mListener != null) {
        mListener.onFragmentInteraction(uri);
    }
}
@Override
public void onAttach(Context context) {
    super.onAttach(context);
    if (context instanceof OnFragmentInteractionListener) {
        mListener = (OnFragmentInteractionListener) context;
    } else {
        throw new RuntimeException(context.toString()
                + " must implement OnFragmentInteractionListener");
    }
}
@Override
public void onDetach() {
    super.onDetach();
    mListener = null;
}
/**
 * This interface must be implemented by activities that contain this
 * fragment to allow an interaction in this fragment to be communicated
 * to the activity and potentially other fragments contained in that
 * activity.
 * <p>
 * See the Android Training lesson <a href=
 * "http://developer.android.com/training/basics/fragments/communicating.html"
 * >Communicating with Other Fragments</a> for more information.
 */
public interface OnFragmentInteractionListener {
    // TODO: Update argument type and name
    void onFragmentInteraction(Uri uri);
 }
}
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:orientation="vertical"
    android:layout_height="match_parent"
    tools:context="com.myapps.toualbiamine.weathertracker.MainActivity">
    <!--<android.support.v7.widget.Toolbar-->
        <!--android:id="@+id/toolbar"-->
        <!--android:layout_width="match_parent"-->
        <!--android:layout_height="50dp"-->
        <!--android:background="@color/colorPrimary"-->
        <!--android:minHeight="?attr/actionBarSize"-->
        <!--android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"-->
        <!--app:popupTheme="@style/ThemeOverlay.AppCompat.Light">-->
        <!--<TextView-->
            <!--android:layout_width="wrap_content"-->
            <!--android:layout_height="wrap_content"-->
            <!--android:text="Swipe to switch tabs"-->
            <!--android:textSize="30dp"/>-->
    <!--</android.support.v7.widget.Toolbar>-->
    <android.support.design.widget.TabLayout
        android:id="@+id/tablayout"
        android:layout_width="match_parent"
        android:layout_height="30dp"
        android:background="@color/textColor"
        android:minHeight="?attr/actionBarSize"
        android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
    </android.support.design.widget.TabLayout>
    <android.support.v4.view.ViewPager
        android:layout_width="match_parent"
        android:layout_height="fill_parent"
        android:id="@+id/pager"
        android:background="@color/background">
    </android.support.v4.view.ViewPager>
</LinearLayout>
fragment_tab3.xml - fragment_tab1.xml & fragment_tab2.xml are simple copies:
<LinearLayout 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="com.myapps.toualbiamine.weathertracker.Tab1"
    android:orientation="vertical"
    android:layout_weight="1"
    android:background="@drawable/bg"
    android:backgroundTintMode="multiply"
    android:backgroundTint="@color/background">
    <!-- TODO: Update blank fragment layout -->
    <TextView
        android:id="@+id/title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Data"
        android:textSize="40dp"
        android:layout_gravity="center"
        android:layout_marginTop="40dp"
        android:textColor="@color/titleColor" />
    <TextView
        android:id="@+id/dataTextTab3"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="120dp"
        android:text="Data will come here"
        android:textSize="15dp"
        android:layout_gravity="center"
        />
    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <android.support.design.widget.FloatingActionButton
            android:id="@+id/floatingActionButton4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignParentEnd="true"
            android:layout_alignParentRight="true"
            android:layout_marginBottom="28dp"
            android:layout_marginEnd="16dp"
            android:layout_marginRight="16dp"
            android:clickable="true"
            app:backgroundTint="@color/background"
            app:fabSize="normal"
            app:srcCompat="@drawable/ic_refresh_black_24dp"
            android:onClick="refresh"/>
    </RelativeLayout>
</LinearLayout>
So, I've been trying to figure out a way around my problem & have done a lot of reading but I've been stuck here for now a week & it's the last part of my project.
Here is the issue. You can see that in my MainActivity class, in the method receiveString(), there is the following line: 
dataTextTab3.setText(response.substring(positionFactor * 169 + 16 + 3, positionFactor * 169 + 16 + 3 + 144));
I used the same line for my two other TextViews dataTextTab1 & dataTextTab2 a few lines before in this same method. 
This is the part where I parse the data that I want received from the website. The numbers correspond to a formula to determine the indexes of the substring I set the text to.
It works perfectly fine for my two other TextViews but when I reach the third TextView, dataTextTab3, I get a NullPointerException & I can't get my head around it to figure it out. 
StackTrace:
E/AndroidRuntime: FATAL EXCEPTION: main Process: com.myapps.toualbiamine.weathertracker, PID: 22340 java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setText(java.lang.CharSequence)' on a null object reference
at com.myapps.toualbiamine.weathertracker.MainActivity$2. onResponse(MainActivity.java:139) at com.myapps.toualbiamine.weathertracker.MainActivity$2 .onResponse(MainActivity.java:108) at com.android.volley.toolbox.StringRequest. deliverResponse(StringRequest.java:60) at com.android.volley.toolbox.StringRequest. deliverResponse(StringRequest.java:30) at com.android.volley.ExecutorDelivery$ResponseDeliveryRunnable. run(ExecutorDelivery.java:99) at android.os.Handler.handleCallback(Handler.java:790) at android.os.Handler.dispatchMessage(Handler.java:99) at android.os.Looper.loop(Looper.java:164) at android.app.ActivityThread.main(ActivityThread.java:6494) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller. run(RuntimeInit.java:438) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:807)
One more thing, I get that error if I refresh 3 times from the first tab to logically fill all the tabs at once, however, if I refresh the first tab, then go to the second one & refresh it, and then go to the third one & refresh it, I do not get the NullPointerException.
Is there a way to avoid that NPE whatever happens? I would like to make sure that the user can refresh 3 times from the first tab without having the app crashing.
Thank you very much, Community! Please, I place a lot of hope into you right now, be the hero I need.
PSA: not duplicate of "why am I getting a NPE" since I went through most of the posts & I am explicitly declaring and instantiating my variables.
 
    