1

Good day all, I am working on an application where I have multiple Activities (Activities A, B, B) that inflate this fragment (TheListFragment).

This is a visual representation of what it looks like: ListView picture

Currently, I am able to change the descriptions, images, etc from the Fragment itself, but that is not what I would like to do. My goal is to have the respective activities all be able to change the fragment and use the fragment as a reusable listview. Here is some of my code:

public class TheListFragment extends Fragment {

    CustomAdapter.Holder holder;

    //The listview
    ListView listView;

    //When the view is created
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        //Inflate the add new game layout view
        View view = inflater.inflate(R.layout.list_view_holder, container, false);

        //Setup the listview and reference it to the listview id
        listView = (ListView) view.findViewById(R.id.data_list_view);

        //Set the custom adapter to the listview
        listView.setAdapter(new CustomAdapter(context);

        return view;
    }

    //This custom adapter is used to fill the respective data into the listview
    class CustomAdapter extends BaseAdapter {
        Context context;

        public CustomAdapter(Context context)) {
            this.context = context;
            inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        }

        @Override
        public int getCount() {
            return all_passed_data.size();
            //List of data. removed it for space purposes
        }

        @Override
        public Object getItem(int position) {
            return position;
        }

        @Override
        public long getItemId(int position) {
            return position;
        }

        //Holds the respective fields
        public class Holder {
            //UI Components
            TextView textview;
            ImageView imageView;

            LinearLayout linearLayout;
        }

        //Custom view
        public View getView(final int position, View convertView, ViewGroup parent) {

            //A holder object to reference the textviews and imageviews
            holder = new Holder();
            View rowView;
            rowView = inflater.inflate(R.layout.custom_list_view, null);

            holder.imageView = (ImageView) rowView.findViewById(R.id.custom_list_view_image);

            holder.textview = (TextView) rowView.findViewById(R.id.custom_list_view_game_name);

            holder.linearLayout = (LinearLayout) rowView.findViewById(R.id.left_layout);

            return rowView;
        }
    }
}

I am trying to set/ alter the listView contents (The holder class items) from within the activity that is inflating the fragment itself. IE, something along the lines of this:

public class ActivityA extends Activity{

    FragmentManager manager;
    ListFragment fragment;

    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.list_fragment_holder);

        manager = getFragmentManager();

        ListFragment fragment = (ListFragment) manager.findFragmentById(R.id.the_list_fragment);

        //These will not work at the moment, they read as null pointers
        //This will be changed dynamically depending on the activity. Could be checkbox, imageview, etc.
        fragment.holder.linearLayout.addView(holder.checkBox); 

        fragment.holder.textview.setText("I Want to set the text here");    

        //Make it do something when clicked 
        fragment.holder.textview.setOnClickListener(this); 

        //Use third party library picasso to set the image
        fragment.Picasso.with(context).load("http://www.google.com/somepicture").into(holder.imageview); 

    }
}

But I am having no luck figuring out how to accomplish this. I have read through these links: Call fragment events from activity , Android: Reusing same View object in different Activities (the case is about ad banners) , How to access UI elements created by a List Adapter from an Activity? . Do I need to implement an interface that accesses the data somehow? If so, how? Or some other means I am missing?

Community
  • 1
  • 1
PGMacDesign
  • 6,092
  • 8
  • 41
  • 78
  • Just as a recommendation, **DON'T** do that. only the Fragment should access/change the the content of the Holder. You need a abstract fragment and then a concrete version of fragments i.e. (fragment A, B o C) that implements the abstract methods of the abstrac fragment, and use the activity to create the appliate fragments as needed. I hope you undestand what i'm trying to explain here. – Gatunox Feb 11 '15 at 23:34
  • Makes sense, ok, from the other way around then, is there a way I could send requests FROM the activity TO the fragment where the fragment makes the actual chances? IE, If I send from Activity A, [textview A should be "ff7", imageViewA should be "picture", LinearLayoutA should become a checkbox and it is checked], send it to the fragment, and let the fragment actually make the changes? – PGMacDesign Feb 11 '15 at 23:43
  • sure, just create a public method within the fragment, like `public void doSomething()` and from the activity call that method once you create the concrete fragment ie. `Fragment fragment = new SomeFragment();` and then `fragmemt.doSomething;` in the activity – Gatunox Feb 11 '15 at 23:47
  • Gotcha, ok, so then with this method in the Fragment, if I want IT to be able to access the holder View items, how would you recommend I implement them? IE, If I have a list of 12 strings and those 12 strings are to update 1 instance each of the view (multiple items on the list), how would I go about getting the passed data to setup those text Views within each list View item? Just add an extra parameter to the public CustomAdapter(Context context)) and use that? (Also, please post your answer so I can select it as the right one and give you credit!) – PGMacDesign Feb 11 '15 at 23:58
  • check the complete answer, let me know if something was not clear enougth – Gatunox Feb 12 '15 at 01:00

1 Answers1

2

So here is the complete answer i think.

First let each class do its job. So Activity have Fragments and Fragments have adapters and adapters have Holders.

Create a abatract Fragment with the methods you need and then create concrete version of that fragments by making them extend the abstract one.

one of the methods in the abstract fragment should be i.e. public void doSomething();.

in the concrete version of your fragments (A B o C) tha implements the methods you do the actual "something" on the doSomething() method. in these framgents use some kind of colletion to hold the desired information (i use an arraylist). this is the actual data on the list, and holder will pupulate as needed to show on the screen. in you case lest assume that will be the text to put in the elements on the screen. This actually should be a class that represents the elemtens on the screen i.e. class GameItem that has all the elemtns that need to be shown, even the checkbox state. that represent a game.

Then in you adapter (custom adapter) you have to receive two paramenter the context and the arraylist (containg the array of text or to be 100% correct should receive the array of Games) from the holding activity. Also in this adapter create a public method called public void changeGameInfo(); is in method is where you change the content of the array you receive. The holder will acceess the element when you populate the list and grab the appropiate values to show on the screen.

In your class you create the instance of the fragment. at the correct time you call the method you create within the fragment, i.e.fregment.doSomething(); in the doSomething is where you call the adapter.changeGameInfo(); Since is the fragment that holds an instance of the Adapter. and since the adapter has a reference of the arraylist of games you passed as paramters i will know the elemetn that need to be show and that's it,

So as a resume Class XXXX calls fragment.doSomething(). In fragment.doSoemthing you call adapter.changeGameInfo() in the adapter you alter the desired game representation of the arraylist paseed as paramter. the viewholder just shows the elements, After you change the elemnts on the array list remember to call notifyDataSetChanged(); in the adpter so the actual values on the screen get updated automatically

look at examples of the viewholder patter

public class InteractiveArrayAdapter extends ArrayAdapter<Model> {

private final List<Model> list;
private final Activity context;

public InteractiveArrayAdapter(Activity context, List<Model> list) {
  super(context, R.layout.rowbuttonlayout, list);
  this.context = context;
  this.list = list;
}

static class ViewHolder {
  protected TextView text;
  protected CheckBox checkbox;
}

@Override
public View getView(int position, View convertView, ViewGroup parent) {
  View view = null;
  if (convertView == null) {
    LayoutInflater inflator = context.getLayoutInflater();
    view = inflator.inflate(R.layout.rowbuttonlayout, null);
    final ViewHolder viewHolder = new ViewHolder();
    viewHolder.text = (TextView) view.findViewById(R.id.label);
    viewHolder.checkbox = (CheckBox) view.findViewById(R.id.check);
    viewHolder.checkbox
      .setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {

        @Override
        public void onCheckedChanged(CompoundButton buttonView,
            boolean isChecked) {
          Model element = (Model) viewHolder.checkbox
              .getTag();
          element.setSelected(buttonView.isChecked());

        }
      });
  view.setTag(viewHolder);
  viewHolder.checkbox.setTag(list.get(position));
} else {
  view = convertView;
  ((ViewHolder) view.getTag()).checkbox.setTag(list.get(position));
}
ViewHolder holder = (ViewHolder) view.getTag();
holder.text.setText(list.get(position).getName());
holder.checkbox.setChecked(list.get(position).isSelected());
return view;
}
} 
Gatunox
  • 532
  • 4
  • 14