I am having troubling sending data from one fragment to another fragment. I was following the android guideline which tells me to create an interface to communicate with activity and fragments. I'm using the bottom navigation to switch over fragments. Anyway, here's the error from android studio:
java.lang.NullPointerException: Attempt to invoke virtual method 'void com.example.makkhay.cameratranslate.Favorite.displayReceivedData(java.lang.String)' on a null object reference
at com.example.makkhay.cameratranslate.HomeActivity.sendData(HomeActivity.java:143)
at com.example.makkhay.cameratranslate.HomeFragment$2.onClick(HomeFragment.java:162)
at android.view.View.performClick(View.java:6256)
at android.view.View$PerformClick.run(View.java:24697)
at android.os.Handler.handleCallback(Handler.java:789)
For some reason, my fragments are always null even after initializing it. I tried initializing it both ways, onCreate method, and the sendData method, the instance always seems to be null. I think the main culprit might be the DrawerLayout. Since it is the parent xml and there is another xml called "app_bar_home.xml"; which is hosting the two fragments using bottom navigation, the newly created instances are always null
Here's my main activity which is holding two fragments HomeActivity.java
public class HomeActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener,HomeFragment.SendMessage {
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener
= new BottomNavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem item) {
Fragment selectedFragment = null;
switch (item.getItemId()) {
case R.id.navigation_home:
selectedFragment = new HomeFragment();
break;
case R.id.navigation_favorite:
selectedFragment = new Favorite();
break;
}
getSupportFragmentManager().beginTransaction().replace(R.id.app_bar,
selectedFragment).commit();
return true;
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.addDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
BottomNavigationView navigation = (BottomNavigationView) findViewById(R.id.navigation);
navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
//I added this if statement to keep the selected fragment when rotating the device
if (savedInstanceState == null) {
getSupportFragmentManager().beginTransaction().replace(R.id.app_bar,
new HomeFragment()).commit();
}
}
@Override
public void sendData(String message) {
Favorite f = (Favorite) getSupportFragmentManager().findFragmentById(R.id.favFragment);
f.displayReceivedData(message);
}
}
Here's my xml for my activity activity_home.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.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:id="@+id/drawer_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:openDrawer="start">
<include
android:id="@+id/app_bar"
layout="@layout/app_bar_home"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<android.support.design.widget.NavigationView
android:id="@+id/nav_view"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="start"
android:fitsSystemWindows="true"
app:headerLayout="@layout/nav_header_home"
app:menu="@menu/activity_home_drawer" />
</android.support.v4.widget.DrawerLayout>
Here's the app_bar_home.xml which is also part of the activity
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".HomeActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
>
<android.support.v7.widget.Toolbar
android:layout_width="match_parent"
android:layout_height="?actionBarSize"
app:layout_collapseMode="pin"
android:id="@+id/toolbar"
/>
</android.support.design.widget.AppBarLayout>
<android.support.design.widget.BottomNavigationView
android:id="@+id/navigation"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="0dp"
android:layout_marginStart="0dp"
app:layout_constraintBottom_toBottomOf="parent"
android:background="#000"
app:itemIconTint="@color/color_selector"
app:itemTextColor="@color/color_selector"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:menu="@menu/navigation" />
</android.support.constraint.ConstraintLayout>
Here's the fragment 1 from which I want to send the data to another fragment. HomeFragment.java
public class HomeFragment extends Fragment implements View.OnClickListener{
SendMessage SM;
private Button clearButton, favButton, shareButton;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_home, container, false);
return v;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
favButton = view.findViewById(R.id.favButton);
favButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
SM.sendData(" test");
}
});
}
interface SendMessage {
void sendData(String message);
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
try {
SM = (SendMessage) getActivity();
} catch (ClassCastException e) {
throw new ClassCastException("Error in retrieving data. Please try again");
}
}
}
HomeFragment.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
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:id="@+id/homeFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".HomeFragment"
>
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?actionBarSize"
app:layout_collapseMode="pin" />
</android.support.design.widget.AppBarLayout>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="6dp"
android:layout_marginEnd="6dp"
android:layout_marginLeft="6dp"
android:layout_marginRight="6dp"
android:layout_marginStart="6dp"
android:layout_marginTop="56dp"
android:background="@drawable/card_shadow"
android:divider="?android:dividerHorizontal"
android:paddingTop="6dp"
android:paddingBottom="6dp"
android:showDividers="middle">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:paddingBottom="16dp"
android:gravity="right"
android:orientation="vertical">
<Button
android:id="@+id/favButton"
android:layout_width="48dp"
android:layout_height="48dp"
android:layout_marginTop="4dp"
android:background="@drawable/ic_favorite_black_12dp"
/>
</LinearLayout>
</LinearLayout>
</android.support.constraint.ConstraintLayout>
</android.support.constraint.ConstraintLayout>
Finally here's the 2nd fragment where I want to recieve the data Favorite.java
public class Favorite extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_favorite, container, false);
favText = v.findViewById(R.id.tv_recycler_item_1);
return v;
}
protected void displayReceivedData(String message)
{
Toast.makeText(getContext(),"rec:" + message,Toast.LENGTH_SHORT).show();
}
}
fragment_favorite.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
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:id="@+id/favFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".Favorite">
<android.support.design.widget.AppBarLayout
android:id="@+id/app_bar_scrolling"
android:layout_width="match_parent"
android:layout_height="180dp"
android:fitsSystemWindows="true"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<android.support.design.widget.CollapsingToolbarLayout
android:id="@+id/collapsing_toolbar_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
app:contentScrim="?attr/colorPrimary"
app:layout_scrollFlags="scroll|exitUntilCollapsed">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:scaleType="centerCrop"
android:src="@drawable/bg_red" />
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:layout_scrollFlags="scroll|enterAlways"
app:popupTheme="@style/Widget.AppCompat.PopupMenu.Overflow" />
</android.support.design.widget.CollapsingToolbarLayout>
</android.support.design.widget.AppBarLayout>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
>
<TextView
android:id="@+id/txtData"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="548dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/recycler_view_recycler_view"
app:layout_constraintStart_toStartOf="parent" />
<android.support.v7.widget.RecyclerView
android:id="@+id/recycler_view_recycler_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="382dp"
android:layout_marginEnd="344dp"
android:layout_marginRight="344dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent">
</android.support.v7.widget.RecyclerView>
</android.support.constraint.ConstraintLayout>
</android.support.design.widget.CoordinatorLayout>
Let me know if you need more info. thanks in advance :)