I have implemented a ricyvlerview search, and i want to listen for clicks, but context is allways null, i even tryed to move the method to an activity and i got the same result
This is my first time messing arround with Data binding i searched alot here but i can't find what i am doing wrong
item_exemple.xml
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable
name="model"
type="pt.condutorresponsavel.android.testescodigo.Search.models.ExampleModel"/>
<variable
name="handlers"
type="pt.condutorresponsavel.android.testescodigo.Study"/>
</data>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/selectableItemBackground"
android:clickable="true">
<TextView
android:onClick="#{(v) -> handlers.onCategoryClick(v,model)}"
android:ellipsize="end"
android:lines="1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp"
android:text="#{model.text}"/>
<View
android:layout_marginTop="40dp"
android:layout_width="match_parent"
android:layout_height="2dp"
android:background="#color/colorPrimary"
android:alpha="0.17"/>
</FrameLayout>
ExampleViewHolder.java
public class ExampleViewHolder extends SortedListAdapter.ViewHolder<ExampleModel> {
private final ItemExampleBinding mBinding;
public ExampleViewHolder(ItemExampleBinding binding) {
super(binding.getRoot());
mBinding = binding;
}
#Override
protected void performBind(ExampleModel item) {
mBinding.setModel(item);
mBinding.setHandlers(new Study());
}
}
Study.java
public class Study extends Fragment {
public static Fragment fragment;
public static SearchView searchView;
Context context;
private final String[] pageNames = {"Favorites", ""};
ViewPager pager;
private OnFragmentInteractionListener mListener;
public Study() { }
public static Estudo newInstance(String param1, String param2) {
Estudo fragment = new Estudo();
Bundle args = new Bundle();
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_estudo, container, false);
fragment = this;
...
pager = (ViewPager) view.findViewById(R.id.pager);
pager.setAdapter(buildAdapter());
return view;
}
private PagerAdapter buildAdapter() {
return(new SampleAdapter(getActivity(), getChildFragmentManager()));
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
this.context = context;
}
public interface OnFragmentInteractionListener {
void onFragmentInteraction(Uri uri);
}
public class SampleAdapter extends FragmentPagerAdapter {
Context ctxt = null;
public SampleAdapter(Context ctxt, FragmentManager mgr) {
super(mgr);
this.ctxt = ctxt;
}
#Override
public int getCount() {
return (2);
}
#Override
public Fragment getItem(int position) {
if (position == 0) {
return Favorites.newInstance(position + 1);
}else{
return otherFragment.newInstance(position + 1);
}
}
#Override
public String getPageTitle ( int position){
return (String.valueOf(pageNames[position]));
}
}
public void onCategoryClick(View view, ExampleModel model) {
Log.d("mTag", "Index: " + model.getId());
Dialog dialog = new Dialog(getActivity()); //NullPointerException
dialog.setContentView(R.layout.dialog_pergunta);
dialog.show();
}
public static class Favorites extends Fragment{...} //RecyclerView is in here
public static class otherFragment extends Fragment{...}
}
Problem
public void onCategoryClick(View view, ExampleModel model) {
Log.d("mTag", "Index: " + model.getId());
Dialog dialog = new Dialog(getActivity()); //NullPointerException
dialog.setContentView(R.layout.dialog);
dialog.show();
}
i tried setting the context in onAttach and also tried to use
final Context contex = getActivity();
but nothing worked outside onCategoryClick the context is not null but inside onCategoryClick the context is null
how can i overcome this?
EDIT
if i don't declare my interface static i get this
NullPointerException: Attempt to invoke interface method 'void pt.condutorresponsavel.android.testescodigo.Study$OnItemClick.onClick(long)' on a null object reference at
pt.condutorresponsavel.android.testescodigo.Study.onCategoryClick(Study.java:303)
I was able to fix this, there may be better options to achive the same result but since i am not a expert this was what i come up with.
I created a Interface, on my fragment when the onCategoryClick is called i call a my interface.
static OnItemClick onItemClick;
...
public void onCategoryClick(View view, ExampleModel model) {
onItemClick.onClick(model.getId());
}
public interface OnItemClick{
void onClick(long index);
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
onItemClick = new OnItemClick() {
#Override
public void onClick(long index) {
Log.d(TAG, "myIndex: " + index);
Dialog dialog = new Dialog(getActivity());
dialog.getWindow().setBackgroundDrawable(new ColorDrawable(android.graphics.Color.TRANSPARENT));
dialog.setContentView(R.layout.dialog);
}
}
Related
I am trying to display news of different categories under different tabs using TabLayout. The corresponding fragments do not load at all, only the tabs are displayed. The app freezes when I try to scroll or select a tab such that even the tabIndicator barely moves to the corresponding tab and Android displays "Not responding" message.
MainActivity.java
public class MainActivity extends AppCompatActivity{
Toolbar toolbar;
TabLayout tabLayout;
ViewPager2 viewPager2;
NewsPagerAdapter newsPagerAdapter;
TabLayoutMediator tabLayoutMediator;
String[] tabTitles = new String[]{"HOME","BUSINESS","HEALTH","TECHNOLOGY","SPORTS"};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toolbar = findViewById(R.id.tbCustom);
tabLayout = findViewById(R.id.tlCategories); setSupportActionBar(toolbar);
viewPager2 = findViewById(R.id.vpNews);
newsPagerAdapter = new NewsPagerAdapter(getSupportFragmentManager(),getLifecycle());
viewPager2.setAdapter(newsPagerAdapter);
tabLayoutMediator = new TabLayoutMediator(tabLayout, viewPager2, (tab, position) -> tab.setText(tabTitles[position]));
tabLayoutMediator.attach();
tabLayout.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() {
#Override
public void onTabSelected(TabLayout.Tab tab) {
viewPager2.setCurrentItem(tab.getPosition());
newsPagerAdapter.notifyDataSetChanged();
}
#Override
public void onTabUnselected(TabLayout.Tab tab) {
}
#Override
public void onTabReselected(TabLayout.Tab tab) {
}
});
viewPager2.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
#Override
public void onPageSelected(int position) {
super.onPageSelected(position);
tabLayout.selectTab(tabLayout.getTabAt(position));
}
#Override
public void onPageScrollStateChanged(int state) {
super.onPageScrollStateChanged(state);
}
});
}
#Override
protected void onDestroy() {
super.onDestroy();
tabLayoutMediator.detach();
viewPager2.setAdapter(null);
}
}
NewsPagerAdapter.java
public class NewsPagerAdapter extends FragmentStateAdapter {
public NewsPagerAdapter(#NonNull FragmentManager fragmentManager, #NonNull Lifecycle lifecycle) {
super(fragmentManager, lifecycle);
}
#NonNull
#Override
public Fragment createFragment(int position) {
switch (position)
{
case 0: return new HomeFragment();
case 1: return new BusinessFragment();
case 2: return new HealthFragment();
case 3: return new TechnologyFragment();
case 4: return new SportsFragment();
default: return null;
}
}
#Override
public int getItemCount() {
return 5;
}
}
Home Fragment.java - Other fragments have the same structure
public class HomeFragment extends Fragment {
#Override
public void onDestroyView() {
super.onDestroyView();
recyclerView.setAdapter(null);
}
#Override
public void onDetach() {
super.onDetach();
}
private List<NewsModelClass> homeNews = new ArrayList<>();
String country = "in";
String category = "general";
int pageSize = 50;
private RecyclerView recyclerView;
NewsAdapter newsAdapter;
final String API_KEY = "ba88d060a3e049ca9fa46f2bea0d52c4";
public HomeFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
View v = inflater.inflate(R.layout.fragment_home, container, false);
recyclerView = v.findViewById(R.id.rvHome);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
return v;
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
newsAdapter = new NewsAdapter(getContext(),homeNews);
recyclerView.setAdapter(newsAdapter);
fetchNews();
}
private void fetchNews()
{
Call<NewsArticles> call = RetrofitClient.getInstance().getMyApi().getNews(country,pageSize,category,API_KEY);
call.enqueue(new Callback<NewsArticles>() {
#Override
public void onResponse(#NonNull Call<NewsArticles> call, #NonNull Response<NewsArticles> response) {
if(response.isSuccessful()) {
if (!homeNews.isEmpty()) {
homeNews.clear();
}
homeNews=response.body().getArticles();
newsAdapter.notifyDataSetChanged();
}
}
#Override
public void onFailure(#NonNull Call<NewsArticles> call, Throwable t) {
Toast.makeText(getContext(),"Something is wrong",Toast.LENGTH_SHORT).show();
}
});
}
}
fragment_home.xml - Other fragments have the same layout
<FrameLayout 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"
tools:context=".fragments.HomeFragment">
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/rvHome"
android:fitsSystemWindows="true"
android:padding="8dp"/>
</FrameLayout>
NewsAdapter.java
public class NewsAdapter extends
RecyclerView.Adapter<NewsAdapter.NewsViewHolder> {
Context context;
List<NewsModelClass> allNews;
public NewsAdapter(Context context,List<NewsModelClass>
allNews) {
this.context = context;
this.allNews = allNews;
}
#NonNull
#Override
public NewsViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View newsItem = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_news, parent, false);
return new NewsViewHolder(newsItem);
}
#Override
public void onBindViewHolder(#NonNull NewsViewHolder holder, int position) {
NewsModelClass currentNewsItem = allNews.get(position);
holder.title.setText(currentNewsItem.getTitle());
holder.author.setText(currentNewsItem.getAuthor());
if (currentNewsItem.getUrlToImage() != null)
Glide.with(holder.itemView.getContext()).load(Uri.parse(currentNewsItem.getUrlToImage())).into(holder.articleImage);
holder.cardView.setOnClickListener(v -> {
String newsUrl = currentNewsItem.getUrl();
CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
int colorInt = Color.parseColor("#F1ECC3");
CustomTabColorSchemeParams defaultColors = new CustomTabColorSchemeParams.Builder()
.setToolbarColor(colorInt)
.build();
builder.setDefaultColorSchemeParams(defaultColors);
CustomTabsIntent customTabsIntent = builder.build();
customTabsIntent.launchUrl(context, Uri.parse(newsUrl));
});
}
#Override
public int getItemCount() {
return allNews.size();
}
public static class NewsViewHolder extends RecyclerView.ViewHolder {
ImageView articleImage;
TextView title, author;
CardView cardView;
public NewsViewHolder(#NonNull View itemView) {
super(itemView);
articleImage = itemView.findViewById(R.id.ivArticleImage);
title = itemView.findViewById(R.id.tvHeadline);
author = itemView.findViewById(R.id.tvAuthor);
cardView = itemView.findViewById(R.id.cardView);
}
}
}
I have taken youtube-api sample app VideoListDemoActivity class for android and converted it to fragment to use in my app.
In inner class VideoListFragment the view videoBox from fragment is accessed, which returns null. In activity the view is not null but in fragment it's failing to get reference of fragment's view. I have attached code which I modified for this class.
Error Exception
2021-04-28 16:42:18.695 27495-27495/com.gardify.android
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.gardify.android, PID: 27495
java.lang.NullPointerException: Attempt to invoke virtual method 'int android.view.View.getVisibility()' on a null object reference
at com.gardify.android.ui.video.VideoFragment$VideoListFragment.onListItemClick(VideoFragment.java:192)
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
videoBox = getView().findViewById(R.id.video_box);
^^^^^^^^
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
setListAdapter(adapter);
}
modified Class
public final class VideoFragment extends Fragment {
/**
* The duration of the animation sliding up the video in portrait.
*/
private static final int ANIMATION_DURATION_MILLIS = 300;
/**
* The padding between the video list and the video in landscape orientation.
*/
private static final int LANDSCAPE_VIDEO_PADDING_DP = 5;
/**
* The request code when calling startActivityForResult to recover from an API service error.
*/
private static final int RECOVERY_DIALOG_REQUEST = 1;
private VideoListFragment listFragment;
private YoutubeFragment videoFragment;
private View videoBox;
private View closeButton;
private View root;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
root = inflater.inflate(R.layout.video_fragment, container, false);
videoBox = root.findViewById(R.id.video_box);
closeButton = root.findViewById(R.id.close_button);
videoBox.setVisibility(View.INVISIBLE);
return root;
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
listFragment = (VideoListFragment) getActivity().getFragmentManager().findFragmentById(R.id.list_fragment);
videoFragment = (YoutubeFragment) getActivity().getFragmentManager().findFragmentById(R.id.video_fragment_container);
checkYouTubeApi();
}
private void checkYouTubeApi() {
YouTubeInitializationResult errorReason =
YouTubeApiServiceUtil.isYouTubeApiServiceAvailable(getActivity());
if (errorReason.isUserRecoverableError()) {
errorReason.getErrorDialog(getActivity(), RECOVERY_DIALOG_REQUEST).show();
} else if (errorReason != YouTubeInitializationResult.SUCCESS) {
String errorMessage = getResources().getString(R.string.an_error_occurred);
Toast.makeText(getActivity(), errorMessage, Toast.LENGTH_LONG).show();
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == RECOVERY_DIALOG_REQUEST) {
// Recreate the activity if user performed a recovery action
getActivity().recreate();
}
}
public void onClickClose(#SuppressWarnings("unused") View view) {
listFragment.getListView().clearChoices();
listFragment.getListView().requestLayout();
videoFragment.pause();
ViewPropertyAnimator animator = videoBox.animate()
.translationYBy(videoBox.getHeight())
.setDuration(ANIMATION_DURATION_MILLIS);
runOnAnimationEnd(animator, new Runnable() {
#Override
public void run() {
videoBox.setVisibility(View.INVISIBLE);
}
});
}
#TargetApi(16)
private void runOnAnimationEnd(ViewPropertyAnimator animator, final Runnable runnable) {
if (Build.VERSION.SDK_INT >= 16) {
animator.withEndAction(runnable);
} else {
animator.setListener(new AnimatorListenerAdapter() {
#Override
public void onAnimationEnd(Animator animation) {
runnable.run();
}
});
}
}
/**
* A fragment that shows a static list of videos.
*/
public static final class VideoListFragment extends ListFragment {
private static final List<VideoEntry> VIDEO_LIST;
static {
List<VideoEntry> list = new ArrayList<VideoEntry>();
list.add(new VideoEntry("YouTube Collection", "Y_UmWdcTrrc"));
list.add(new VideoEntry("GMail Tap", "1KhZKNZO8mQ"));
list.add(new VideoEntry("Chrome Multitask", "UiLSiqyDf4Y"));
list.add(new VideoEntry("Google Fiber", "re0VRK6ouwI"));
list.add(new VideoEntry("Autocompleter", "blB_X38YSxQ"));
list.add(new VideoEntry("GMail Motion", "Bu927_ul_X0"));
list.add(new VideoEntry("Translate for Animals", "3I24bSteJpw"));
VIDEO_LIST = Collections.unmodifiableList(list);
}
private PageAdapter adapter;
private View videoBox;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
adapter = new PageAdapter(getActivity(), VIDEO_LIST);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
videoBox = getView().findViewById(R.id.video_box);
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
setListAdapter(adapter);
}
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
String videoId = VIDEO_LIST.get(position).videoId;
YoutubeFragment videoFragment = (YoutubeFragment) getFragmentManager().findFragmentById(R.id.video_fragment_container);
videoFragment.setVideoId(videoId);
// The videoBox is INVISIBLE if no video was previously selected, so we need to show it now.
if (videoBox.getVisibility() != View.VISIBLE) {
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
// Initially translate off the screen so that it can be animated in from below.
videoBox.setTranslationY(videoBox.getHeight());
}
videoBox.setVisibility(View.VISIBLE);
}
// If the fragment is off the screen, we animate it in.
if (videoBox.getTranslationY() > 0) {
videoBox.animate().translationY(0).setDuration(ANIMATION_DURATION_MILLIS);
}
}
#Override
public void onDestroyView() {
super.onDestroyView();
adapter.releaseLoaders();
}
public void setLabelVisibility(boolean visible) {
adapter.setLabelVisibility(visible);
}
}
/**
* Adapter for the video list. Manages a set of YouTubeThumbnailViews, including initializing each
* of them only once and keeping track of the loader of each one. When the ListFragment gets
* destroyed it releases all the loaders.
*/
private static final class PageAdapter extends BaseAdapter {
private final List<VideoEntry> entries;
private final List<View> entryViews;
private final Map<YouTubeThumbnailView, YouTubeThumbnailLoader> thumbnailViewToLoaderMap;
private final LayoutInflater inflater;
private final ThumbnailListener thumbnailListener;
private boolean labelsVisible;
public PageAdapter(Context context, List<VideoEntry> entries) {
this.entries = entries;
entryViews = new ArrayList<View>();
thumbnailViewToLoaderMap = new HashMap<YouTubeThumbnailView, YouTubeThumbnailLoader>();
inflater = LayoutInflater.from(context);
thumbnailListener = new ThumbnailListener();
labelsVisible = true;
}
public void releaseLoaders() {
for (YouTubeThumbnailLoader loader : thumbnailViewToLoaderMap.values()) {
loader.release();
}
}
public void setLabelVisibility(boolean visible) {
labelsVisible = visible;
for (View view : entryViews) {
view.findViewById(R.id.text).setVisibility(visible ? View.VISIBLE : View.GONE);
}
}
#Override
public int getCount() {
return entries.size();
}
#Override
public VideoEntry getItem(int position) {
return entries.get(position);
}
#Override
public long getItemId(int position) {
return 0;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = convertView;
VideoEntry entry = entries.get(position);
// There are three cases here
if (view == null) {
// 1) The view has not yet been created - we need to initialize the YouTubeThumbnailView.
view = inflater.inflate(R.layout.video_list_item, parent, false);
YouTubeThumbnailView thumbnail = (YouTubeThumbnailView) view.findViewById(R.id.thumbnail);
thumbnail.setTag(entry.videoId);
thumbnail.initialize(DeveloperKey.YOUTUBE_API_DEVELOPER_KEY, thumbnailListener);
} else {
YouTubeThumbnailView thumbnail = (YouTubeThumbnailView) view.findViewById(R.id.thumbnail);
YouTubeThumbnailLoader loader = thumbnailViewToLoaderMap.get(thumbnail);
if (loader == null) {
// 2) The view is already created, and is currently being initialized. We store the
// current videoId in the tag.
thumbnail.setTag(entry.videoId);
} else {
// 3) The view is already created and already initialized. Simply set the right videoId
// on the loader.
//thumbnail.setImageResource(R.drawable.loading_thumbnail);
loader.setVideo(entry.videoId);
}
}
TextView label = ((TextView) view.findViewById(R.id.text));
label.setText(entry.text);
label.setVisibility(labelsVisible ? View.VISIBLE : View.GONE);
return view;
}
private final class ThumbnailListener implements
YouTubeThumbnailView.OnInitializedListener,
YouTubeThumbnailLoader.OnThumbnailLoadedListener {
#Override
public void onInitializationSuccess(
YouTubeThumbnailView view, YouTubeThumbnailLoader loader) {
loader.setOnThumbnailLoadedListener(this);
thumbnailViewToLoaderMap.put(view, loader);
view.setImageResource(R.drawable.loading_thumbnail);
String videoId = (String) view.getTag();
loader.setVideo(videoId);
}
#Override
public void onInitializationFailure(
YouTubeThumbnailView view, YouTubeInitializationResult loader) {
view.setImageResource(R.drawable.no_thumbnail);
}
#Override
public void onThumbnailLoaded(YouTubeThumbnailView view, String videoId) {
}
#Override
public void onThumbnailError(YouTubeThumbnailView view, ErrorReason errorReason) {
view.setImageResource(R.drawable.no_thumbnail);
}
}
}
public static final class YoutubeFragment extends YouTubePlayerFragment
implements OnInitializedListener {
private YouTubePlayer player;
private String videoId;
public static YoutubeFragment newInstance() {
return new YoutubeFragment();
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
initialize(DeveloperKey.YOUTUBE_API_DEVELOPER_KEY, this);
}
#Override
public void onDestroy() {
if (player != null) {
player.release();
}
super.onDestroy();
}
public void setVideoId(String videoId) {
if (videoId != null && !videoId.equals(this.videoId)) {
this.videoId = videoId;
if (player != null) {
player.cueVideo(videoId);
}
}
}
public void pause() {
if (player != null) {
player.pause();
}
}
#Override
public void onInitializationSuccess(Provider provider, YouTubePlayer player, boolean restored) {
this.player = player;
}
#Override
public void onInitializationFailure(Provider provider, YouTubeInitializationResult result) {
this.player = null;
}
}
private static final class VideoEntry {
private final String text;
private final String videoId;
public VideoEntry(String text, String videoId) {
this.text = text;
this.videoId = videoId;
}
}
}
modified xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
<fragment
class="com.gardify.android.ui.video.VideoFragment$VideoListFragment"
android:id="#+id/list_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
<LinearLayout
android:id="#+id/video_box"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:orientation="vertical">
<ImageButton
android:id="#+id/close_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:src="#android:drawable/btn_dialog"
android:onClick="onClickClose"/>
<fragment
class="com.gardify.android.ui.video.VideoFragment$YoutubeFragment"
android:id="#+id/video_fragment_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
I am trying to pass a String "mMeetingKey" from View.class to PostListFragment.class, but the bundle is returning null. I checked the bundle in View.class, it is not null. When I check the bundle in PostListFragment.class, it keep returning null.
The code is mainly from "Firebase Quickstart for Database".
Thank you for your help.
View.class
public class View extends BaseActivity {
private FragmentPagerAdapter mPagerAdapter;
private ViewPager mViewPager;
private String mMeetingKey;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_posts);
mViewPager = findViewById(R.id.container);
mMeetingKey=getIntent().getStringExtra("meetingKey");
Bundle bundle = new Bundle();
bundle.putString("mMeetingKey", mMeetingKey);
PostListFragment postListFragment=new PostListFragment();
postListFragment.setArguments(bundle);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.container,postListFragment).commit();
mPagerAdapter = new FragmentPagerAdapter(getSupportFragmentManager()) {
private final Fragment[] mFragments = new Fragment[] {
new PostListFragment(),
// new MyPostsFragment(),
// new CompletedPostFragment(),
};
private final String[] mFragmentNames = new String[] {
getString(R.string.heading_recent),
//getString(R.string.heading_my_posts),
//getString(R.string.heading_completed_posts)
};
#Override
public Fragment getItem(int position) {
return mFragments[position];
}
#Override
public int getCount() {
return mFragments.length;
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentNames[position];
}
};
mViewPager.setAdapter(mPagerAdapter);
TabLayout tabLayout = findViewById(R.id.tabs);
tabLayout.setupWithViewPager(mViewPager);
Toast.makeText(this,mMeetingKey,Toast.LENGTH_LONG).show();
// Button launches NewPostActivity
findViewById(R.id.fab_new_post).setOnClickListener(new android.view.View.OnClickListener() {
#Override
public void onClick(android.view.View v) {
Intent intent = new Intent(View.this, NewPostActivity.class);
intent.putExtra("mMeetingKey",mMeetingKey);
startActivity(intent);
}
});
}
}
PostListFragment.class
public class PostListFragment extends android.support.v4.app.Fragment {
private static final String TAG = "PostListFragment";
// [START define_database_reference]
private DatabaseReference mDatabase;
// [END define_database_reference]
private String mMeetingKey;
private FirebaseRecyclerAdapter<Post, PostViewHolder> mAdapter;
private RecyclerView mRecycler;
private String meetingKeyRef;
private LinearLayoutManager mManager;
public PostListFragment() {}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView (LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View rootView = inflater.inflate(R.layout.fragment_all_post, container, false);
Bundle bundle = this.getArguments();
if (bundle != null) {
meetingKeyRef = bundle.getString("mMeetingKey").toString();
}
if (bundle!= null) {
meetingKeyRef = this.getArguments().getString("mMeetingKey");
}
if (bundle == null) {
throw new IllegalArgumentException("Bundle is null");
}
// [START create_database_reference]
mDatabase = FirebaseDatabase.getInstance().getReference().child(meetingKeyRef);
// [END create_database_reference]
mRecycler = rootView.findViewById(R.id.messages_list);
mRecycler.setHasFixedSize(true);
return rootView;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
// Set up Layout Manager, reverse layout
mManager = new LinearLayoutManager(getActivity());
mManager.setReverseLayout(true);
mManager.setStackFromEnd(true);
mRecycler.setLayoutManager(mManager);
// Set up FirebaseRecyclerAdapter with the Query
Query postsQuery = getQuery(mDatabase);
mAdapter = new FirebaseRecyclerAdapter<Post, PostViewHolder>(Post.class, R.layout.item_post,
PostViewHolder.class, postsQuery) {
#Override
protected void populateViewHolder(final PostViewHolder viewHolder, final Post model, final int position) {
final DatabaseReference postRef = getRef(position);
mMeetingKey= postRef.getKey();
// Set click listener for the whole post view
final String postKey = postRef.child(mMeetingKey).getKey();
viewHolder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// Launch PostDetailActivity
Intent intent = new Intent(getActivity(), PostDetailActivity.class);
intent.putExtra(PostDetailActivity.EXTRA_POST_KEY, postKey);
intent.putExtra(PostDetailActivity.EXTRA_MEETING_KEY,mMeetingKey);
startActivity(intent);
}
});
// Determine if the current user has liked this post and set UI accordingly
if (model.boxCount==1) {
viewHolder.boxView.setImageResource(R.drawable.ic_toggle_check_box_checked);
} else {
viewHolder.boxView.setImageResource(R.drawable.ic_toggle_check_box_outline);
}
// Bind Post to ViewHolder, setting OnClickListener for the star button
viewHolder.bindToPost(model, new View.OnClickListener() {
#Override
public void onClick(View boxView) {
// Need to write to both places the post is stored
DatabaseReference globalPostRef = mDatabase.child("posts").child(postRef.getKey());
DatabaseReference userPostRef = mDatabase.child("user-posts").child(model.uid).child(postRef.getKey());
// Run two transactions
onBoxClicked(globalPostRef);
onBoxClicked(userPostRef);
}
});
}
};
mRecycler.setAdapter(mAdapter);
}
// [START post_stars_transaction]
private void onBoxClicked(DatabaseReference postRef) {
postRef.runTransaction(new Transaction.Handler() {
#Override
public Transaction.Result doTransaction(MutableData mutableData) {
Post p = mutableData.getValue(Post.class);
if (p == null) {
return Transaction.success(mutableData);
}
if (p.checkbox.containsKey(getUid())) {
// Unstar the post and remove self from stars
p.boxCount = 0;
p.checkbox.remove(getUid());
} else {
// Star the post and add self to stars
p.boxCount = 1;
p.checkbox.put(getUid(), true);
}
// Set value and report transaction success
mutableData.setValue(p);
return Transaction.success(mutableData);
}
#Override
public void onComplete(DatabaseError databaseError, boolean b,
DataSnapshot dataSnapshot) {
// Transaction completed
Log.d(TAG, "postTransaction:onComplete:" + databaseError);
}
});
}
// [END post_stars_transaction]
#Override
public void onDestroy() {
super.onDestroy();
if (mAdapter != null) {
mAdapter.cleanup();
}
}
public String getUid() {
return FirebaseAuth.getInstance().getCurrentUser().getUid();
}
public Query getQuery(DatabaseReference databaseReference){
Query recentPostsQuery = databaseReference.child("posts")
.limitToFirst(100);
// [END recent_posts_query]
return recentPostsQuery;
}
}
activity_view_posts.xml
<?xml version="1.0" encoding="utf-8"?>
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.design.widget.TabLayout
android:id="#+id/tabs"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<android.support.v4.view.ViewPager
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#id/tabs"/>
<android.support.design.widget.FloatingActionButton
android:id="#+id/fab_new_post"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_margin="16dp"
android:src="#drawable/ic_create"
app:backgroundTint="#android:color/holo_orange_dark" />
fragment_all_post.xml
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".checklist.View">
<android.support.v7.widget.RecyclerView
android:id="#+id/messages_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_alignParentTop="true"
android:clipToPadding="false"
android:padding="5dp"
android:scrollbars="vertical"
tools:listitem="#layout/item_post" />
You are using ViewPager then why you are replacing container with your fragment. Remove that code and use below code for View
public class View extends BaseActivity {
private FragmentPagerAdapter mPagerAdapter;
private ViewPager mViewPager;
private String mMeetingKey;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_view_posts);
mViewPager = findViewById(R.id.container);
mMeetingKey=getIntent().getStringExtra("meetingKey");
Bundle bundle = new Bundle();
bundle.putString("mMeetingKey", mMeetingKey);
PostListFragment postListFragment=new PostListFragment();
postListFragment.setArguments(bundle);
mPagerAdapter = new FragmentPagerAdapter(getSupportFragmentManager()) {
private final Fragment[] mFragments = new Fragment[] {
postListFragment ,
// new MyPostsFragment(),
// new CompletedPostFragment(),
};
private final String[] mFragmentNames = new String[] {
getString(R.string.heading_recent),
//getString(R.string.heading_my_posts),
//getString(R.string.heading_completed_posts)
};
#Override
public Fragment getItem(int position) {
return mFragments[position];
}
#Override
public int getCount() {
return mFragments.length;
}
#Override
public CharSequence getPageTitle(int position) {
return mFragmentNames[position];
}
};
mViewPager.setAdapter(mPagerAdapter);
TabLayout tabLayout = findViewById(R.id.tabs);
tabLayout.setupWithViewPager(mViewPager);
Toast.makeText(this,mMeetingKey,Toast.LENGTH_LONG).show();
// Button launches NewPostActivity
findViewById(R.id.fab_new_post).setOnClickListener(new android.view.View.OnClickListener() {
#Override
public void onClick(android.view.View v) {
Intent intent = new Intent(View.this, NewPostActivity.class);
intent.putExtra("mMeetingKey",mMeetingKey);
startActivity(intent);
}
});
}
}
I have a fragment with a list of recipes. But I can't get the onItemClick to work...
I have tried it with onListItemClick but that didn't seem to work either.
My Fragment
public class RecipeBookListViewFragment extends ListFragment implements AdapterView.OnItemClickListener {
private List<Recipe> recipes;
private DataPassListener mCallback;
private ListView recipeList;
public interface DataPassListener{
public void passData(Recipe recipe);
}
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
RecipeBookActivity.CONTEXT = getActivity().getApplicationContext();
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_recipeitem_list, container, false);
return view;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
fillRecipeBook();
getListView().setOnItemClickListener(this);
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position,long id) {
Recipe recipe = (Recipe) getListAdapter().getItem(position);
final ProgressDialog dialog = ProgressDialog.show(getActivity(), "", "halloooooo...");
mCallback.passData(recipe);
}
#Override
public void onViewCreated(View v, Bundle savedInstanceState){
super.onViewCreated(v,savedInstanceState);
recipeList = getListView();
recipeList.setClickable(true);
}
#Override
public void onAttach(Activity activity){
super.onAttach(activity);
try {
mCallback = (DataPassListener)activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement DataPassListener");
}
}
private void fillRecipeBook(){
final ProgressDialog dialog = ProgressDialog.show(getActivity(), "", "loading...");
RestClient.ApiInterface service = RestClient.getClient();
Call<List<Recipe>> call = service.recipes();
call.enqueue(new Callback<List<Recipe>>() {
#Override
public void onResponse(Response<List<Recipe>> response, Retrofit retrofit) {
dialog.dismiss();
Log.d("MainActivity", "Status Code = " + response.code());
if (response.isSuccess()) {
// request successful (status code 200, 201)
recipes = response.body();
ArrayAdapter<String> adapter = new RecipeListAdapter(getActivity(), recipes);
setListAdapter(adapter);
} else {
// response received but request not successful (like 400,401,403 etc)
//Handle errors
}
}
#Override
public void onFailure(Throwable t) {
Log.d("MainActivity", "GOE KAPOT " + t.getMessage());
dialog.dismiss();
}
});
}
}
my ListView.xml
<?xml version="1.0" encoding="utf-8"?>
<ListView android:id="#android:id/list" android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="#FFCC00"
android:dividerHeight="2dp"/>
<TextView android:id="#+id/recipe_title" android:layout_width="match_parent"
android:layout_height="match_parent" android:gravity="left"
android:textAppearance="?android:attr/textAppearanceLarge"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"/>
My custom adapter
public class RecipeListAdapter extends ArrayAdapter{
private Context context;
private boolean useList = true;
private List<Recipe> recipes;
public RecipeListAdapter(Context context, List<Recipe> recipes) {
super(context,-1, recipes);
this.context = context;
this.recipes = recipes;
}
private class ViewHolder{
TextView titleText;
}
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder holder;
Recipe recipe = (Recipe)getItem(position);
View viewToUse;
LayoutInflater mInflater = (LayoutInflater) context
.getSystemService(Activity.LAYOUT_INFLATER_SERVICE);
if (convertView == null) {
if(useList){
viewToUse = mInflater.inflate(R.layout.fragment_recipeitem_list, null);
} else {
viewToUse = mInflater.inflate(R.layout.fragment_recipeitem_grid, null);
}
holder = new ViewHolder();
holder.titleText = (TextView)viewToUse.findViewById(R.id.recipe_title);
viewToUse.setTag(holder);
} else {
viewToUse = convertView;
holder = (ViewHolder) viewToUse.getTag();
}
holder.titleText.setText(recipe.getTitle());
return viewToUse;
}
}
my main activity:
public class RecipeBookActivity extends Activity implements DataPassListener {
public static Context CONTEXT;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_recipe);
if(findViewById(R.id.recipe_list_fragment) != null){
if (savedInstanceState != null)
return;
RecipeBookListViewFragment recipeBookListViewFragmentFragment = new RecipeBookListViewFragment();
recipeBookListViewFragmentFragment.setArguments(getIntent().getExtras());
getFragmentManager().beginTransaction().add(R.id.recipe_list_fragment,
recipeBookListViewFragmentFragment).commit();
}
}
#Override
public void passData(Recipe recipe){
RecipeFragment recipeFragment = new RecipeFragment();
Bundle args = new Bundle();
args.putSerializable(recipeFragment.DATA_RECEIVE, recipe);
recipeFragment.setArguments(args);
getFragmentManager().beginTransaction()
.replace(R.id.recipe_list_fragment, recipeFragment)
.commit();
}
}
You need to set the onItemClickListener to the ListView before it can register any clicks. Change your onViewCreated code to:
#Override
public void onViewCreated(View v, Bundle savedInstanceState){
super.onViewCreated(v,savedInstanceState);
recipeList = getListView();
recipeList.setOnItemClickListener(this);
}
That way any item clicks on the ListView will be handled in the onItemClick() method that is overidden in the Fragment.
I have implemented an abstract class that has a List View like so:
public abstract class ExampleListFragment extends ExampleFragment{
protected ListView _listView;
public ExampleListFragment () {
super();
}
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//Set Up the Bottom Bar
View view = super.onCreateView(inflater, container, savedInstanceState);
addList();
return view;
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
}
public void addList() {
_listView = new ListView(getActivity());
RelativeLayout.LayoutParams parms = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
parms.addRule(RelativeLayout.CENTER_HORIZONTAL);
parms.addRule(RelativeLayout.BELOW, R.id.tableLayout);
_listView.setLayoutParams(parms);
_listView.setClickable(true);
_listView.setFocusable(true);
_listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
#Override
public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l) {
longListClick(i);
return true;
}
});
_listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
listClick(i);
}
});
_layout.addView(_listView);
}
public abstract void longListClick(int pos);
public abstract void listClick(int pos);
}
I then have a class that inherits from this to implement the abstract methods which should be called when clicking an item in the list
public class TwitterFragment extends ExampleListFragment {
private TwitterAdapter _adapter;
//...
#Override
public void onSelected() {
_adapter = new TwitterAdapter(getActivity());
populateAdapter();
}
private void populateAdapter() {
showLoadingTweets();
new TwitterGetTimelineTask().execute(username); //fills adapter with Twitter status info...
}
#Override
public void longListClick(int pos) {
Toast toast = Toast.makeText(getActivity(),String.format("You have clicked item number: %d",pos),
Toast.LENGTH_SHORT);
toast.show();
}
#Override
public void listClick(int pos) {
Toast toast = Toast.makeText(getActivity(),String.format("You have clicked item number: %d",pos),
Toast.LENGTH_SHORT);
toast.show();
}
//...
class TwitterGetTimelineTask extends AsyncTask<String, String, String> {
//...
}
}
However, whenever I click on an Item, it does not appear to even enter onItemClick functions.
Any ideas? help much appreciated.
*EDIT*
As requested, here is the code for my Adapter
public class TwitterAdapter extends BaseAdapter {
private ArrayList<StatusDetails> _statusDetailsArrayList;
private LayoutInflater _inflater;
public TwitterAdapter(Context context) {
_statusDetailsArrayList = new ArrayList<StatusDetails>();
_inflater = LayoutInflater.from(context);
}
#Override
public int getCount() {
return _statusDetailsArrayList.size();
}
#Override
public Object getItem(int i) {
return _statusDetailsArrayList.get(i);
}
#Override
public long getItemId(int i) {
return _statusDetailsArrayList.get(i).get_id();
}
#Override
public View getView(int i, View view, ViewGroup viewGroup) {
ViewHolder holder;
if (view == null) {
view = _inflater.inflate(R.layout.twitter_layout, null);
holder = new ViewHolder();
holder.img_icon = (ImageView) view.findViewById(R.id.statusImage);
holder.text_line1 = (TextView) view.findViewById(R.id.statusText);
holder.text_line2 = (TextView) view.findViewById(R.id.statusDateText);
view.setTag(holder);
} else {
holder = (ViewHolder) view.getTag();
}
Bitmap bmp = _statusDetailsArrayList.get(i).get_profile();
if (bmp == null) {
holder.img_icon.setImageResource(R.drawable.ic_action_twitter);
} else {
holder.img_icon.setImageBitmap(bmp);
}
holder.text_line1.setText(_statusDetailsArrayList.get(i).get_text());
holder.text_line2.setText(_statusDetailsArrayList.get(i).get_date());
return view;
}
public void addStatus(StatusDetails details) {
_statusDetailsArrayList.add(details);
}
public void setStatuses(ArrayList<StatusDetails> details) {
_statusDetailsArrayList = details;
}
public ArrayList<StatusDetails> getEvents() {
return _statusDetailsArrayList;
}
public void removeAll() {
_statusDetailsArrayList.clear();
}
private class ViewHolder {
ImageView img_icon;
TextView text_line1;
TextView text_line2;
}
}
And if needed, the XML of the layout of each list
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/statusImage"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:text="Status"
android:id="#+id/statusText"
android:layout_alignParentTop="true"
android:autoLink="web"
android:textColor="#android:color/white"
android:layout_toRightOf="#+id/statusImage" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceSmall"
android:layout_below="#id/statusText"
android:text="Date"
android:id="#+id/statusDateText"
android:layout_alignBottom="#+id/statusImage"
android:layout_toRightOf="#+id/statusImage" />
Thanks.