I tried to transfer data from View Fragment which contains RecycleView to Display Fragment... but I'm getting null Exception Error every time while using bundle
Here is my code.
Inside Adapter
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
StringIntString ping=arrayList.get(position);
holder.name.setText(ping.getmString());
holder.desc.setText(ping.getnString());
holder.num.setText(Integer.toString(ping.getmInt()));
holder.layout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Bundle bundle=new Bundle();
bundle.putString("name", ping.getmString());
bundle.putString("desc", ping.getnString());
bundle.putString("num",Integer.toString(ping.getmInt()));
DisplayFrag frag=new DisplayFrag();
frag.setArguments(bundle);
((FragmentActivity)view.getContext()).getSupportFragmentManager().beginTransaction().setCustomAnimations(R.anim.fade_in,R.anim.slide_out).replace(R.id.fragview,DisplayFrag.class,null).commit();
}
});
}
Inside Display view
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
v=inflater.inflate(R.layout.fragment_viewfrag2, container, false);
name=v.findViewById(R.id.box1);
desc=v.findViewById(R.id.box2);
num=v.findViewById(R.id.box3);
Bundle bundle=this.getArguments();
// if(bundle != null) {
name.setText(bundle.getString("name"));
desc.setText(bundle.getString("desc"));
num.setText(bundle.getInt("num"));
// }
return v;
}
Log Message
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.myapplication, PID: 31856
java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.os.Bundle.getString(java.lang.String)' on a null object reference
at com.example.myapplication.DisplayFrag.onCreateView(DisplayFrag.java:31)
at androidx.fragment.app.Fragment.performCreateView(Fragment.java:3104)
at androidx.fragment.app.FragmentStateManager.createView(FragmentStateManager.java:524)
at androidx.fragment.app.FragmentStateManager.moveToExpectedState(FragmentStateManager.java:261)
at androidx.fragment.app.FragmentManager.executeOpsTogether(FragmentManager.java:1899)
at androidx.fragment.app.FragmentManager.removeRedundantOperationsAndExecute(FragmentManager.java:1817)
at androidx.fragment.app.FragmentManager.execPendingActions(FragmentManager.java:1760)
at androidx.fragment.app.FragmentManager$5.run(FragmentManager.java:547)
at android.os.Handler.handleCallback(Handler.java:938)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loopOnce(Looper.java:201)
at android.os.Looper.loop(Looper.java:288)
at android.app.ActivityThread.main(ActivityThread.java:7839)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:548)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1003)
I'm expecting to transfer data from View fragment to Display fragmnet
In your constants class define new (you can make it Static) variables like below
public class MyUtils
{
public static MutableLiveData<String> nameMutableLiveDataString = new MutableLiveData<>();
public static MutableLiveData<String> descMutableLiveDataString = new MutableLiveData<>();
public static MutableLiveData<Integer> numMutableLiveDataString = new MutableLiveData<>();
and your onBindViewHolder will look something like this
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
StringIntString ping=arrayList.get(position);
holder.name.setText(ping.getmString());
holder.desc.setText(ping.getnString());
holder.num.setText(Integer.toString(ping.getmInt()));
holder.layout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
MyUtils.nameMutableLiveDataString.postValue(ping.getmString());
MyUtils.descMutableLiveDataString.postValue(ping.getnString());
MyUtils.numMutableLiveDataString.postValue(ping.getmInt());
// Bundle bundle=new Bundle();
// bundle.putString("name", ping.getmString());
// bundle.putString("desc", ping.getnString());
// bundle.putString("num",Integer.toString(ping.getmInt()));
DisplayFrag frag=new DisplayFrag();
// frag.setArguments(bundle);
((FragmentActivity)view.getContext()).getSupportFragmentManager().beginTransaction().setCustomAnimations(R.anim.fade_in,R.anim.slide_out).replace(R.id.fragview,DisplayFrag.class,null).commit();
}
});
}
and your view class something like this
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
v=inflater.inflate(R.layout.fragment_viewfrag2, container, false);
name=v.findViewById(R.id.box1);
desc=v.findViewById(R.id.box2);
num=v.findViewById(R.id.box3);
Bundle bundle=this.getArguments();
// if(bundle != null) {
MyUtils.nameMutableLiveDataString.observe((LifecycleOwner) this, new Observer<String>()
{
#Override
public void onChanged(String s)
{
name.setText(s);
}
});
MyUtils.descMutableLiveDataString.observe((LifecycleOwner) this, new Observer<String>()
{
#Override
public void onChanged(String s)
{
desc.setText(s);
}
});
MyUtils.numMutableLiveDataString.observe((LifecycleOwner) this, new Observer<Integer>()
{
#Override
public void onChanged(Integer s)
{
num.setText(s.toString());
}
});
// }
return v;
}
Related
This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 1 year ago.
So I've set up my RecyclerView with API and it's populating the list on the adapter but every time I click on the list item it should open the new activity and pass position through an interface.
The click gives me NullPointerException:
public class ticketsListAdapter extends RecyclerView.Adapter<ticketsListAdapter.ViewHolder>{
onclicklistner listners;
Context context;
public ticketsListAdapter(Context context, onclicklistner listners) {
this.context = context;
this.listners = listners;
}
#NonNull
#Override
public ticketsListAdapter.ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(context).inflate(R.layout.list_support_tickets,parent, false);
return new ViewHolder(view, listners);
}
#Override
public void onBindViewHolder(#NonNull ticketsListAdapter.ViewHolder holder, int position) {
holder.item_name.setText("hello");
}
#Override
public int getItemCount() {
return 5;
}
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView item_name;
public ViewHolder(#NonNull View itemView, onclicklistner listner) {
super(itemView);
item_name = itemView.findViewById(R.id.tickets_name);
item_name.setOnClickListener(this::onClick);
}
#Override
public void onClick(View v) {
listners.onItemClick(getAdapterPosition(), item_name);
}
}
public interface onclicklistner{
void onItemClick(int position, View v);
}
}
Log cat & Debug output:
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.kalyani.aura, PID: 21421
java.lang.NullPointerException: Attempt to invoke interface method 'void com.kalyani.aura.adapters.ticketsListAdapter$onclicklistner.onItemClick(int, android.view.View)' on a null object reference
at com.kalyani.aura.adapters.ticketsListAdapter$ViewHolder.onClick(ticketsListAdapter.java:60)
at com.kalyani.aura.adapters.-$$Lambda$hRD_GBr-hvL2HaQtFW31sqkj_0o.onClick(Unknown Source:2)
at android.view.View.performClick(View.java:7125)
at android.view.View.performClickInternal(View.java:7102)
at android.view.View.access$3500(View.java:801)
at android.view.View$PerformClick.run(View.java:27336)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
Fragment Where Recycler view Implemented
public class support_fragment extends Fragment {
FloatingActionButton create_support;
ticketsListAdapter.onclicklistner listner;
RecyclerView recyclerView;
ticketsListAdapter ticketsListAdapter;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_support, container, false);
create_support = view.findViewById(R.id.create_support);
recyclerView = view.findViewById(R.id.support_recycler);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
recyclerView.setHasFixedSize(false);
ticketsListAdapter = new ticketsListAdapter(getContext(), listner);
recyclerView.setAdapter(ticketsListAdapter);
create_support.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent i = new Intent(getContext(), Support_main_activity.class);
startActivity(i);
}
});
listner = new ticketsListAdapter.onclicklistner() {
#Override
public void onItemClick(int position, View v) {
Toast.makeText(getContext(), "Test", Toast.LENGTH_SHORT).show();
}
};
return view;
}
}
You are using the listener before initialization. This is why you are getting nullpointerexception.
public class support_fragment extends Fragment {
FloatingActionButton create_support;
ticketsListAdapter.onclicklistner listner;
RecyclerView recyclerView;
ticketsListAdapter ticketsListAdapter;
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_support, container, false);
create_support = view.findViewById(R.id.create_support);
recyclerView = view.findViewById(R.id.support_recycler);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
recyclerView.setHasFixedSize(false);
//initialize the listner before using!
listner = new ticketsListAdapter.onclicklistner() {
#Override
public void onItemClick(int position, View v) {
Toast.makeText(getContext(), "Test", Toast.LENGTH_SHORT).show();
}
};
ticketsListAdapter = new ticketsListAdapter(getContext(), listner);
recyclerView.setAdapter(ticketsListAdapter);
create_support.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent i = new Intent(getContext(), Support_main_activity.class);
startActivity(i);
}
});
/*
listner = new ticketsListAdapter.onclicklistner() {
#Override
public void onItemClick(int position, View v) {
Toast.makeText(getContext(), "Test", Toast.LENGTH_SHORT).show();
}
};
*/
return view;
}
}
I have 2 fragments. When I click like in one fragment, in the second fragment must appear news, which I liked.
Here is my favourite fragment I have a method Add()
RecyclerView recyclerView;
private FavouriteListAdapter adapter;
private List<News> newsList;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
ViewGroup rootView = (ViewGroup)inflater.inflate(R.layout.fragment_favourite, container,
false);
recyclerView = rootView.findViewById(R.id.recycler_favourite);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
newsList= new ArrayList<>();
adapter = new FavouriteListAdapter(newsList);
recyclerView.setAdapter(adapter);
return rootView;
}
public void addNews(News news) {
newsList.add(news);
recyclerView.getAdapter().notifyItemInserted(newsList.size() - 1);
}
In Home Fragment I use interface listener and add
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.fragment_home, container, false);
recyclerView = (RecyclerView) rootView.findViewById(R.id.recycler_home);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
listener = new NewsListAdapter.ItemClickListener() {
#Override
public void likeClick(int position, News item) {
add.respond(item);
newsListAdapter.notifyItemChanged(position);
}
};
add = new NewsListAdapter.Add() {
#Override
public void respond(News news) {
((MainActivity) getActivity()).respond(news);
}
};
newsListAdapter = new NewsListAdapter(newsGenerator(), listener, add);
recyclerView.setAdapter(newsListAdapter);
return rootView;
}
Adapter for Home
#Override
public void onBindViewHolder(#NonNull NewsListAdapter.NewsViewHolder holder, final int position)
{
final News news = mainList.get(position);
holder.theme.setText(news.getTheme());
holder.like.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (listener!=null){
listener.likeClick(position,news);
}
}
});
#Override
public int getItemCount() {
return mainList.size();
}
public class NewsViewHolder extends RecyclerView.ViewHolder {
private TextView theme;
private ImageButton like;
public NewsViewHolder(#NonNull View itemView) {
super(itemView);
theme = itemView.findViewById(R.id.theme);
like = itemView.findViewById(R.id.like);
}
}
interface ItemClickListener {
void likeClick(int position, News item);
}
public interface Add{
void respond(News news);
}
Adaper for favourites. Adapter favourites contains News and we call method add here in MainActivity
#NonNull
#Override
public FavouriteListAdapter.FavouriteNewsHolder onCreateViewHolder(#NonNull ViewGroup parent,
int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.news, null,false);
RecyclerView.LayoutParams params = new RecyclerView.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
);
view.setLayoutParams(params);
return new FavouriteNewsHolder(view);
}
#Override
public void onBindViewHolder(#NonNull FavouriteListAdapter.FavouriteNewsHolder holder, int
position) {
final News news = newsList.get(position);
holder.theme.setText(news.getTheme());
}
#Override
public int getItemCount() {
return newsList.size();
}
public class FavouriteNewsHolder extends RecyclerView.ViewHolder {
TextView theme;
ImageButton like;
public FavouriteNewsHolder(#NonNull View itemView) {
super(itemView);
theme = itemView.findViewById(R.id.theme);
like = itemView.findViewById(R.id.like);
}
}
in Activity I overwrite my method. When I execute my programm and click button click the program stopping
#Override
public void respond(News news) {
FavouriteFragment f = (FavouriteFragment)
getSupportFragmentManager().findFragmentById(R.id.fragment_container);
f.addNews(news);
}
In logcat:
2020-03-24 21:55:12.367 13933-13933/com.example.newsfragment E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.newsfragment, PID: 13933
java.lang.ClassCastException: com.example.newsfragment.HomeFragment cannot be cast to com.example.newsfragment.FavouriteFragment
at com.example.newsfragment.MainActivity.respond(MainActivity.java:50)
at com.example.newsfragment.HomeFragment$2.respond(HomeFragment.java:51)
at com.example.newsfragment.HomeFragment$1.likeClick(HomeFragment.java:43)
at com.example.newsfragment.NewsListAdapter$1.onClick(NewsListAdapter.java:61)
at android.view.View.performClick(View.java:7125)
at android.view.View.performClickInternal(View.java:7102)
at android.view.View.access$3500(View.java:801)
at android.view.View$PerformClick.run(View.java:27336)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
The 50 line in MainActivity
public void respond(News news) {
FavouriteFragment f = (FavouriteFragment)
getSupportFragmentManager().findFragmentById(R.id.fragment_container);
f.addNews(news);
}
Use the eventBus for this type of communication with a fragment. Using https://github.com/greenrobot/EventBus this lib I have implemented the same things(When like a post in homeFragment at that time I want to like that post in multiple fragments)
Register and unregister EventBus
#Override public void onStart() {
super.onStart();
EventBus.getDefault().register(this); }
#Override public void onStop() {
super.onStop();
EventBus.getDefault().unregister(this); }
Post events:
EventBus.getDefault().post(new MessageEvent());
I have 2 fragment consist of FeedFragment(Fragment) which will transfer the string to Transfer(Fragment). I am using interface to transfer it.
FeedFragment
public class FeedFragment extends Fragment {
public interface OnInputSelected{
void sendInput(String input);
}
public OnInputSelected mOnInputSelected;
private TextView feed;
private TextView bt;
private String input;
public FeedFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_feed, container, false);
feed= view.findViewById(R.id.feed);
bt= view.findViewById(R.id.bt);
bt.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
input=feed.getText().toString();
mOnInputSelected.sendInput(input);
}
});
// Inflate the layout for this fragment
return view;
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
mOnInputSelected = (FeedFragment.OnInputSelected) getTargetFragment();
} catch (ClassCastException e) {
Log.e(TAG, "onAttach: ClassCastException : " + e.getMessage());
}
}
}
Transfer
public class Transfer extends Fragment implements FeedFragment.OnInputSelected{
public TextView transfer;
#Override
public void sendInput(String input) {
transfer.setText(input);
}
public Transfer() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_transfer, container, false);
// Inflate the layout for this fragment
transfer= view.findViewById(R.id.transfer);
return view;
}
}
Error
Attempt to invoke interface method 'void com.shrikanthravi.customnavigationdrawer.FeedFragment$OnInputSelected.sendInput(java.lang.String)' on a null object reference
at com.shrikanthravi.customnavigationdrawer.FeedFragment$1.onClick(FeedFragment.java:49)
I try to load the database from firebase database and get this exception. It is about the notifyDataSetChanged. I has tried to put in in getCount() in SlideShowAapter but it has not worked.
Exceptions:
java.lang.IllegalStateException: The application's PagerAdapter changed the adapter's contents without calling PagerAdapter#notifyDataSetChanged!
Expected adapter item count: 0, found: 1 Pager id: com.example.dave.lomoapp:id/slideShow Pager class: class android.support.v4.view.ViewPager
Problematic adapter: class com.example.davenguyen.lomoapp.SlideShowAdapter
at android.support.v4.view.ViewPager.populate(ViewPager.java:1135)
at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:662)
at android.support.v4.view.ViewPager.setCurrentItemInternal(ViewPager.java:624)
at android.support.v4.view.ViewPager.setCurrentItem(ViewPager.java:616)
at com.example.davenguyen.lomoapp.HomeFragment$1.run(HomeFragment.java:71)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:148)
at android.app.ActivityThread.main(ActivityThread.java:7331)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1230)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1120)
This my SlideShowAdapter
public class SlideShowAdapter extends PagerAdapter {
private boolean doNotifyDataSetChangedOnce = false;
private ArrayList<Genre> genresList;
private LayoutInflater inflater;
private Context context;
public SlideShowAdapter(Context context, ArrayList<Genre> images) {
this.context = context;
this.genresList =images;
inflater = LayoutInflater.from(context);
}
#Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
#Override
public int getCount()
{
if (doNotifyDataSetChangedOnce) {
doNotifyDataSetChangedOnce = false;
notifyDataSetChanged();
}
return genresList.size();
}
#Override
public Object instantiateItem(ViewGroup view, int position) {
View myImageLayout = inflater.inflate(R.layout.slide, view, false);
ImageView myImage = (ImageView) myImageLayout
.findViewById(R.id.slideShowImg);
Picasso.with(context).load(genresList.get(position).getImage()).into(myImage);
view.addView(myImageLayout, 0);
view.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
}
});
return myImageLayout;
}
#Override
public boolean isViewFromObject(View view, Object object) {
return view.equals(object);
}
}
This a fragment that has my custom adapter
public class HomeFragment extends Fragment {
private static ViewPager mPager;
private static int currentPage = 0;
private ArrayList<Genre> genreList = new ArrayList<Genre>();
DatabaseReference mref;
public HomeFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
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);
loadImage();
mPager = (ViewPager) view.findViewById(R.id.slideShow);
mPager.setAdapter(new SlideShowAdapter(getActivity(), genreList));
CircleIndicator indicator = (CircleIndicator) view.findViewById(R.id.indicator);
indicator.setViewPager(mPager);
// Auto start of viewpager
final Handler handler = new Handler();
final Runnable Update = new Runnable() {
public void run() {
if (currentPage == genreList.size()) {
currentPage = 0;
}
mPager.setCurrentItem(currentPage++, true);
}
};
Timer swipeTimer = new Timer();
swipeTimer.schedule(new TimerTask() {
#Override
public void run() {
handler.post(Update);
}
}, 2500, 2500);
}
private void loadImage() {
// Get a reference to our genres
mref = FirebaseDatabase.getInstance().getReference().child("genres");
// Attach a listener to read the data at our genres reference
mref.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
genreList.add (dataSnapshot.getValue(Genre.class));
}
#Override
public void onCancelled(DatabaseError databaseError) {
Log.i("READ_FAIELD","The read failed: " + databaseError.getCode());
}
});
}
}
Thanks in advance
My guess is that the problem is that flag doNotifyDataSetChangedOnce in your adapter. Try to remove that if and call adapter.notifyDataSetChanged() after your image is loaded (in onDataChange).
If this solves the crash but the viewPager is not updated, you might need to add this code in your adapter:
public int getItemPosition(Object object) {
return POSITION_NONE;
}
Write this way :
SlideShowAdapter adapter=new SlideShowAdapter(getActivity(), genreList);
mPager.setAdapter(adapter);
adapter.notifyDataSetChanged();
Instead of
mPager.setAdapter(new SlideShowAdapter(getActivity(), genreList));
Try changing in instantiateItem with this:
View myImageLayout = inflater.inflate(R.layout.slide, view, false);
ImageView myImage = (ImageView) myImageLayout
.findViewById(R.id.slideShowImg);
Picasso.with(context).load(genresList.get(position).getImage()).into(myImage);
.
myImageLayout.addView(myImage, 0);
myImageLayout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
}
});
return myImageLayout;
And remove :
if (doNotifyDataSetChangedOnce) {
doNotifyDataSetChangedOnce = false;
notifyDataSetChanged();
}
I create custom dialog by extending DialogFragment class. My Dialog show list menu based on parameters List<String> datas. So, I create a custom adapter for that.
ListMenuAdapter.java
/**
* Created by fanjavaid on 10/2/17.
*/
public class ListMenuAdapter extends ArrayAdapter<String> implements View.OnClickListener {
private Context mContext;
private List<String> mMenus;
private OnClickItemMenuListener onClickItemMenuListener;
public ListMenuAdapter(#NonNull Context context, #LayoutRes int resource, #NonNull List<String> objects) {
super(context, resource, objects);
this.mMenus = objects;
this.mContext = context;
}
#NonNull
#Override
public View getView(int position, #Nullable View convertView, #NonNull ViewGroup parent) {
String menu = mMenus.get(position);
LayoutInflater inflater = LayoutInflater.from(mContext);
final ViewListItemBinding binding = DataBindingUtil.inflate(inflater, R.layout.view_list_item, null, false);
binding.textListMenu.setTag(R.string.id_menu_item, position);
binding.textListMenu.setText(menu);
binding.textListMenu.setOnClickListener(this);
return binding.getRoot();
}
#Override
public void onClick(View v) {
onClickItemMenuListener.onClickItem((int) v.getTag(R.string.id_menu_item));
}
public OnClickItemMenuListener getOnClickItemMenuListener() {
return onClickItemMenuListener;
}
public void setOnClickItemMenuListener(OnClickItemMenuListener onClickItemMenuListener) {
this.onClickItemMenuListener = onClickItemMenuListener;
}
public interface OnClickItemMenuListener {
void onClickItem(int index);
}
}
In the code above, I create Listener to handle click event in each list menu.
Below is my Custom dialog implementation.
CustomDialogMenu.java
public class CustomDialogMenu extends DialogFragment implements
ListMenuAdapter.OnClickItemMenuListener {
private DialogTemplateBinding mDataBinding;
private FragmentManager dialogFragmentManager;
private List<String> mMenus;
private IDialogView.ListMenuSelectedListener onMenuClickListener;
private ListMenuAdapter mMenuAdapter;
public CustomDialogMenu() {
}
public static CustomDialogMenu newInstance() {
CustomDialogMenu fragment = new CustomDialogMenu();
Bundle bundle = new Bundle();
fragment.setArguments(bundle);
return fragment;
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
mDataBinding = DataBindingUtil.inflate(inflater, R.layout.dialog_template, container, false);
// Create menu list and add click listener
mMenuAdapter = new ListMenuAdapter(getActivity(), 0, mMenus);
mMenuAdapter.setOnClickItemMenuListener(this);
mDataBinding.dialogListMenu.setAdapter(mMenuAdapter);
return mDataBinding.getRoot();
}
#NonNull
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
Dialog dialog = super.onCreateDialog(savedInstanceState);
dialog.getWindow().requestFeature(Window.FEATURE_NO_TITLE);
return dialog;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
getDialog().getWindow().setWindowAnimations(R.style.DialogAnimation);
}
#Override
public void onStart() {
super.onStart();
getDialog().getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT);
getDialog().getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
}
public void show() {
if (null == dialogFragmentManager)
throw new NullPointerException("dialogFragmentManager is null. " +
"Please set it from support FragmentManager when instantiate this Fragment.");
show(dialogFragmentManager, "CustomDialog");
}
public void setDialogFragmentManager(FragmentManager dialogFragmentManager) {
this.dialogFragmentManager = dialogFragmentManager;
}
public void setMenus(List<String> mMenus) {
this.mMenus = mMenus;
}
public IDialogView.ListMenuSelectedListener getOnMenuClickListener() {
return onMenuClickListener;
}
public void setOnMenuClickListener(IDialogView.ListMenuSelectedListener onMenuClickListener) {
this.onMenuClickListener = onMenuClickListener;
}
#Override
public void onClickItem(int index) {
onMenuClickListener.onItemSelected(index);
// Toast.makeText(getActivity(), "Is NULL : " + (getOnMenuClickListener() == null), Toast.LENGTH_SHORT).show();
}
}
Finally, I can create the dialog menu using this code :
// Show popup menu
List<String> menus = new ArrayList<>();
menus.add(getString(R.string.occupant_detail_menu_edit));
menus.add(getString(R.string.occupant_detail_menu_delete));
CustomDialogMenu dialog = new CustomDialogMenu();
dialog.setMenus(menus);
dialog.setDialogFragmentManager(getSupportFragmentManager());
dialog.setOnMenuClickListener(new IDialogView.ListMenuSelectedListener() {
#Override
public void onItemSelected(int index) {
Toast.makeText(OccupantDetailActivity.this, "Index : " + index, Toast.LENGTH_SHORT).show();
}
});
dialog.show();
I got this following error when triggering click on a list item :
FATAL EXCEPTION: main
Process: android.bookost.com.bookost, PID: 29807
java.lang.NullPointerException: Attempt to invoke interface method
'void app.bookost.com.bookost.view.IDialogView$ListMenuSelectedListener.onItemSelected(int)' on a null object reference
at app.bookost.com.bookost.view.component.CustomDialogMenu.onClickItem(CustomDialogMenu.java:119)
at app.bookost.com.bookost.adapter.ListMenuAdapter.onClick(ListMenuAdapter.java:52)
at android.view.View.performClick(View.java:5637)
at android.view.View$PerformClick.run(View.java:22429)
at android.os.Handler.handleCallback(Handler.java:751)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6119)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:886)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:776)
It says null on IDialogView$ListMenuSelectedListener, but I already initialized it on onCreateView() method.
Is any other way to initialize it?
Thank you.