Why does onAttach not recognize the correct instanceof context? - java

I am having troubles getting Android to set my listener. Somehow the context isn't of the type I am expecting it to be. I'm not sure where I am going wrong.
Below is AddEditCharacterFragment.java, where it is throwing an exception because context isn't of the type I expect.
public class AddEditCharacterFragment extends Fragment {
public static final String ARG_PARAM1 = "param1";
private InitiativeTrackerDBHelper mHelper;
private String mParam1;
private Character mCharacter;
public AddEditCharacterFragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* #return A new instance of fragment AddEditCharacterFragment.
*/
// TODO: Rename and change types and number of parameters
public static AddEditCharacterFragment newInstance() {
AddEditCharacterFragment fragment = new AddEditCharacterFragment();
Bundle args = new Bundle();
//args.putInt(ARG_PARAM1, id);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_add_character, container, false);
mHelper = new InitiativeTrackerDBHelper(getActivity());
mCharacter = mHelper.addCharacter();
EditText characterNameEditText = (EditText) v.findViewById(R.id.character_name_text_edit);
characterNameEditText.setText(mCharacter.getName());
characterNameEditText.addTextChangedListener(new TextWatcher() {
public void onTextChanged(CharSequence c, int start, int before, int count) {
mCharacter.setName(c.toString());
}
public void beforeTextChanged(CharSequence c, int start, int before, int after) {
}
public void afterTextChanged(Editable c) {
}
});
EditText modifierPicker =
(EditText) v.findViewById(R.id.modEditText);
modifierPicker.setText(Integer.toString(mCharacter.getModifier()));
modifierPicker.addTextChangedListener(new TextWatcher() {
public void onTextChanged(CharSequence c, int start, int before, int count) {
mCharacter.setModifier(Integer.parseInt(c.toString()));
}
public void beforeTextChanged(CharSequence c, int start, int before, int after) {
}
public void afterTextChanged(Editable c) {
}
});
Button saveButton = (Button) v.findViewById(R.id.saveButton);
saveButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(mHelper != null)
{
mHelper.updateCharacter(mCharacter);
Toast.makeText(getActivity(), "Update complete!", Toast.LENGTH_LONG).show();
mListener.onCharacterSave();
}
}
});
return v;
}
private OnCharacterSave mListener;
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnCharacterSave) {
mListener = (OnCharacterSave) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public interface OnCharacterSave {
public void onCharacterSave();
}
}
AddEditCharacterActivity is the activity for the fragment above.
public class AddEditCharacterActivity extends SingleFragmentActivity
implements AddEditCharacterFragment.OnCharacterSave {
#Override
protected Fragment createFragment() {
return AddEditCharacterFragment.newInstance();
}
#Override
public void onCharacterSave() {
FragmentManager fm = getFragmentManager();
// Get the container for the character list
InitiativeListFragment initiativeListFragment = (InitiativeListFragment)
fm.findFragmentById(R.id.fragmentContainer);
// Update the UI
initiativeListFragment.updateInitiativeList();
}
}
InitiativeTrackerActivity which is using an intent to start the AddEditCharacterActivity and subsequently AddEditCharacterFragment.
public class InitiativeTrackerActivity extends SingleFragmentActivity
implements InitiativeListFragment.OnCharacterListListener, AddEditCharacterFragment.OnCharacterSave {
#Override
protected Fragment createFragment() {
return InitiativeListFragment.newInstance();
}
#Override
public void onAddCharacter() {
Intent intent = new Intent(this, AddEditCharacterActivity.class);
startActivity(intent);
}
#Override
public void onCharacterSave() {
FragmentManager fm = getFragmentManager();
// Get the container for the character list
InitiativeListFragment initiativeListFragment = (InitiativeListFragment)
fm.findFragmentById(R.id.fragmentContainer);
// Update the UI
initiativeListFragment.updateInitiativeList();
}
}
And the base class of SingleFragmentActivity for reference:
public abstract class SingleFragmentActivity extends AppCompatActivity {
protected abstract Fragment createFragment();
protected int getLayoutId() {
return R.layout.activity_single_fragment;
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayoutId());
FragmentManager fm = getFragmentManager();
Fragment fragment = fm.findFragmentById(R.id.fragmentContainer);
if (fragment == null) {
fragment = createFragment();
fm.beginTransaction()
.add(R.id.fragmentContainer, fragment)
.commit();
}
}
}
And InitiativeListFragment.java
package com.example.twistedpurpose.finalproject;
import android.content.Context;
import android.content.Intent;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.app.Fragment;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.CursorAdapter;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;
import android.widget.Toast;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
/**
* A simple {#link Fragment} subclass.
* Activities that contain this fragment must implement the
* {#link InitiativeListFragment.OnCharacterListListener} interface
* to handle interaction events.
* Use the {#link InitiativeListFragment#newInstance} factory method to
* create an instance of this fragment.
*/
public class InitiativeListFragment extends Fragment {
private InitiativeTrackerDBHelper.CharacterCursor mCursor;
private CharacterCursorAdapter adapter;
private OnCharacterListListener mListener;
public InitiativeListFragment() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* #return A new instance of fragment InitiativeListFragment.
*/
public static InitiativeListFragment newInstance() {
return new InitiativeListFragment();
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (adapter != null) {
adapter.notifyDataSetChanged();
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View v = inflater.inflate(R.layout.fragment_initiative_list, container, false);
//getActivity().deleteDatabase("characters.db");
Context context = getActivity();
// 1. Create a new InitiativeTrackerDBHelper
InitiativeTrackerDBHelper dbHelper = new InitiativeTrackerDBHelper(context);
// 2. Query the characters and obtain a cursor (store in mCursor).
mCursor = dbHelper.queryCharacters();
// Find ListView to populate
ListView characterListView = (ListView) v.findViewById(R.id.character_listView);
// Setup cursor adapter using cursor from last step
adapter = new CharacterCursorAdapter(context, mCursor);
// Attach cursor adapter to the ListView
characterListView.setAdapter(adapter);
Button rollButton = (Button) v.findViewById(R.id.rollBtn);
rollButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
InitiativeTrackerDBHelper dbHelper = new InitiativeTrackerDBHelper(getContext());
List<Character> characterList = dbHelper.getCharacters();
InitiativeRoller.rollInitiative(characterList);
for (Character c : characterList) {
dbHelper.updateCharacter(c);
}
updateInitiativeList();
Toast.makeText(getContext(), "Roll initiative!", Toast.LENGTH_SHORT).show();
}
});
Button addButton = (Button) v.findViewById(R.id.addBtn);
addButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if(mListener != null) {
mListener.onAddCharacter();
}
}
});
return v;
}
public void updateInitiativeList(){
if(mCursor != null && adapter != null){
mCursor.requery();
adapter.notifyDataSetChanged();
}
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnCharacterListListener) {
mListener = (OnCharacterListListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated
* to the activity and potentially other fragments contained in that
* activity.
* <p>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.html"
* >Communicating with Other Fragments</a> for more information.
*/
public interface OnCharacterListListener {
public void onAddCharacter();
}
/**
* A character cursor adaptor for adding characters
* to a list
*/
private static class CharacterCursorAdapter extends CursorAdapter {
private InitiativeTrackerDBHelper.CharacterCursor mCharacterCursor;
public CharacterCursorAdapter(Context context, InitiativeTrackerDBHelper.CharacterCursor cursor) {
super(context, cursor, 0);
mCharacterCursor = cursor;
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
// Use a layout inflater to get a row view
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
return inflater.inflate(R.layout.character_listview, parent, false);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
TextView characterName = (TextView) view.findViewById(R.id.name);
TextView characterMod = (TextView) view.findViewById(R.id.mod);
TextView characterInit = (TextView) view.findViewById(R.id.init);
characterName.setText(mCharacterCursor.getCharacter().getName());
characterMod.setText(Integer.toString(mCharacterCursor.getCharacter().getModifier()));
characterInit.setText(Integer.toString(mCharacterCursor.getCharacter().getTotalInitiative()));
}
}
}

Your problem is that you do NOT implement the Interface in your activity…
public class AddEditCharacterActivity extends SingleFragmentActivity {
This does not implement OnCharacterSave.
This is what I meant with the earlier comment.
UPDATE:
You are misunderstanding Fragments.
// Get the container for the character list -> This is not true. You're not getting the "Container", you're trying to get an actual instance of a fragment.
InitiativeListFragment initiativeListFragment = (InitiativeListFragment)
fm.findFragmentById(R.id.fragmentContainer);
This would be fine, if that fragment were there.
Let me put it in a more graphic way, this is what you're doing… (give or take)
Start Activity XXX (SingleFragmentActivity).
At some point, InitiativeListFragment in R.id.fragmentContainer is replaced by AddEditCharacterActivity / AddEditCharacterFragment combo.
At this point, R.id.fragmentContainer contains a fragment of type AddEditCharacterFragment.
Since your Activity implements OnCharacterSave, so far so good.
Still in the same activity/fragment combo, you call onCharacterSave() which is implemented (see #4), so all is good.
You then tell the Fragment manager to get you the fragment in R.id.fragmentContainer and you explicitly say (aka: cast) that the Fragment is of the type InitiativeListFragment, but… your Activity should know this is not the case… because the current fragment is AddEditCharacterFragment.
What you ought to do is:
Re-Read about FragmentManager and FragmentTransactions.
If you're going to pass info to another Fragment that is not currently visible/started/attached/etc. then you have to obtain a reference (via TAG if you have one).
Then maybe add it to a container if possible while passing the "data" via a Bundle.
It's completely unclear what you're trying to do and it what order because your code doesn't really have a lot of separation of concerns so as you can see your Activities and Fragments are becoming monolithic monsters full of code and business logic. There are solutions and alternatives (Read about Model-View-Presenter or similar patterns) that can ease the mess while providing an easier environment to test your code.
That being said, regardless of the complexity of your code, I believe you need to understand WHY you're getting the exception, and I have the feeling that you need to practice that a little bit.
In short… when you do findFragmentById, you do get the Fragment (if existing), but you can't just cast it to whatever you want.
OLD COMMENTS:
newInstance() static methods should generally live inside the Fragments and return new YourFragment();
What I mean is the Fragment creation is usually done via a static method IN the fragment.
Say you have
MyFragment extends Fragment {
public static MyFragment newInstance() {
return new MyFragment();
}
public MyFragment() {
// empty constructor is most of the time needed to restore.
}
}
Then from the activity you usually do what you're doing, but the fragment instance is created by calling MyFragment.newInstance(); (this is how Google does it).
I suggest you add your fragment by Tag as well (it's faster). So you do
final Fragment existing = getSupportFragmentManager().findFragmentByTag(tag);
if (existing == null) {
final Fragment newInstance = MyFragment.newInstance();
getSupportFragmentManager()
.beginTransaction()
.add(R.id.fragmentContainer, newInstance, tag)
.commit();
}
Tag is a String and you can keep it in constants (final static String MYFRAGMENT_TAG = "MYFRAGMENT_TAG"; for example).
Are you using Support.V4 fragments? If so you need to change getFragmentManager() to getSupportFragmentManager() (It looks like you are, because you have AppCompatActivity.
Also, the fragment transaction, should be surrounded by if (savedInstaceState == null) { // do it here }

I do not see any problems with creating a fragment instance in your question as stated in other answers.
I think the problem is that your context is AddEditCharacterActivity where you do not implement OnCharacterSave interface.
So you should add:
public class AddEditCharacterActivity extends SingleFragmentActivity implements OnCharacterSave

Related

How to fix "System services not available to Activities before onCreate" when passing values between classes, and updating recycler view?

I'm making an order taking cashier application. Using a recycler view to show the order queue. However, I'm having trouble passing ArrayList values between classes, and also, updating the recycler view. In this case, I won't have a massive recycler view so performance wouldn't be that much of an issue, but an optimized method of doing this would be greatly appreciated. I just don't know how to tackle this problem.
I've attempted to create a set method in the MainActivty class, I've also tried the intent put extra, but I don't believe I fully understand put extra quite yet.
MainActivity Class:
public class MainActivity extends AppCompatActivity implements MyRecyclerViewAdapter.ItemClickListener {
private RecyclerView recyclerView;
private RecyclerView.Adapter mAdapter;
private RecyclerView.LayoutManager layoutManager;
public ArrayList<String> orderList = new ArrayList<>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
// set up the RecyclerView
recyclerView = findViewById(R.id.recyle_view_activity);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
mAdapter = new MyRecyclerViewAdapter(this, orderList);
((MyRecyclerViewAdapter) mAdapter).setClickListener(this);
recyclerView.addItemDecoration(new DividerItemDecoration(this,
DividerItemDecoration.VERTICAL));
recyclerView.setAdapter(mAdapter);
}
//This is the set method I attempted:
public void setOrderAdd(ArrayList<String> data){
if (data != null){
mAdapter = new MyRecyclerViewAdapter(this,data); //Error refrences here
}
}
}
Other Class:
public class regularCoffee extends AppCompatActivity implements AdapterView.OnItemSelectedListener, Serializable {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_regular_coffee);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
addToOrder();
}
public void addToOrder(){
//Reg Addons:
final CheckBox leaveRoomReg = findViewById(R.id.leave_room_reg);
final CheckBox cinnamonReg = findViewById(R.id.cinnamon_reg);
final CheckBox chocolateSyrupReg = findViewById(R.id.chocolate_syrup_reg);
final CheckBox whiteChocolateSyrupReg = findViewById(R.id.white_chocolate_syrup_reg);
final CheckBox caramelReg = findViewById(R.id.caramelReg);
final CheckBox hazelnutReg = findViewById(R.id.hazel_nut_reg);
final CheckBox[] RegCoffeeAddOns = {leaveRoomReg,cinnamonReg,chocolateSyrupReg,whiteChocolateSyrupReg,caramelReg,hazelnutReg};
//Decaf Addons:
final Button leaveRoomDecaf = findViewById(R.id.leave_room_decaf);
final Button cinnamonDecaf = findViewById(R.id.cinnamon_decaf);
final Button chocolateSyrupDecaf = findViewById(R.id.chocolate_syrup_decaf);
final Button whiteChocolateDecaf = findViewById(R.id.white_chocolate_syrup_decaf);
final Button caramelDecaf = findViewById(R.id.caramel_decaf);
final Button hazelnutDecaf = findViewById(R.id.hazel_nut_decaf);
final Button[] DecafCoffeeAddOns = {leaveRoomDecaf,cinnamonDecaf,caramelDecaf,chocolateSyrupDecaf,whiteChocolateDecaf,hazelnutDecaf};
Button addToOrderButton = findViewById(R.id.addToOrderReg);
addToOrderButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
MainActivity addToOrderArea = new MainActivity();
String forOrder;
ArrayList<String> tempArray = new ArrayList<>();
if (regCoffeeQuantity > 0){
forOrder = "Regular Coffee (x" + regCoffeeQuantity + ") \n ";
for (int i = 0; i < RegCoffeeAddOns.length; i++){
if (RegCoffeeAddOns[i].isChecked()){
forOrder = forOrder + "| " + RegCoffeeAddOns[i].getText().toString() + " ";
System.out.println(forOrder);
}
}
addToOrderArea.setOrderAdd(tempArray); //Error refrences here
}
}
});
}
RecyclerView Adapter:
package com.example.holygroundsapplication;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.ViewHolder> {
private List<String> mData;
private LayoutInflater mInflater;
private ItemClickListener mClickListener;
// data is passed into the constructor
MyRecyclerViewAdapter(Context context, List<String> data) {
this.mInflater = LayoutInflater.from(context); //Error refrences here.
this.mData = data;
}
// inflates the row layout from xml when needed
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = mInflater.inflate(R.layout.recyclerview_row, parent, false);
return new ViewHolder(view);
}
// binds the data to the TextView in each row
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
String animal = mData.get(position);
holder.myTextView.setText(animal);
}
// total number of rows
#Override
public int getItemCount() {
return mData.size();
}
// stores and recycles views as they are scrolled off screen
public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView myTextView;
ViewHolder(View itemView) {
super(itemView);
myTextView = itemView.findViewById(R.id.tvAnimalName);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View view) {
if (mClickListener != null) mClickListener.onItemClick(view, getAdapterPosition());
}
}
// convenience method for getting data at click position
String getItem(int id) {
return mData.get(id);
}
// allows clicks events to be caught
void setClickListener(MainActivity itemClickListener) {
this.mClickListener = itemClickListener;
}
// parent activity will implement this method to respond to click events
public interface ItemClickListener {
void onItemClick(View view, int position);
}
}
This is the error:
java.lang.IllegalStateException: System services not available to Activities before onCreate()
at android.app.Activity.getSystemService(Activity.java:5774)
at android.view.LayoutInflater.from(LayoutInflater.java:233)
at com.example.holygroundsapplication.MyRecyclerViewAdapter.<init>(MyRecyclerViewAdapter.java:21)
at com.example.holygroundsapplication.MainActivity.setOrderAdd(MainActivity.java:89)
at com.example.holygroundsapplication.regularCoffee$8.onClick(regularCoffee.java:262)
...
In your onClick function you have
MainActivity addToOrderArea = new MainActivity();
You shouldn't create activity instances by your self. This is something the Android system does. Because you create the activity by yourself it is not initialized (i.e. onCreate() is not called). The adapter which is created in the setOrderAdd() requires that the Activity is initialized and therefore throws an exception.
To prevent these problems you need to create your Activity with startActivity(). You can pass your data to the new Activity by adding extras to the starting Intent.
I think you logically need to replace
MainActivity addToOrderArea = new MainActivity();
with
MainActivity addToOrderArea = MainActivity.this;
But since you are not in the same class you need to pass the reference accordingly.
As long the MainActivity is still active and the other class is just a helper that wouldn't be a problem. Just add MainActivity to all the constructors... Somewhat like this:
OtherClass{
private MainClass addToOrderArea;
public OtherClass(MainClass addToOrderArea){
this.addToOrderArea=addToOrderArea;
}
// ...
abstract class MyOnclicklistener extends View.OnClickListene{
private MainClass addToOrderArea;
public MyOnclicklistener(MainClass addToOrderArea){
this.addToOrderArea=addToOrderArea;
}
}
// ...
addToOrderButton.setOnClickListener(new MyOnclicklistener(this.addToOrderArea) {
#Override
public void onClick(View v) {
String forOrder;
ArrayList<String> tempArray = new ArrayList<>();
if (regCoffeeQuantity > 0){
forOrder = "Regular Coffee (x" + regCoffeeQuantity + ") \n ";
for (int i = 0; i < RegCoffeeAddOns.length; i++){
if (RegCoffeeAddOns[i].isChecked()){
forOrder = forOrder + "| " + RegCoffeeAddOns[i].getText().toString() + " ";
System.out.println(forOrder);
}
}
addToOrderArea.setOrderAdd(tempArray); //Error refrences here
}
}
});
}
Attention: i guess this might still get you into another error, since you try to edit one activity from another...
Propably only store the variable between both activities, that seems okay. Updating the recycler view directly from another activity however might get you into some android view or security errors. I would say just pass the variable and update the recyclerview in the onResume function later. Something like this:
private ArrayList<String> _data;
public void setOrderAdd(ArrayList<String> data){
if (data != null){
// only store variable
_data = data;
}
}
#Override
protected void onResume() {
super.onResume();
// make update of your viewing components here
if(_data!=null){
mAdapter = new MyRecyclerViewAdapter(this,_data);
}
}
Now it should work i guess

java - How to match the details of a Dialog from RecyclerViewAdapter to another Fragment upon clicking the button

I'm new to android coding, I've tried all the possible solution here and on YouTube but still struggling. I just want how to match the data from a dialog of a fragment to another fragment upon pressing the button. we're working on a simple project. :)
Here is what we want to do.Kindly watch this link:
https://imgur.com/tGdWcfq
We want to change the name that will match the dialog upon clicking the "set parameters' button
here's what we found online the difference is we have a dialog button
https://www.youtube.com/watch?v=ZXoGG2XTjzU
https://www.youtube.com/watch?v=69C1ljfDvl0
Here are the codes
RecyclerViewAdapter.java
public class RecyclerViewAdapter extends RecyclerView.Adapter<RecyclerViewAdapter.MyViewHolder> {
Context mContext;
List<specieList> mData;
Dialog myDialog;
public RecyclerViewAdapter(Context mContext, List<specieList> mData) {
this.mContext = mContext;
this.mData = mData;
}
#Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v;
Button b;
v = LayoutInflater.from(mContext).inflate(R.layout.row,parent,false);
final MyViewHolder vHolder = new MyViewHolder(v);
myDialog = new Dialog(mContext);
myDialog.setContentView(R.layout.fishpop);
myDialog.getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
b = myDialog.findViewById(R.id.toasted);
b.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
TextView toastfish = (TextView) myDialog.findViewById(R.id.dialog_fish_id);
Toast.makeText(mContext,"Parameters are now set for " + toastfish.getText().toString(), Toast.LENGTH_SHORT).show();
// here upon clicking this button click we want to match the details in this dialog to another tab. Kindly watch the link above :)
}
});
vHolder.fish_choices.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
TextView dialog_fish = (TextView) myDialog.findViewById(R.id.dialog_fish_id);
TextView dialog_sciname = (TextView) myDialog.findViewById(R.id.dialog_sciname_id);
ImageView dialog_image = (ImageView) myDialog.findViewById(R.id.dialog_image_id);
dialog_fish.setText(mData.get(vHolder.getAdapterPosition()).getFish());
dialog_sciname.setText(mData.get(vHolder.getAdapterPosition()).getSciname());
dialog_image.setImageResource(mData.get(vHolder.getAdapterPosition()).getImage());
myDialog.show();
}
});
return vHolder;
}
#Override
public void onBindViewHolder(MyViewHolder holder, int position) {
holder.tv_fish.setText(mData.get(position).getFish());
holder.tv_sciname.setText(mData.get(position).getSciname());
holder.img.setImageResource(mData.get(position).getImage());
}
#Override
public int getItemCount() {
return mData.size();
}
public static class MyViewHolder extends RecyclerView.ViewHolder {
private LinearLayout fish_choices;
private TextView tv_fish;
private TextView tv_sciname;
private ImageView img;
public MyViewHolder(View itemView) {
super(itemView);
fish_choices = (LinearLayout) itemView.findViewById(R.id.choices);
tv_fish = (TextView) itemView.findViewById(R.id.textView1);
tv_sciname = (TextView) itemView.findViewById(R.id.textView2);
img = (ImageView) itemView.findViewById(R.id.image);
}
}
}
Code for overview tab(This tab we want to match the content)
public class overview extends Fragment {
View v2;
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
private OnFragmentInteractionListener mListener;
public overview() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* #param param1 Parameter 1.
* #param param2 Parameter 2.
* #return A new instance of fragment overview.
*/
// TODO: Rename and change types and number of parameters
public static overview newInstance(String param1, String param2) {
overview fragment = new overview();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
v2 = inflater.inflate(R.layout.fragment_overview, container, false);
Calendar calendar = Calendar.getInstance();
SimpleDateFormat time = new SimpleDateFormat("HH:mm:ss");
String currentDate = DateFormat.getDateInstance(DateFormat.FULL).format(calendar.getTime());
String currentTime = time.format(calendar.getTime());
TextView textViewDate =(TextView) v2.findViewById(R.id.date_id);
textViewDate.setText(currentDate);
TextView textViewTime =(TextView) v2.findViewById(R.id.time_id);
textViewTime.setText(currentTime);
return v2;
}
// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(Uri uri) {
if (mListener != null) {
mListener.onFragmentInteraction(uri);
}
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}
}
Code for Specie tab (this tab we want to refer)
public class specie extends Fragment {
View v;
private RecyclerView myrecyclerview;
private List<specieList> lstspecie;
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
private OnFragmentInteractionListener mListener;
public specie() {
// Required empty public constructor
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* #param param1 Parameter 1.
* #param param2 Parameter 2.
* #return A new instance of fragment specie.
*/
// TODO: Rename and change types and number of parameters
public static specie newInstance(String param1, String param2) {
specie fragment = new specie();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
lstspecie = new ArrayList<>();
lstspecie.add(new specieList("Nile Tilapia", "Oreochromis niloticus", R.drawable.tilapia));
lstspecie.add(new specieList("Ayungin (Silver Perch)", "Bidyanus bidyanus", R.drawable.ayungin));
lstspecie.add(new specieList("Sugpo (Tiger Prawn)", "Penaeus monodon", R.drawable.hipon));
lstspecie.add(new specieList("Hito (Catfish)", "Siluriformes", R.drawable.hito));
lstspecie.add(new specieList("Giant Gourami", "Osphronemus goramy", R.drawable.giant));
lstspecie.add(new specieList("Bangus (Milkfish)", "Chanos chanos", R.drawable.bangus));
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
v = inflater.inflate(R.layout.fragment_specie, container, false);
myrecyclerview = (RecyclerView)v.findViewById(R.id.specie_recycleview);
RecyclerViewAdapter recyclerAdapter = new RecyclerViewAdapter(getContext(), lstspecie);
myrecyclerview.setLayoutManager(new LinearLayoutManager(getActivity()));
myrecyclerview.setAdapter(recyclerAdapter);
return v;
}
// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(Uri uri) {
if (mListener != null) {
mListener.onFragmentInteraction(uri);
}
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
/**
* This interface must be implemented by activities that contain this
* fragment to allow an interaction in this fragment to be communicated
* to the activity and potentially other fragments contained in that
* activity.
* <p>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.html"
* >Communicating with Other Fragments</a> for more information.
*/
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}
}
Thank you!
Using object oriented Approach
You can write a function in your activity and you can call a fragment's method from it, as you have your Fragment's reference in your Activity when you initialized it like
In Your Activity
class yourActivity ... {
// your other methods
public void callFragmentMethod(String params) {
// here call your fragment's method
fragment.method(params);
}
}
In your Fragment now
class yourFragment ... {
// your other methods
public void method(String params) {
// here call your fragment's method
here do whatever you want to do it with params
}
}
Now you can call your Activity's method either from another fragment or from Adapter, whatever you want
From Fragment you can call like
((yourActivity)getActivity()).callFragmentMethod(params);
From Adapter
((yourActivity)context).callFragmentMethod(params);
Call below method on your button click..
public void replaceFragment(Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.frameContainer, fragment);
fragmentTransaction.addToBackStack(fragment.toString());
fragmentTransaction.commit();
}
pass frameContainer in constructor of your Adapter like..
new RecyclerViewAdapter(context, list, R.id.frameContainer);

How to update textview of fragment "continuously" from viewpageradpater?viewpager adapter is in main fragment

My viewpager adapter is in another fragment(i.e. in main fragment) i.e. i used viewpager in another fragment.so viewpager adapter having 2 fragments.
I am getting heart rate value continuously from main fragment and need to send it to viewpager adapter.then viewpager adapter send this value to fragment and upadate the textview here.
//Main Fragment were i initialize fragmentpageradapter with updated heart rate value:-((readingdata)samplePagerAdapter).passdata(value);
used interface to update value:-
public interface readingdata
{
void passdata(int value);
}
//Adapter code:-
public class SamplePagerAdapter extends FragmentStatePagerAdapter implements readingdata {
private final Random random = new Random();
private int mSize = 2;
private int heart_rate;
FragmentManager fm;
private Map<Integer, String> mFragmentTags;
public SamplePagerAdapter(FragmentActivity activity, FragmentManager supportFragmentManager, int heart) {
super(supportFragmentManager);
fm = supportFragmentManager;
mFragmentTags = new HashMap<Integer, String>();
}
#Override
public int getCount() {
return mSize;
}
#Override
public Fragment getItem(int position) {
Fragment f = null;
if (position == 0) {
f = new MyFragment().newInstance(heart_rate);
} else if (position == 1) {
f = new SecondFragment();
}
return f;
}
#Override
public Object instantiateItem(ViewGroup container, int position) {
Object object = super.instantiateItem(container, position);
if (object instanceof Fragment) {
Fragment fragment = (Fragment) object;
String tag = fragment.getTag();
mFragmentTags.put(position, tag);
}
return object;
}
public Fragment getFragment(int position) {
Fragment fragment = null;
String tag = mFragmentTags.get(position);
if (tag != null) {
fragment = fm.findFragmentByTag(tag);
}
return fragment;
}
#Override
public void passdata(int value) {
heart_rate=value;
}
}
//Fragment code were textview updated on regular interval
public class MyFragment extends Fragment{
private int heart_rate;
private ArcProgress arc_progress;
private TextView tv_heartrate;
private Handler handler;
private Runnable runnable;
private View view;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle saveBundle) {
view = inflater.inflate(R.layout.ecg_layout, container, false);
handler=new Handler();
arc_progress = (ArcProgress) view.findViewById(R.id.arc_progress);
tv_heartrate = (TextView) view.findViewById(R.id.tv_heart_rate);
handler=new Handler();
handler.post(runnable = new Runnable() {
#Override
public void run() {
MyFragment myFragment=new MyFragment();
arc_progress.setProgress(heart_rate);
tv_heartrate.setText(String.valueOf(heart_rate));
handler.postDelayed(this, 1000);
}
});
return view;
}
#Override
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
}
public static Fragment newInstance(int heartvalue) {
MyFragment f = new MyFragment();
f.heart_rate = heartvalue;
return f;
}
}
So how should i update textview continuously inside the fragment?
In MainFragment
private static HeartRateListener heartRateListener;
public static void setHeartRateListener(HeartRateListener listener){
heartRateListener = listener;
}
public static interface HeartRateListener{
void onHeartRate(int yourValue);
}
// Send your continuously updated value
heartRateListener.onHeartRate(yourValue);
In ViewPager Fragment (inside onViewCreated())
MainFragment.setHeartRateListener(new MainFragment.HeartRateListener() {
#Override
public void onHeartRate(int yourValue) {
// Update your textview with yourValue
}
});
create Method
public void updateScreenData(String text)
{
tv_heartrate.setText(text);
}
in fragment and then call this method from activity
make sure that fragment reference is not null whenever call this method
Take Help from this and save reference to view you are inflating
package com.mtg.workapp_v2.listing.wanted.add_wanted;
import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.TextView;
import com.mtg.classes.AddressView;
import com.mtg.classes.ListingVisibilityLayout;
import com.mtg.utils.CommonMethods;
import com.mtg.workapp.R;
public class WantedBasicInfoFragment extends Fragment implements View.OnClickListener{
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
View FragmentView ;
Context myContext;
TextView text_continue;
EditText edit_title;
EditText edit_description;
private OnFragmentInteractionListener mListener;
//this is add by ahsan according to new design
ListingVisibilityLayout listingVisibilityLayout = null;
public WantedBasicInfoFragment() {
}
public static WantedBasicInfoFragment newInstance(String param1, String param2) {
WantedBasicInfoFragment fragment = new WantedBasicInfoFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
FragmentView= inflater.inflate(R.layout.fragment_wanted_basic, container, false);
init();
return FragmentView;
}
/********************************************************************************/
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}
/********************************************************************************/
public void setListener(OnFragmentInteractionListener listener) {
this.mListener = listener;
}
/********************************************************************************/
public void setInitValues()
{
}
/***********************************************************************************/
public void updateScreenData()
{
edit_title.setText(wantedInformation.csName);
edit_description.setText(wantedInformation.csDescription);
}
/***********************************************************************************/
public void init()
{
myContext=getActivity();
text_continue=(TextView) FragmentView.findViewById(R.id.text_continue);
edit_title = (EditText) FragmentView.findViewById(R.id.edit_title);
edit_description = (EditText) FragmentView.findViewById(R.id.edit_description);
text_continue.setOnClickListener(this);
edit_title.addTextChangedListener(new TextWatcher() {
#Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
#Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
wantedInformation.csListingLanguage = CommonMethods.getInputLanguage(myContext);
}
#Override
public void afterTextChanged(Editable s) {
wantedInformation.csListingLanguage = CommonMethods.getInputLanguage(myContext);
}
});
initVisibilitySpinner();
}
/***********************************************************************************/
public void initVisibilitySpinner()
{
listingVisibilityLayout = new ListingVisibilityLayout(myContext);
View visibilityView = (View)FragmentView.findViewById(R.id.id_visibility_layout);
listingVisibilityLayout.ListingVisibilityInit(visibilityView);
}
/***********************************************************************************/
#Override
public void onClick(View view) {
int itemID = view.getId();
switch (itemID) {
case R.id.text_continue:
{
moveToNextScreen(true);
}
}
}
/***********************************************************************************/
public void moveToNextScreen(boolean isContinueClicked)
{
String csName = edit_title.getText().toString().trim();
String csDescription = edit_description.getText().toString().trim();
if(csName.length() <= 0 && csDescription.toString().length() <= 0)
{
CommonMethods.showMessageBox("", getResources().getString(R.string.id_please_enter_name_and_description), myContext);
return;
}
else if(csName.length() <= 0)
{
CommonMethods.showMessageBox("", getResources().getString(R.string.id_please_enter_name), myContext);
return;
}
else if(csDescription.length() <= 0)
{
CommonMethods.showMessageBox("", getResources().getString(R.string.id_please_enter_description), myContext);
return;
}
else if(listingVisibilityLayout.selectedProfileVisibility.csOptionID.equalsIgnoreCase("-1"))
{
CommonMethods.showMessageBox("", getResources().getString(R.string.id_select_visibility_option_msg), myContext);
return;
}
wantedInformation.csName = csName;
wantedInformation.csDescription = csDescription;
wantedInformation.visibilityOption = listingVisibilityLayout.selectedProfileVisibility;
//MH: If continue clicked then continue Button listener will be called
//MH: If only tick is clicked in Edit Mode then onUpdate listener will be called
//MH: and data will be updated before sent to api
//MH: The below statements are repeated in all fragments of Wanted
if(isContinueClicked)
mListener.continueButtonPressed(wantedInformation);
else
mListener.onUpdate(wantedInformation);
}
}

Android - Interfaces and Inner Class

I'm new to Android programming and am trying to figure out how to go about this. I have a fragment that hosts inner tabs, one of them being a ListFragment. On the tabhost fragment I have a button that calls a DialogFragment. When "Yes" is clicked on that DialogFragment I need to refresh that ListFragment if it's currently active in order to show the item added onto the list.
What is the best way to go about this? I am thinking I should put an interface on the DialogFragment and then implement the listener on the Activity which would then call the refresh in the ListFragment. I would need to be able to pull the ListFragment's tag in order to determine if it's active, however and not sure how to do that.
I just started to learn programming a few months ago and this is my first post on this site. I searched for this answer and couldn't find anything. I apologize if my methods or formatting are wrong. Any tips are appreciated, thanks.
TabFragment:
public class Items extends Fragment implements TabHost.OnTabChangeListener, ViewPager.OnPageChangeListener, View.OnClickListener {
MyPageAdapter pageAdapter;
private ViewPager mViewPager;
private TabHost mTabHost;
static final String ARG_ID = "id";
static final String name = "name";
long id;
String itemName;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.tab_test);
Bundle args = getArguments();
long id = args.getLong(ARG_ID);
String itemName = args.getString(name);
View v = inflater.inflate(R.layout.item_tab, container, false);
mViewPager = (ViewPager) v.findViewById(R.id.pager);
// Tab Initialization
//initialiseTabHost
mTabHost = (TabHost) v.findViewById(android.R.id.tabhost);
mTabHost.setup();
// TODO Put here your Tabs
List<Fragment> fragments = getFragments();
FragmentActivity context = getActivity();
this.AddTab(context, this.mTabHost, this.mTabHost.newTabSpec("ItemList").setIndicator("ItemList"));
mTabHost.setOnTabChangedListener(this);
// Fragments and ViewPager Initialization
pageAdapter = new MyPageAdapter(getChildFragmentManager(), fragments);
mViewPager.setAdapter(pageAdapter);
mViewPager.setOnPageChangeListener(this);
if (savedInstanceState == null) {
}else {
int pos = savedInstanceState.getInt("tab");
mTabHost.setCurrentTab(pos);
}
Button addItemButton = (Button) v.findViewById(R.id.addItem);
addItemButton.setOnClickListener(this);
return v;
}
public void onClick(View view) {
switch (view.getId()) {
case R.id.addItem:
DialogFragment addItem = new AddItemDialogFragment();
Bundle itemArgs = getArguments();
addItem.setArguments(itemArgs);
addItem.show(getChildFragmentManager(), "addItem");
Toast.makeText(getActivity(), "Adding Item", Toast.LENGTH_LONG).show();
break;
}
}
// Method to add a TabHost
private static void AddTab(FragmentActivity activity, TabHost tabHost, FragmentTabHost.TabSpec tabSpec) {
tabSpec.setContent(new MyTabFactory(activity));
tabHost.addTab(tabSpec);
}
// Manages the Tab changes, synchronizing it with Pages
public void onTabChanged(String tag) {
int pos = this.mTabHost.getCurrentTab();
this.mViewPager.setCurrentItem(pos);
}
#Override
public void onPageScrollStateChanged(int arg0) {
}
// Manages the Page changes, synchronizing it with Tabs
#Override
public void onPageScrolled(int arg0, float arg1, int arg2) {
int pos = this.mViewPager.getCurrentItem();
this.mTabHost.setCurrentTab(pos);
}
#Override
public void onPageSelected(int arg0) {
}
private List<Fragment> getFragments(){
List<Fragment> fList = new ArrayList<Fragment>();
// TODO Put here your Fragments
Bundle args = getArguments();
long id = args.getLong("val");
ItemList f1 = ItemList.newinstance(id);
fList.add(f1);
return fList;
}
public class MyPageAdapter extends FragmentStatePagerAdapter {
private List<Fragment> fragments;
public MyPageAdapter(FragmentManager fm, List<Fragment> fragments) {
super(fm);
this.fragments = fragments;
}
#Override
public Fragment getItem(int position) {
return this.fragments.get(position);
}
#Override
public int getCount() {
return this.fragments.size();
}
}
}
ListFragment within Tab:
public class ItemList extends ListFragment implements LoaderManager.LoaderCallbacks<Cursor> {
String DATABASE_TABLE;
String Query;
String Order;
String name;
MainActivity home;
View view;
public static MyListAdapter mAdapter;
private static Cursor c;
static ItemList newinstance(long rowId) {
ItemList itemList = new ItemList();
// Supply val input as an argument.
Bundle args = new Bundle();
args.putLong("val", rowId);
//args.putString("name", itemName);
itemList.setArguments(args);
return itemList;
}
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Bundle args = getArguments();
int itemId= (int) args.getLong("val");
mAdapter = new MyListAdapter(getActivity(), R.layout.list_row, c, from, to);
setListAdapter(mAdapter);
setListShown(false);
getLoaderManager().initLoader(itemId, null, this);
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
}
public Loader<Cursor> onCreateLoader(int id, Bundle args) {
// View progressBar = getView().findViewById(R.id.progressbar_loading);
// progressBar.setVisibility(View.VISIBLE);
return new RawCursorLoader(getActivity(), Query + Order);
}
// Called when a previously created loader has finished loading
public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
//View progressBar = getView().findViewById(R.id.progressbar_loading);
// progressBar.setVisibility(View.GONE);
// Swap the new cursor in. (The framework will take care of closing the
// old cursor once we return.)
mAdapter.swapCursor(data);
if (isResumed()) {
setListShown(true);
} else {
setListShownNoAnimation(true);
}
}
// Called when a previously created loader is reset, making the data unavailable
public void onLoaderReset(Loader<Cursor> loader) {
// This is called when the last Cursor provided to onLoadFinished()
// above is about to be closed. We need to make sure we are no
// longer using it.
mAdapter.swapCursor(null);
}
}
Dialog:
public class AddItemDialogFragment extends DialogFragment {
UpdateItemListener mListener;
public interface UpdateItemsListener {
public void onItemAdded();
}
#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 {
mListener = (UpdateItemListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement UpdateItemListener");
}
}
#Override
public Dialog onCreateDialog(Bundle savedInstanceState) {
// Use the Builder class for convenient dialog construction
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setMessage("Add " + itemName + "?")
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
postItem(ItemId);
mListener.onItemAdded();
}
})
.setNegativeButton("No", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// User cancelled the dialog
}
});
// Create the AlertDialog object and return it
return builder.create();
}
}
I was able to figure it out, my brain just got stuck for a while.
The first problem was that I was using FragmentStatePagerAdapter which does not set tags when instantiating the fragments. I set it to this since FragmentPagerAdapter was being buggy and another thread recommending extending that class instead. I was able to get it working with FragmentPagerAdapter which sets a tag. I then call getTag() during the onAttach() method of the ItemList fragment and set the variable on the activity. I then have an interface on the AddItemDialogFragment when the item is added and a listener on the activity. The listener then calls:
ItemList itemList= (ItemList)
getSupportFragmentManager().findFragmentByTag("Items")
.getChildFragmentManager().findFragmentByTag("itemListTag");
if(itemList != null) {
itemList.listChange();
}

How to create interface between Fragment and adapter?

I have fragment with ListView, say MyListFragment, and custom CursorAdapter.
I'm setting onClickListener in this adapter for the button in the list row.
public class MyListAdapter extends CursorAdapter {
public interface AdapterInterface {
public void buttonPressed();
}
...
#Override
public void bindView(final View view, final Context context, final Cursor cursor) {
ViewHolder holder = (ViewHolder) view.getTag();
...
holder.button.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
// some action
// need to notify MyListFragment
}
});
}
}
public MyListFragment extends Fragment implements AdapterInterface {
#Override
public void buttonPressed() {
// some action
}
}
I need to notify fragment when the button is pressed. How to invoke this interface?
Help, please.
Make a new constructor and an instance variable:
AdapterInterface buttonListener;
public MyListAdapter (Context context, Cursor c, int flags, AdapterInterface buttonListener)
{
super(context,c,flags);
this.buttonListener = buttonListener;
}
When the Adapter is made, the instance variable will be given the proper reference to hold.
To call the Fragment from the click:
public void onClick(View v) {
buttonListener.buttonPressed();
}
When making the Adapter, you will have to also pass your Fragment off to the Adapter. For example
MyListAdapter adapter = new MyListAdapter (getActivity(), myCursor, myFlags, this);
since this will refer to your Fragment, which is now an AdapterInterface.
Keep in mind that on orientation of the Fragment changes, it will most likely be recreated. If your Adapter isn't recreated, it can potentially keep a reference to a nonexistent object, causing errors.
Using Eventbus:
Examples:
https://github.com/kaushikgopal/RxJava-Android-Samples/tree/master/app/src/main/java/com/morihacky/android/rxjava/rxbus
or
https://github.com/greenrobot/EventBus
Using Interfaces:
I understand the current answer but needed a more clear example. Here is an example of what I used with an Adapter(RecyclerView.Adapter) and a Fragment.
Create Callback Interface:
public interface AdapterCallback {
void onMethodCallback();
}
Passing in Callback/Fragment:
This will implement the interface that we have in our Adapter. In this example, it will be called when the user clicks on an item in the RecyclerView.
In your Fragment:
public class MyFragment extends Fragment implements AdapterCallback {
private MyAdapter mMyAdapter;
#Override
public void onMethodCallback() {
// do something
}
#Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.mMyAdapter = new MyAdapter(this); // this class implements callback
}
}
Use the Callback in your Adapter:
In the Fragment, we initiated our Adapter and passed this as an argument to the constructer. This will initiate our interface for our callback method. You can see that we use our callback method for user clicks.
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private AdapterCallback mAdapterCallback;
public MyAdapter(AdapterCallback callback) {
this.mAdapterCallback = callback;
}
#Override
public void onBindViewHolder(final MyAdapter.ViewHolder viewHolder, final int i) {
// simple example, call interface here
// not complete
viewHolder.itemView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
mAdapterCallback.onMethodCallback();
}
});
}
}
or Use the Fragment in your Adapter:
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
private AdapterCallback mAdapterCallback;
public MyAdapter(Fragment fragment) {
try {
this.mAdapterCallback = ((AdapterCallback) fragment);
} catch (ClassCastException e) {
throw new ClassCastException("Fragment must implement AdapterCallback.");
}
}
#Override
public void onBindViewHolder(final MyAdapter.ViewHolder viewHolder, final int i) {
// simple example, call interface here
// not complete
viewHolder.itemView.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
try {
mAdapterCallback.onMethodCallback();
} catch (ClassCastException exception) {
// do something
}
}
});
}
}
Follow the 2 steps below for receive callback from Adapter in Fragment (or Activity)
First: In your Adapter
public class ListAdapter extends RecyclerView.Adapter < RecyclerListAdapter.ItemViewHolder > {
...
private ListAdapterListener mListener;
public interface ListAdapterListener { // create an interface
void onClickAtOKButton(int position); // create callback function
}
public RecyclerListAdapter(Context mContext, ArrayList < Items > listItems, ListAdapterListener mListener) { // add the interface to your adapter constructor
...
this.mListener = mListener; // receive mListener from Fragment (or Activity)
}
...
public void onBindViewHolder(final ItemViewHolder holder, final int position) {
holder.btnOK.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// use callback function in the place you want
mListener.onClickAtOKButton(position);
}
});
...
}
...
}
Second: In your Fragment (or Activity), there are 2 ways for implement callback method
Way 1
public MyListFragment extends Fragment {
...
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
...
ListAdapter adapter = new ListAdapter(getActivity(), listItems, new ListAdapter.ListAdapterListener() {
#Override
public void onClickAtOKButton(int position) {
Toast.makeText(getActivity(), "click ok button at" + position, Toast.LENGTH_SHORT).show();
}
});
...
}
}
Way 2
public MyListFragment extends Fragment implements ListAdapter.ListAdapterListener {
...
public void onViewCreated(View view, #Nullable Bundle savedInstanceState) {
ListAdapter adapter = new ListAdapter (getActivity(), listItems, this);
...
}
#Override
public void onClickAtOKButton(int position) {
Toast.makeText(getActivity(), "click ok button at" + position, Toast.LENGTH_SHORT).show();
}
}
This is very similar to the way an activity and a fragment should communicate. In the constructor of your adapter, pass a reference of your fragment, cast it to your interface and just call yourReference.buttonPressed() on your onClick method.
a solution for NPE is first to make conctractor in your Fragment like that
public MyFragment MyFragment(){
return this;
}
then initialize your listener is adapter like that
Lisener lisener = new MyFragment();
Make a constructor like that:
public MyAdapter(Activity activity,AlertMessageBoxOk alertMessageBoxOk) {
this.mActivity = activity;
mAlertMessageBoxOk = alertMessageBoxOk;
}
call the interface from adapter use any event
mAlertMessageBoxOk.onOkClick(5);
after that implement AlertMessageBoxOk interface to your fragment like this,
class MyFragment extends Fragment implements AlertMessageBoxOk {
#Override
public void onOkClick(int resultCode) {
if(resultCode==5){
enter code here
}
}
}

Categories