0

I have an application which has one main activity which in turn hosts two tabs. Each tab is a fragment. The first tab has an editText and a Button and on button press the text entered by the user must be displayed on the second tab fragment which hosts only one textView. I am using a listener to pass the data but for some reason the app crashes when i press the submit button. Any help would be appreciated. Here is my code:

MainActivity.java

    public class MainActivity extends AppCompatActivity implements OnEditTextListener {

    Toolbar toolbar;
    ViewPager pager;
    ViewPagerAdapter adapter;
    SlidingTabLayout tabs;
    CharSequence Titles[] = {"Home", "Events"};
    int Numboftabs = 2;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Creating The Toolbar and setting it as the Toolbar for the activity

        toolbar = (Toolbar) findViewById(R.id.tool_bar);
        setSupportActionBar(toolbar);


        // Creating The ViewPagerAdapter and Passing Fragment Manager, Titles fot the Tabs and Number Of Tabs.
        adapter = new ViewPagerAdapter(getSupportFragmentManager(), Titles, Numboftabs);

        // Assigning ViewPager View and setting the adapter
        pager = (ViewPager) findViewById(R.id.pager);
        pager.setAdapter(adapter);

        // Assiging the Sliding Tab Layout View
        tabs = (SlidingTabLayout) findViewById(R.id.tabs);
        tabs.setDistributeEvenly(true); // To make the Tabs Fixed set this true, This makes the tabs Space Evenly in Available width

        // Setting Custom Color for the Scroll bar indicator of the Tab View
        tabs.setCustomTabColorizer(new SlidingTabLayout.TabColorizer() {
            @Override
            public int getIndicatorColor(int position) {
                return getResources().getColor(R.color.ColorPrimary);
            }
        });

        // Setting the ViewPager For the SlidingTabsLayout
        tabs.setViewPager(pager);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @Override
    public void OnEditText(String data) {
        Tab2 newFragment = (Tab2)adapter.getItem(1);
        newFragment.updateDisplay(data);
    }
}

Tab1.java

import android.app.Activity;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.text.Editable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.EditText;

public class Tab1 extends Fragment
{
    public interface OnEditTextListener {
        public void OnEditText(String data);
    }

    OnEditTextListener editTextListener = null;
    EditText edtText;
    Button btnSubmit;

    String val;

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        try {
            editTextListener = (OnEditTextListener) activity;
        } catch (ClassCastException ex) {
            ex.printStackTrace();
        }
    }

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

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

        edtText = (EditText)getActivity().findViewById(R.id.edtText);
        btnSubmit = (Button)getActivity().findViewById(R.id.btnSubmit);
        btnSubmit.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                val = edtText.getText().toString();
                editTextListener.OnEditText(val);
            }
        });
    }
}

Tab2.java

public class Tab2 extends Fragment {

    public static final String TAG = "DATA";
    public static final String SAVE = "NBHJB";
    String newdata = "";

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        if (savedInstanceState != null)
            savedInstanceState.getInt(SAVE);

        return inflater.inflate(R.layout.second_fragment, container, false);
    }

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

        if (savedInstanceState != null) {
            savedInstanceState.getString(SAVE);
        }
    }

    public void updateDisplay(String data) {
        newdata = data;
        TextView randomData = (TextView) getActivity().findViewById(R.id.txtView1);
        randomData.setText(newdata);
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);

        outState.putString(SAVE, newdata);
    }

MainActivity.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <include
        android:id="@+id/tool_bar"
        layout="@layout/tool_bar"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />

    <View
        android:layout_height="2dip"
        android:background="@color/tabsScrollColor"
        android:layout_width="wrap_content" />

    <com.example.regi.tabsprove.SlidingTabLayout
        android:id="@+id/tabs"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:background="@color/prove"
        android:elevation="2dp" />



    <android.support.v4.view.ViewPager
        android:id="@+id/pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_weight="1"></android.support.v4.view.ViewPager>


</LinearLayout>

second_fragment.xml

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

    <TextView
        android:id="@+id/txtView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_weight="1"
        android:gravity="center"
        android:padding="10dp"
        android:text="Default Text"
        android:textSize="20dp" />

</LinearLayout>

This is the error that I get

java.lang.NullPointerException
            at com.example.regi.tabsprove.Tab2.updateDisplay(Tab2.java:36)
            at com.example.regi.tabsprove.MainActivity.OnEditText(MainActivity.java:79)
            at com.example.regi.tabsprove.Tab1$1.onClick(Tab1.java:51)
            at android.view.View.performClick(View.java:4198)
            at android.view.View$PerformClick.run(View.java:17158)
            at android.os.Handler.handleCallback(Handler.java:615)
            at android.os.Handler.dispatchMessage(Handler.java:92)
            at android.os.Looper.loop(Looper.java:137)
            at android.app.ActivityThread.main(ActivityThread.java:4918)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:511)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1004)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:771)
            at dalvik.system.NativeStart.main(Native Method)
DevilSummer
  • 3
  • 1
  • 5

3 Answers3

1

I'm pretty sure that the line Tab2 newFragment = (Tab2)adapter.getItem(1); is creating a new instance of Tab2 instead of giving you the Fragment that you need. You should find a better way to get the instance of the Fragment that has been built to you by the ViewPager; I'm sure that this post can help you.

Community
  • 1
  • 1
Mimmo Grottoli
  • 5,758
  • 2
  • 17
  • 27
  • Yes that was the problem. Thank you for your help – DevilSummer Jul 20 '15 at 09:33
  • Apparently getItem() is misleading and we need to get an instance of the existing fragment that we want by using `findFragmentByTag();` – DevilSummer Jul 20 '15 at 09:34
  • @DevilSummer: my experience is a little bit different about what you define 'misleading'. Let's suppose you have a ViewPager with 5 Fragments and you need a way to communicate between the first and the last fragment. It's not possible in the way you're implementing that feature, because when you're in the first Fragment, you don't know the status of the last one. You don't even know if that Fragment has been built or not. What about switching your approach to SharedPreferences? Save the value in the first fragment, read the value from the second (you can be notified of preference changes too) – Mimmo Grottoli Jul 20 '15 at 10:03
  • I am new in Android and still learning. Could you please provide me with an example? If you could show me how to implement the SharedPreferences approach in the code I have provided I'd be really grateful. – DevilSummer Jul 20 '15 at 19:15
0

I found your design a bit complicated than regular data passing. From the logs, the issue is the program unable to find txtView1 in second fragment. It is always a good practice to use bundle for passing data.

I hope the following changes should fix your problem, but that's not the best way to do it.

Declare your TextView next to newData

public static final String TAG = "DATA";
public static final String SAVE = "NBHJB";
String newdata = "";
TextView randomData;

Initialize it in onCreateView()

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    if (savedInstanceState != null)
        savedInstanceState.getInt(SAVE);

    View rootView = inflater.inflate(R.layout.second_fragment, container, false);

    randomData = (TextView) rootView.findViewById(R.id.txtView1);

    return rootView;
}

Change the updateDisplay function

public void updateDisplay(String data) {
    newdata = data;
    randomData.setText(newdata);
}

Make sure you dont have any other items with same id as txtView1.

ganeshvjy
  • 399
  • 1
  • 12
  • I implemented the changes you recommended and now I get this error `32403-32403/com.example.regi.tabsprove E/AndroidRuntime﹕ FATAL EXCEPTION: main java.lang.NullPointerException at com.example.regi.tabsprove.Tab2.updateDisplay(Tab2.java:41)` – DevilSummer Jul 19 '15 at 17:07
  • It corresponds to this line `randomData.setText(newdata);` – DevilSummer Jul 19 '15 at 17:09
  • What would be the best way to pass data in this case (I was following the general approach of passing data between 2 frags using an interface). Could you provide me with an example or please? – DevilSummer Jul 19 '15 at 17:43
0

Here is the solution to everyone who might be facing the same issue:

public static String makeFragmentName(int containerViewId, long id) {
        return "android:switcher:" + containerViewId + ":" + id;
    }

    public @Nullable
    Fragment getFragmentForPosition(int position)
    {
        String tag = makeFragmentName(pager.getId(), position);
        Fragment fragment = getSupportFragmentManager().findFragmentByTag(tag);
        return fragment;
    }

    @Override
    public void OnEditText(String data) {
        Tab2 tab2 = (Tab2)getFragmentForPosition(1);
        tab2.updateDisplay(data);
    }

This code goes to MainActivity.java

DevilSummer
  • 3
  • 1
  • 5