class Fragment extends Fragment() implements Callback {
#Ovverride
onCreate(SavedInstanceState savedInstanceState) {
Adapter adapter = new Adapter(getContext())
}
#Ovverride
someCallbackMethod() { // Code when callback is called }
}
class Adapter extends RecyclerView.Adapter<VH>() {
Context context;
public Adapter(Context context) {this.context = context}
class VH extends RecyclerView.ViewHolder {
private void bind() {
button.setOnClickListener (v-> {
BottomSheet sheet = BottomSheet.newInstance(variable);
sheet.show(((FragmentActivity) context).getSupportFragmentManager(),
sheet.getClass().getName());
})
}
}
class BottomSheet extends BottomSheetDialogFragment {
#Override
public void onAttach(#NonNull Context context) {
super.onAttach(context);
if (context instanceof Callback) listener =
(Callback) context;
else Log.v("BottomSheet", "Not instance");
}
}
Even though the main fragment implements the callback the context of that fragment is never the instance of the callback what might be the reason for this and how can it be fixed.
Note: There might be some errors here and there because I made a generic view of the classes.
A Fragment does not inherit from Context. Your easiest solution would be to implement your Callback in the Activity (which is a Context) that contains the Fragment.
Related
android navigation component reload fragment , and observe mutable data again when navigate back from fragment to fragment , I tried single observe listener but nothing happen keep reloading and hitting api again
public class TermsFragment extends Fragment {
private TermsViewModel termsViewModel;
private FragmentTermsBinding binding;
public View onCreateView(#NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
termsViewModel = new ViewModelProvider(this).get(TermsViewModel.class);
termsViewModel.init(getContext());
binding = FragmentTermsBinding.inflate(inflater, container, false);
termsViewModel.terms.observe(getViewLifecycleOwner(), terms -> {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
binding.terms.setText(Html.fromHtml(terms.replaceAll("<img.+?>", ""), Html.FROM_HTML_MODE_COMPACT));
} else {
binding.terms.setText(Html.fromHtml(terms.replaceAll("<img.+?>", "")));
}
});
View root = binding.getRoot();
return root;
}
#Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
}
}
and my viewmodel Class
public class TermsViewModel extends ViewModel implements Onresponse {
public MutableLiveData<String> terms;
Context context=null;
public TermsViewModel() {
terms = new MutableLiveData<>();
}
public void init(Context context){
this.context=context;
Map<String,Object> body=new HashMap<>();
body.put("st", Api.app_data);
body.put("id",1);
body.put("lg",Constant.langstr);
Constant.connect(context,Api.app_data,body,this::onResponse,false);
}
#Override
public void onResponse(String st, JSONObject object, int online) {
if(object!=null) {
try {
terms.setValue(object.getString("data"));
} catch (JSONException e) {
e.printStackTrace();
}
}
}
}
When you navigate back and forth the view does not survive but the fragment does. Thus you can move any initialization code to onCreate instead of onCreateView. onCreate is called once per fragment's lifetime.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
termsViewModel = new ViewModelProvider(this).get(TermsViewModel.class);
termsViewModel.init(getContext());
}
This way you will:
create view model only once! It is crucial as replacing view model with a new instance discards all the data you have previously loaded;
call init only once in a lifetime of this fragment.
I am sending the arraylist from one fragment to the another by using the interface.but when i make the instance of the interface it gives class cast exception.can anyone tell me what i am doing wrong ??
This is my interface:-
public class SaleFragment extends UpdatableFragment {
private SendArrayList mSendArrayList;
public interface SendArrayList {
public void sendData(ArrayList<String> listCustomer);
}
}
And this is the code where i am making the instance of the interface and add the arraylist to it :-
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
mSendArrayList = (SendArrayList)getActivity();
dbh = new DatabaseHandler(getContext());
Cursor cursor = dbh.getAllCustomer();
if (cursor.moveToFirst()) {
do {
String customerName = cursor.getString(0);
mListCustomerName.add(customerName);
} while (cursor.moveToNext());
}
mSendArrayList.sendData(mListCustomerName);
}
at this line " mSendArrayList = (SendArrayList)getActivity();" gives class cast exception can anyone tell me how can i use the interface for send the data from one fragment to the another.
You get the Activity instance from the OnAttach() method.
public class HeadlinesFragment extends ListFragment {
OnHeadlineSelectedListener mCallback;
// Container Activity must implement this interface
public interface OnHeadlineSelectedListener {
public void onArticleSelected(int position);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception
try {
mCallback = (OnHeadlineSelectedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnHeadlineSelectedListener");
}
}
...
}
The following method in the fragment is called when the user clicks on a list item. The fragment uses the callback interface to deliver the event to the parent activity.
#Override
public void onListItemClick(ListView l, View v, int position, long id) {
// Send the event to the host activity
mCallback.onArticleSelected(position);
}
The Activity should implement the your Interface.then you send the data from fragment to activity, it will be shared to another fragment.
public static class MainActivity extends Activity
implements HeadlinesFragment.OnHeadlineSelectedListener{
...
public void onArticleSelected(int position) {
// The user selected the headline of an article from the HeadlinesFragment
// Create your second fragment instance here and share your data (position)
}
}
reference: https://developer.android.com/training/basics/fragments/communicating.html#Deliver
Its simple,get instance of interface in onAttach
private SendArrayList mCallback;
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
mCallback = (SendArrayList) context;
dbh = new DatabaseHandler(getContext());
Cursor cursor = dbh.getAllCustomer();
if (cursor.moveToFirst()) {
do {
String customerName = cursor.getString(0);
mListCustomerName.add(customerName);
} while (cursor.moveToNext());
}
mCallback.sendData(mListCustomerName);
} catch (ClassCastException e) {
throw new ClassCastException(context.toString()
+ " must implement SendArrayList");
}
}
And in your Parent Activity, you need to implement SendArrayList interface
So I need to have access to a variable from MainActivty from another class. what's the best way to do so. Below is the scenario but I cannot call frag.receiveInt(give_this_int_to_fragment);
MainActivity.java:
import com.me.fragments.FragmentExtender
public class MainActivity{
int give_this_int_to_fragment;
protected void onCreate(...){
Fragment frag = new FragmentExtender();
give_this_int_to_frag = new int();
frag.receiveInt(give_this_int_to_frag);
}
}
FragmentExtender.java:
public class FragmentExtender extends Fragment{
int receive_int_from_main;
public View onCreateView(...){...}
receiveInt(int_from_main){
receive_int_from_main = int_from_main;
}
}
I'm not trying to create a duplicate variable, just a pointer to that variable in MainActivity if you catch my drift.
Create getter and setter for that variable in Activity
public class MainActivity{
int give_this_int_to_fragment;
protected void onCreate(...){
Fragment frag = new FragmentExtender();
}
}
public int getgive_this_int_to_fragment(){
return give_this_int_to_fragment;
}
public void getgive_this_int_to_fragment(int var){
give_this_int_to_fragment = var;
}
Now, in fragment you can use getActivity() to get activity context and then call getter
public class FragmentExtender extends Fragment{
public View onCreateView(...){
//....
int var = ((MainActivity) getActivity()).getgive_this_int_to_fragment();
}
}
The more elegant way will be to implement an interface in the Fragment and make the app inherit from it. That way you can comunicate that way.
interface FragmentInterface{
Object getMainValue();
void passValueToMain(Object obj);
}
With this code, you just have to add it to the MainActivity declaration and in the fragment constructor
public class MainActivity implements FragmentInterface{
int give_this_int_to_fragment;
protected void onCreate(...){
Fragment frag = new FragmentExtender();
....
}
}
And then in the Fragment
public class FragmentExtender extends Fragment{
private FragmentInterface mInterface;
int receive_int_from_main;
public View onCreateView(...){...}
#Override
public void onAttach(Context context) {
super.onAttach(context);
setListeners(context);
}
//This is for pre Marshmallow versions
#SuppressWarnings("deprecation")
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
setListeners(activity);
}
}
private void setListeners(Object object) {
if (object instanceof FragmentInterface) {
mListener = (FragmentInterface) object;
} else {
throw new RuntimeException(object.toString()
+ " must implement FragmentInterface");
}
}
}
This will work for any fragment and any activity that implement them
Hi everybody I was stuck at a point, the problem is that I have three classes shown below and I want to instantiate my DatabaseHelper class in AsyncTask class. Could you please help, how can I get context in AsyncTask class?
Problem Solved
MainActivity class
public class MainActivity extends Activity {
...
FetchData fetchData = new FetchData();
fetchData.execute();
...
}
DatabaseHelper
public class DatabaseHelper extends SQLiteOpenHelper {
....
public DatabaseHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
....
}
FetchData class
public class FetchData extends AsyncTask<String, String, String> {
....
DatabaseHelper db = new DatabaseHelper(); //need context here!!!
....
}
#
Thanks to Kasra, I create a fourh class and use it in MainActivity before calling AsyncTask
ContextStatic class
public class ContextStatic {
private static Context mContext;
public static Context getmContext() {
return mContext;
}
public static void setmContext(Context mContext) {
ContextStatic.mContext = mContext;
}
}
Updated MainActivity class
public class MainActivity extends Activity {
...
ContextStatic.setmContext(this);
FetchData fetchData = new FetchData();
fetchData.execute();
...
}
Try this:
private class FetchData extends AsyncTask<Context, Void, Void> {
protected Long doInBackground(Context... c) {
Context myContext = c[0];
// Do your things here....
}
protected void onPostExecute() {
// Insert your post execute code here
}
}
You can call this AsyncTask by the following line - assuming you are in an activity:
new FetchData().execute(this);
if You cannot change your AsyncTask deceleration, then you can try using a static variable - although it is not as efficient and pretty as AsyncTask deceleration. Try this:
Class myStatic{
private static Context mContext;
static public void setContext(Context c);
mContext = c;
}
static public Context getContext(){
return mContext;
}
}
and in your main code, before you call AsyncTask, call this:
myStatic.setContext(this);
in your doInBackground method of your AsyncTask, add this:
Context myContext = myStatic.getContext();
I want to return a callback from a custom adapter to my fragment. However the adapter won't let me pass the reference of the Fragment implementing the interface defined in custom adapter. How can I receive callbacks from adapter to fragment?
public class MyFrag extends Fragment implements MyInterface
{
#Override
public void onCreateView()
{
MyAdapter adapter = new MyAdapter(this); // error here: How to resolve
}
#Override
public void mySignal()
{
}
}
public class MyAdapter extends RecyclerViewAdapter
{
MyInterface listener;
public MyAdapter(MyInterface listener)
{
this.listener = listener;
}
public interface MyInterface
{
public void mySignal();
}
}
Just for a clear definition and SOC you could try this instead,
public class MyFrag extends Fragment
{
#Override
public void onCreateView()
{
MyAdapter adapter = new MyAdapter(new MyInterface() {
#Override
public void mySignal()
{
//do stuff here
}
});
}
}
As I know, Fragment has this method
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
Sorry for my question! What is onCreateView() method without any params?
This way will work fine if there is not any different things more.