How to call a method two different classes have in common? - android

My question is a design question. I have two custom fragments CustomFrag1 and CustomFrag2. Both these fragments have a method swapCursor.
CustomFrag1:
public class CustomFrag1 extends Fragment {
#Override
public void onCreate(Bundle savedInstanceState) {
// .... code
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// .... code
MyAdapter mAdapter = new MyAdapter();
// .... code
}
public static void swapCursor(final Cursor cursor, Activity ctx){
// .... code
}
}
CustomFrag2:
public class CustomFrag1 extends Fragment {
#Override
public void onCreate(Bundle savedInstanceState) {
// .... code
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// .... code
MyAdapter mAdapter = new MyAdapter();
// .... code
}
public static void swapCursor(final Cursor cursor, Activity ctx){
// .... code
}
}
I don't want to make a seperate adapter class for each fragment. I do however, want to call swapCursor in the adapter class. If the adapter has been instantied from CustomeFrag1 I want swapCurosr to swap the cursor in CustomFrag1. If the adapter has been instantiated from CustomeFrag2 I want swapCurosr to swap the cursor in CustomFrag2.
Is it possible to pass in an instance of the Fragment...
MyAdapter mAdapter = new MyAdapter(this);
...and somehow represent that instance with a generic variable that has swapCursor defined as a method? If not, what strategy can I use? Interfaces? Generics? Something?
edit
I tried inheriting swapCursor but that would just swap out the cursor out on the parent and not the child.

swapCursor shouldn't be static at the first place, because there's no inheritance for static methods.
You could create an interface (SwappableCursor as a name hint) which has a method swapCursor, then all of your fragments can implement this interface. So that you'll have to implement swapCursor.
In MyAdapter's constructor you can add a parameter which has the type of your interface (SwappableCursor). You'll be able to invoke swapCursor method.

Use interfaces.
public interface SwapFrag {
public swapCursor(final Cursor cursor, Activity ctx);
}
your fragments need to implement SwapFrag:
public class CustomFrag1 extends Fragment implements SwapFrag
and also need to implements the swapCursor method.
#Override
public static void swapCursor(final Cursor cursor, Activity ctx) {
...
}

Related

Android - RecyclerView pass value into its own activity [duplicate]

My fragment:
public class FragmentSort extends Fragment {
#BindView(R.id.sortRecyclerView)
RecyclerView sortRecyclerView;
protected RecyclerView.Adapter adapter;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(layoutResId, container, false);
adapter = new StoreListItemAdapter(getActivity(), collection);
sortRecyclerView.setAdapter((RecyclerView.Adapter) adapter);
return rootView;
}
#Subscribe
public void onStoreClickEvent(Store store) {
Debug.d(TAG, "onStoreClickEvent: store = " + store);
handleFilterItemSelect(store.getAddress());
}
}
Here my custom adapter:
public class StoreListItemAdapter extends RecyclerView.Adapter {
private Context context;
private List<?> data = new ArrayList<>();
public DataBindingRecyclerViewAdapter(Context context, List<?> data) {
this.context = context;
this.data = data;
}
public void onClick(Store store) {
EventBus.getDefault().post(store);
}
}
When click on some item in list then call method onClick().
So I need my fragment to handle click of item.
To to do this I use EventBus.
After click I call
EventBus.getDefault().post(store);
And as result in fragment call method:
onStoreClickEvent(Store store)
So this is my model to communicate between my custom fragment and my custom adapter.
It's work. Fine.
The quesion is: Is this a best approach for communicate between fragment and adapter?
P.S. My custom adapter can use by fragment, activity or custom view.
An alternative would be to create a listener interface like this:
public interface OnStoreItemClickListener {
public void onStoreItemClicked(Store item);
}
Then, in your Adapter, you declare a field of type OnStoreItemClickListener and you create a setter method for it.
When you detect a click, you simply check if your listener is set and call the onStoreItemClicked() method.
You can register a listener via the setter from wherever you need.

RecyclerView is a null in fragment

I have MainActivity,which contain viewpager,which contain 2 fragments:
MainActivity
ViewPager viewPager = findViewById(R.id.viewPager);
MyPagerAdapter adapter = new MyPagerAdapter(this,
getSupportFragmentManager());
viewPager.setAdapter(adapter);
TabLayout tabLayout = findViewById(R.id.TabLayout);
tabLayout.setupWithViewPager(viewPager);
Fragment fragmentHour=adapter.getItem(1);
onChangeDayListener2= (OnChangeDayListener) fragmentHour;
I am also have interface for send data from main activity in fragment:
public interface OnChangeDayListener{
void OnChange(WeatherList list,int pos);
}
but when i try to work with this callback in interface my recycler adapter always is null:
HourWeatherFragment:
public class HourWeatherFragment extends Fragment implements MainScreen.OnChangeDayListener{
private RecyclerView recyclerView;
private AdapterHour adapter;
private ArrayList<Weather> days;
Context context;
static HttpClient httpClient;
public HourWeatherFragment() {
// Required empty public constructor
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
days=new ArrayList<>();
adapter = new AdapterHour(days,getActivity());
LinearLayoutManager LayoutManager = new LinearLayoutManager(getActivity().getBaseContext(),
LinearLayoutManager.VERTICAL, false);
recyclerView.setLayoutManager(LayoutManager);
recyclerView.setAdapter(adapter);
days.add(new Weather());
recyclerView.getAdapter().notifyDataSetChanged();
Log.d("recycler","adapter seted!");
}
#Override
public void onViewCreated(#NonNull View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View rootView = inflater.inflate(R.layout.fragment_hour_weather, container, false);
recyclerView = rootView.findViewById(R.id.hour_list);
httpClient=new HttpClient();
MyAsyncTask task=new MyAsyncTask();
// task.execute("lviv");
return rootView;
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
this.context=context;
}
#Override
public void OnChange(WeatherList list,int pos) {
String date=list.getAverageWeather().get(pos).getDate();
ArrayList<Weather> weather=list.getByDate(date);
Log.d("ldata","size of weather for adding="+weather.size());
// days.add(new Weather());
if(adapter!=null){
adapter.notifyDataSetChanged();
Log.d("tag","first null!");}
else{
try{
recyclerView.getAdapter();}
catch (NullPointerException ex){
Log.d("tag","null!");//THERE ALWAYS NULL
}}
So,firstly creating activity,then i start load data and when data loaded i send data from MainActivity to HourWeatherFragment throught callback,
but when i receive data in fragment,my adapter is null,how i can fix it?
You can create a static singleton class to hold data and retrieve that data in the fragment.
public class DataHolder {
//create static variables here.
}
In your fragment simply retrieve the data and make it null after that.
Alternative solution
Another solution is to use Bundles. Follow the bundle solution here.
You must cast RecyclerView.
in your fragment and onCreateView method :
recyclerView = (RecyclerView) rootView.findViewById(R.id.hour_list);
I know this is an old question, but contrary to the accepted answer I think the issue is that the handle to the fragment's widget such as recyclerView is not available in the OnCreateView function.
The handles (or pointers if you wish) to the widgets are only guaranteed to exist in the OnViewCreated function.
This documentation has good description of the lifecycle of fragments:
https://guides.codepath.com/android/Creating-and-Using-Fragments
an extract is:
// This event is triggered soon after onCreateView().
// onViewCreated() is only called if the view returned from onCreateView() is non-null.
// Any view setup should occur here. E.g., view lookups and attaching view listeners.
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
ListView lv = (ListView) view.findViewById(R.id.lvSome);
lv.setAdapter(adapter);
}
Hope this helps.

Best approach to communicate between Fragment/Activity and RecyclerView.Adapter?

My fragment:
public class FragmentSort extends Fragment {
#BindView(R.id.sortRecyclerView)
RecyclerView sortRecyclerView;
protected RecyclerView.Adapter adapter;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(layoutResId, container, false);
adapter = new StoreListItemAdapter(getActivity(), collection);
sortRecyclerView.setAdapter((RecyclerView.Adapter) adapter);
return rootView;
}
#Subscribe
public void onStoreClickEvent(Store store) {
Debug.d(TAG, "onStoreClickEvent: store = " + store);
handleFilterItemSelect(store.getAddress());
}
}
Here my custom adapter:
public class StoreListItemAdapter extends RecyclerView.Adapter {
private Context context;
private List<?> data = new ArrayList<>();
public DataBindingRecyclerViewAdapter(Context context, List<?> data) {
this.context = context;
this.data = data;
}
public void onClick(Store store) {
EventBus.getDefault().post(store);
}
}
When click on some item in list then call method onClick().
So I need my fragment to handle click of item.
To to do this I use EventBus.
After click I call
EventBus.getDefault().post(store);
And as result in fragment call method:
onStoreClickEvent(Store store)
So this is my model to communicate between my custom fragment and my custom adapter.
It's work. Fine.
The quesion is: Is this a best approach for communicate between fragment and adapter?
P.S. My custom adapter can use by fragment, activity or custom view.
An alternative would be to create a listener interface like this:
public interface OnStoreItemClickListener {
public void onStoreItemClicked(Store item);
}
Then, in your Adapter, you declare a field of type OnStoreItemClickListener and you create a setter method for it.
When you detect a click, you simply check if your listener is set and call the onStoreItemClicked() method.
You can register a listener via the setter from wherever you need.

how to set application context in a fragment in android?

i have an ActionBar that has 2 tabs and each tabs layout is a fragment. in 1 of these tabs , there is a listView. and i want to set ArrayAdapetr for it. but when i run app, error occurred and error is about my application context. my code is :
public class TarfandFrag extends Fragment {
String values[] = new String[]{"sadeq","ali"};
ListView listView;
Context context;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.tarfad_layout,container,false);
listView = (ListView) view.findViewById(R.id.list_tarfand);
return view;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ArrayAdapter adapter = new ArrayAdapter(context,android.R.layout.simple_list_item_1,values);
listView.setAdapter(adapter);
}
}
but its not working. notice that i don't want use listFragment or anything else. i replace context with getActivity() , context.getApplicationContext, getActivity.getApplicationContext. but not working. plz help meeeee
Assing getActivity() to context in onCreate.
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
context=getActivity();
}
In a fragment, onCreate() is called before onCreateView(). the consequence of this is that, at the point onCreate() is called, your ListView is not yet associated with an element in the layout (as your are doing this in onCreateView() which gets called later) and will hence resolve to null and you will get a null pointer exception when you set the adapter for the ListView. Move the code setting the adapter to within the onCreateView() method and use getActivity() and you should be fine.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.tarfad_layout,container,false);
listView = (ListView) view.findViewById(R.id.list_tarfand);
// Here listview will not be null as it is now bound to an object
ArrayAdapter adapter = new ArrayAdapter(getActivity(),android.R.layout.simple_list_item_1,values);
listView.setAdapter(adapter);
return view;
}

ListFragment content changing

I have a simple MyListFragment fragment which shows one simple array of data on the screen.
public class MyListFragment extends ListFragment {
private ArrayAdapter<String> adapter;
public ArrayAdapter<String> getAdapter() {
return adapter;
}
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
String[] values = new String[] {"data", "data", "data"};
adapter = new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_1, values);
setListAdapter(adapter);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return super.onCreateView(inflater, container, savedInstanceState);
}
}
I wonder how can I change this data dynamically from my Activity? Please tell me if there is a simple way how to do this! I've tried but have failed...
UPD: I added a function changeContent to MyListFragment:
public void changeContent(String[] value) {
adapter.addAll(value);
adapter.notifyDataSetChanged();
}
}
As you see, adapter is a global variable and it's initialized inside onActivityCreated, but my program crashes because inside changeContent in equals null! I can't get why!
You could write a function that changes your values variable and then once you have filled it with your new data just call
adapter.notifyDataSetChanged();
to fill your list with the new data.

Categories

Resources