How to start activity from RecyclerView adapter in fragment [duplicate] - android

This question already has answers here:
Get application context from non activity singleton class
(3 answers)
Closed 4 years ago.
I can't click RecyclerView to a new Activity from RecyclerViewAdapter.
I call ItemClick here.
DayAdapter.java:
holder.setItemClickListener(new ItemClickListener() {
#Override
public void onClick(View view, int position, boolean isLongClick) {
openProgramActivity(view, position);
}
});
}
This function opens a new Activity:
public void openProgramActivity(View view, int position) {
//Intent openProgramActivity = new Intent(context, ProgramActivity.class);
Intent openProgramActivity = new Intent(view.getContext(), ProgramActivity.class);
openProgramActivity.putExtra("index",position);
view.getContext().startActivity(openProgramActivity);
}
FragmentDay30.java:
public class FragmentDay30 extends Fragment {
private View view;
public static FragmentDay30 newInstance() {
FragmentDay30 fragment = new FragmentDay30();
Bundle args = new Bundle();
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_30day, container,false);
ViewPager slideViewPager = (ViewPager) view.findViewById(R.id.slideViewPager);
SlideAdapter slideAdapter = new SlideAdapter(getActivity());
slideViewPager.setAdapter(slideAdapter);
RecyclerView fragment30datRecyclerView = (RecyclerView) view.findViewById(R.id.fragment30dayRecyclerView);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity(),LinearLayoutManager.VERTICAL,false);
fragment30datRecyclerView.setLayoutManager(linearLayoutManager);
DayAdapter dayAdapter = new DayAdapter(getActivity());
fragment30datRecyclerView.setAdapter(dayAdapter);
return view;
}
I try to use getActvity() and getContext() but not to new Activity.

Pass contaxt to recyclerview adapter constructor like this
Context context;
MyAdapter(Context context, .....){
this.context=context;
}
Call Activity
context.startActivity(......);

Though you can start Activity from Adapter class passing a Context but as Documented it's
not a Good design pattern
and also a Bad practice to follow.
I would rather suggest to have an interface defined in your Adapter class which would be implemented by the Fragment class. Fragment class initializes the Adapter passing it's reference which you would typeCast to interface like this
DayAdpater.class
public class DayAdapter extends RecyclerView.Adapter<DayAdapter.ViewHolder> {
private OnActionListener mListener;
DayAdapter(OnActionListener listener){
this.mListener=listener;
}
holder.setItemClickListener(new ItemClickListener() {
#Override
public void onClick(View view, int position, boolean isLongClick) {
mListener.startActivity(position);
}
});
interface OnActionListener{
public void startActivity(int position);
}
}
FragmentDay30.class
public class FragmentDay30 extends Fragment implements DayAdapter.OnActionListener{
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
view = inflater.inflate(R.layout.fragment_30day, container,false);
RecyclerView fragment30datRecyclerView = (RecyclerView) view.findViewById(R.id.fragment30dayRecyclerView);
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(getActivity(),LinearLayoutManager.VERTICAL,false);
fragment30datRecyclerView.setLayoutManager(linearLayoutManager);
DayAdapter dayAdapter = new DayAdapter(getActivity(), this);
fragment30datRecyclerView.setAdapter(dayAdapter);
return view;
}
/**
* this is the place where you should start a new activity
*/
public void startActivity(int position) {
//Intent openProgramActivity = new Intent(context, ProgramActivity.class);
Intent openProgramActivity = new Intent(getActivity(), ProgramActivity.class);
openProgramActivity.putExtra("index",position);
getActivity.startActivity(openProgramActivity);
}
}
This is how the your adpater class interacts with the fragment class.
Hope this helps.

Pass context in RecyclerView adapter constructor which you are using for setAdapter like this:
Context context;
MyCustomAdapter(Context context, .....){
this.context=context;
}
For call Activity used:
context.startActivity(......);

Related

how to call main activity code in a recycler view that is inside a fragment?

i have already got all things ready set-up my fragment communication, but my only problem is how can i make the recycler view itemVitem.setOnClickListener call the overridden interface method in the main activity so i can get that data and create an intent with to go to detail activity or update detail fragment for dual-pane layout, more explanation is provided with comments on code below.
MainActivity
public class MainActivity extends AppCompatActivity implements ListFragment.Listener {
// the method to be called when an item in recycler view is clicked
// so i can pass this data to DetailFragment
#Override
public void listener(String firstName, String lastName) {
DetailFragment detailFragment = new DetailFragment();
detailFragment.updateText(firstName, lastName);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
RecyclerViewAdapter
public class ViewHolder extends RecyclerView.ViewHolder {
public TextView tvFirstName;
public TextView tvLastName;
public ViewHolder(#NonNull View itemView) {
super(itemView);
tvFirstName = itemView.findViewById(R.id.row_first_name);
tvLastName = itemView.findViewById(R.id.row_last_name);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// how to call the "listener()" method in main activity
}
});
}
the fragment containing the recycler view
public class ListFragment extends Fragment {
private static final String TAG = "ListFragment";
private RecyclerView recyclerView;
private RecyclerViewAdapter recyclerViewAdapter;
// fragment communication interface
public interface Listener {
void listener(String firstName, String lastName);
}
private Listener listener;
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
try {
this.listener = (Listener) context;
} catch (ClassCastException e) {
Log.d(TAG, "onAttach: "+ e.getMessage());
}
}
public ListFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_list, container, false);
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
recyclerView = getView().findViewById(R.id.recyclerview);
recyclerView.setLayoutManager(new LinearLayoutManager(getActivity()));
// some dummy data to fill the recycler view
ArrayList<User> users = new ArrayList<>();
users.add(new User("hiwa", "jalal"));
users.add(new User("mohammed", "abdullah"));
recyclerViewAdapter = new RecyclerViewAdapter(users, getActivity());
recyclerView.setAdapter(recyclerViewAdapter);
}
}
DetailFragment
public class DetailFragment extends Fragment {
private TextView tvFirstName;
private TextView tvLastName;
public DetailFragment() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
return inflater.inflate(R.layout.fragment_detail, container, false);
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
tvFirstName = view.findViewById(R.id.detail_frag_first_name);
tvLastName = view.findViewById(R.id.detail_frag_last_name);
}
// update the details fragment views
public void updateText(String firstName, String lastName) {
tvFirstName.setText(firstName);
tvLastName.setText(lastName);
}
}
Pass listener to your RecyclerViewAdapter and use this to call the callback
recyclerViewAdapter = new RecyclerViewAdapter(users, getActivity(), listener);
Update RecyclerViewAdapter like below
class RecyclerViewAdapter {
private Listener mListener;
....
public RecyclerViewAdapter(ArrayList<User> users, Context context, Listener listener) {
....
mListener = listener;
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
....
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mListener.listener(first_name. last_name);
}
});
....
}
....
}
Create Method in adapter class.
private Listener mListener;
public void setListener(Listener listener){
mListener = listener
}
public void removeListener(){
mListener = null;
}
Inside Fragment class, set listener like below.
recyclerViewAdapter = new RecyclerViewAdapter(users, getActivity());
recyclerViewAdapter.setListener(listener);
In ViewHolder
holder.itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mListener.listener(first_name. last_name);
}
});
Also in OnDestroy or OnDestroyView() of fragment, call
removeListener() to avoid memory leak.

Callback with two methods is not working between NonActivity class and a Fragment

I have created a callback via interface with two methods. The callback is between a NonActivity class and a Fragment. The problem is that only one interface method invisible is being called. And the other interface method visible is not called. I have copied the code of interface and both classes. MY OBJECTIVE IS THAT BOTH CALLBACK METHODS INVISIBLE() AND VISIBLE() SHOULD BE CALLED AT DIFFERENT TIMES WHEN TRIGGERED. I am somewhat confused about not getting the particular functionality.
public interface MyCustomListener {
void invisible();
void visible();
}
The NonActivity class code is as follows:
public class Operations {
private Context context;
private RecyclerView recyclerView;
private RecyclerView.Adapter adapter;
private MyCustomListener listener;
public void setMyCustomListener(MyCustomListener listener) {
this.listener = listener;
}
public Operations(Context context, RecyclerView recyclerView) {
this.context = context;
this.recyclerView = recyclerView;
}
public void getView(int number) {
Perform pa = new Perform(context);
Long count = pa.count(number);
if (count > 0) {
ArrayList arrayList = pa.getAllList(number);
adapter = new AdapterMovie(context, arrayList, recyclerView, number);
recyclerView.setAdapter(adapter);
if (listener != null)
listener.invisible();
}
else if (count < 1) {
recyclerView.setAdapter(null);
if (listener != null)
listener.visible();
}
}
}
The Fragment class code is as follows:
public class Frag extends Fragment {
private int fragmentNumber = 0;
private Operations fo;
private RecyclerView recyclerView;
private TextView message;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.frag, container, false);
fo = new Operations(getActivity(), recyclerView);
return view;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
fo.setMyCustomListener(new MyCustomListener() {
#Override
public void invisible() {
Toast.makeText(getActivity(), "invisible", Toast.LENGTH_SHORT).show();
}
#Override
public void visible() {
Toast.makeText(getActivity(), "visible", Toast.LENGTH_SHORT).show();
}
});
}
}
If you want get callback in fragment, you should implements your fragment from MyCustomListener. then you pass fragment to constructor of Operations.
fragment such as below:
public class Frag extends Fragment implements MysCustomListener{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.frag, container, false);
fo = new Operations(this, recyclerView);
return view;
}
#override
void invisible(){
}
#override
void visible(){
}
}

Passing data from recylerview adapter to fragments in navigation drawer

I want to pass data from recycleview Adapter to a fragment and then open the fragment. I tried things mentioned but its not working. Should I implement fragment to fragment or activity to fragment? Please provide a solution. How do I do it?
public class QuotationAdapter extends RecyclerView.Adapter<QuotationAdapter.ViewHolder>implements Filterable {
private Context context;
String id;
private List<ListQuotation> contactList;
private List<ListQuotation> contactListFiltered;
private QuotationAdapter.ContactsAdapterListener listener;
Fragment fragment = new Fragment();
#Override
public void onBindViewHolder(final QuotationAdapter.ViewHolder holder, int position) {
final ListQuotation contact = contactListFiltered.get(position);
holder.item_list_btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
context = v.getContext();
id = contact.getId();
passData(id);
}
});
}
private void passData(String id) {
Intent intent = new Intent(context,QuotationItemDetails.class);
intent.putExtra("id", ""+id);
context.startActivity(intent);
}
This is my fragment
public class ItemListFragment extends Fragment {
String id;
TableLayout tv;
private static final String url = "";
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
//returning our layout file
//change R.layout.yourlayoutfilename for each of your fragments
final View rootView = inflater.inflate(R.layout.fragment_item_list, container, false);
tv = (TableLayout)rootView.findViewById(R.id.tableexp);
loadItemData();
//get id
id = getArguments().getString("id");
return rootView;
}

RecyclerView with sqlite db working in activity but not working in fragments

I am the beginner in android
I have found many answers of a similar question but no answer unfortunately worked for me
I am using recylcerView using card view to show student data .I am taking Data from My sqlite db.
My code works fine in activity but because of navigation drawer i put it in a fragment and it is showing blank.
here is my activity and fragment code.
MainActivity
public class MainActivity extends AppCompatActivity {
private RecyclerView mRecyclerView;
private RecyclerView.LayoutManager mLayoutManager;
private PersonDBHelper dbHelper;
private MyCustomAdapter adapter;
private String filter = "";
TextView textView;
public static int navItemIndex = 0;
Toolbar toolbar;
private DrawerLayout mDrawerLayout;
FloatingActionButton button;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.person_list);
/* toolbar=findViewById(R.id.toolbar);
setSupportActionBar(toolbar);*/
mDrawerLayout=findViewById(R.id.drawer_layout);
NavigationView navigationView=findViewById(R.id.nav_view);
mRecyclerView = (RecyclerView)findViewById(R.id.recycler_view);
textView=findViewById(R.id.empty_view);
mLayoutManager = new LinearLayoutManager(this);
mRecyclerView.setLayoutManager(mLayoutManager);
//populate recyclerview
populaterecyclerView(filter);
button=findViewById(R.id.fab_add);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
goToAddUserActivity();
}
});
}
private void populaterecyclerView(String filter) {
dbHelper = new PersonDBHelper(this);
adapter = new MyCustomAdapter(dbHelper.peopleList(filter), this, mRecyclerView);
mRecyclerView.setAdapter(adapter);
}
private void goToAddUserActivity(){
Intent intent = new Intent(MainActivity.this, AddRecordActivity.class);
startActivity(intent);
}
#Override
protected void onResume() {
super.onResume();
adapter.notifyDataSetChanged();
}
this is working fine but for the fragment i did following changes
StudentListFragment()
ublic class StudentListFragment extends Fragment {
private RecyclerView mRecyclerView;
private RecyclerView.LayoutManager mLayoutManager;
private PersonDBHelper dbHelper;
private MyCustomAdapter adapter;
FloatingActionButton button;
private String filter = "";
View rootView;
#RequiresApi(api = Build.VERSION_CODES.M)
public static StudentListFragment newInstance(){
StudentListFragment studentListFragment = new StudentListFragment();
Bundle args=new Bundle();
studentListFragment.setArguments(args);
return studentListFragment;
}
#Override
public void onCreate(#Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
rootView=inflater.inflate(R.layout.person_list,container,false);
mRecyclerView=rootView.findViewById(R.id.recycler_view);
dbHelper = new PersonDBHelper(getContext());
adapter = new MyCustomAdapter(dbHelper.peopleList(filter), getContext(), mRecyclerView);
mLayoutManager = new LinearLayoutManager(getActivity());
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setAdapter(adapter);
adapter.notifyDataSetChanged();
button=rootView.findViewById(R.id.fab_add);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
goToAddUserActivity();
}
});
return rootView;
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setRetainInstance(false);
ensureList();
}
private void goToAddUserActivity() {
Intent intent = new Intent(getActivity(), AddRecordActivity.class);
startActivity(intent);
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getActivity().setTitle("StudentList");
}
public void ensureList(){
if (dbHelper != null) {
return;
}
View root = getView();
if (root == null) {
throw new IllegalStateException("Content view not yet created");
} }
}
i am calling this fragment in navigation drawer code is working but not displaying any data. If i put this fragment first in navigation drawer menu means when navigation drawer activity starts this fragment will get open.In such case it is displaying my cards(my data) but if i switch to other fragment and return back to this fragment it is showing blank
In fragment, onCreateView() method, please inflate your root view and return it immediately, do not do anything else.
Implement your logic to onViewCreated(). something like this :
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, Bundle savedInstanceState) {
rootView=inflater.inflate(R.layout.person_list,container,false);
return rootView;
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
getActivity().setTitle("StudentList");
mRecyclerView=view.findViewById(R.id.recycler_view);
dbHelper = new PersonDBHelper(getContext());
adapter = new MyCustomAdapter(dbHelper.peopleList(filter), getContext(), mRecyclerView);
mLayoutManager = new LinearLayoutManager(getActivity());
mRecyclerView.setLayoutManager(mLayoutManager);
mRecyclerView.setAdapter(adapter);
adapter.notifyDataSetChanged();
button=view.findViewById(R.id.fab_add);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
goToAddUserActivity();
}
});
}
could you please try this. And make sure you have items in the list.

How can I reuse my fragment's code?

I'm writing an Android application with ViewPager. My ViewPager contains two Fragments. In each fragment are located two receclerViews to show different LiveData lists of items from Database (I'm using Room)
The code for BaseFragment
public class BaseFragment extends Fragment {
private RecyclerView recyclerView;
private NewsAdapter adapter;
public ViewModel mViewModel;
public BaseFragment() {
// Required empty public constructor
}
#Override
public void onCreate(#Nullable final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mViewModel = ViewModelProviders.of(this).get(ViewModel.class);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View mView = inflater.inflate(R.layout.fragment_feeds, container, false);
recyclerView = mView.findViewById(R.id.feeds_recycler_view);
return mView;
}
#Override
public void onActivityCreated(#Nullable final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setUpRecyclerView();
mViewModel.getAllNewsEntities()
.observe(this, allNewsEntities -> {
NewsEntityUtilCallback productDiffUtilCallback =
new NewsEntityUtilCallback(adapter.getNewsItems(), allNewsEntities);
DiffUtil.DiffResult newsEntitiesDiffResult = DiffUtil.calculateDiff(productDiffUtilCallback);
adapter.setNewsItems(allNewsEntities);
newsEntitiesDiffResult.dispatchUpdatesTo(adapter);
});
}
protected void setUpRecyclerView() {
LinearLayoutManager layoutManager = new LinearLayoutManager(getContext());
recyclerView.setLayoutManager(layoutManager);
ItemClickListener onClickListener = (v, position) -> {
String url = adapter.getNewsItems().get(position).getLink();
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
if (browserIntent.resolveActivity(getContext().getPackageManager()) != null) {
startActivity(browserIntent);
}
};
adapter = new NewsAdapter(getContext(), onClickListener);
recyclerView.setAdapter(adapter);
}
}
Look closely at this code section:
mViewModel.getAllNewsEntities()
.observe(this, allNewsEntities -> {
NewsEntityUtilCallback productDiffUtilCallback =
new NewsEntityUtilCallback(adapter.getNewsItems(), allNewsEntities);
DiffUtil.DiffResult newsEntitiesDiffResult = DiffUtil.calculateDiff(productDiffUtilCallback);
adapter.setNewsItems(allNewsEntities);
newsEntitiesDiffResult.dispatchUpdatesTo(adapter);
});
}
Here I'm going to observe different LiveData queries in each Fragment(in the second Fragment it's mViewModel.getAllBookmarkedNewsEntities()).The other things my code will be equals (the same lifecycles methods, the same RecyclerView). So could give me advice about the best possible design principle to refactor my code. I don't want simply to copy my code in another Fragment class just because of one line
Just extends the BaseFragment and override onActivityCreated method. Something like this:
public class ReuseBaseFragment extends BaseFragment {
#Override
public void onActivityCreated(#Nullable final Bundle savedInstanceState) {
//Your new code here
}
}

Categories

Resources