0

I'd like to be able to run a method from the HistoryFragment class in the HistoryAdapter class. I have commented the location where I would like to run this method. If you can see another way around what I am attempting to do I'm all ears. I wish to make the text view display "No History Available" when the item list is empty (there is no data being displayed). Would love to hear your input! Thanks

Here is my adapter class to create a custom listview:

package uk.co.rascagneres.clocking_app;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ListAdapter;
import android.widget.TextView;

import java.util.ArrayList;

/**
 * Created by Jacques on 08/08/2016.
 */
public class HistoryAdapter extends BaseAdapter implements ListAdapter{
    private  ArrayList<String> list = new ArrayList<String>();
    private Context context;
    public ArrayList<String> idArray = new ArrayList<String>();
    DatabaseHandler db;


    public HistoryAdapter (ArrayList<String> list, Context context, ArrayList<String> idArray, DatabaseHandler db){
        this.list = list;
        this.context = context;
        this.idArray = idArray;
        this.db = db;
    }

    @Override
    public int getCount(){
        return list.size();
    }

    @Override
    public Object getItem(int pos){
        return list.get(pos);
    }

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

    @Override
    public View getView(final int position, View convertView, ViewGroup parent){
        View view = convertView;
        if(view == null){
            LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            view = inflater.inflate(R.layout.history_list, null);
        }
        final View innerView = view;
        TextView listItemText = (TextView)view.findViewById(R.id.list_item_string);
        listItemText.setText(list.get(position));

        Button deleteBtn = (Button)view.findViewById(R.id.delete_btn);

        deleteBtn.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                db.deleteRowID(Integer.parseInt(idArray.get(position)));
                list.remove(position);
                notifyDataSetChanged();
                idArray.remove(position);
                //RUN setText() in HistoryFragment from here!
            }
        });
        return view;
    }
}

Here is my HistoryFragment class:

package uk.co.rascagneres.clocking_app;

import android.app.Fragment;
import android.database.Cursor;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

/**
 * Created by Jacques on 03/08/2016.
 */
public class HistoryFragment extends Fragment {
    DatabaseHandler db;
    View myView;
    ArrayList<String> historyArray = new ArrayList<String>();
    ArrayList<String> idArray = new ArrayList<String>();



    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        myView = inflater.inflate(R.layout.history_layout, container, false);
        db = new DatabaseHandler(getActivity());

        ArrayList<String> list = insertData();

        HistoryAdapter adapter = new HistoryAdapter(list, getActivity(), idArray, db);

        ListView lView = (ListView)myView.findViewById(R.id.listView);
        lView.setAdapter(adapter);
        return myView;
    }

    public ArrayList<String> insertData(){
        Cursor c = db.getAllData();
        ArrayList<String> list = new ArrayList<String>();
        while(c.moveToNext()) {
            int id = c.getInt(0);
            long in = c.getLong(1);
            long out = c.getLong(2);
            String outTime;

            if(out == 0){
                outTime = "N/A";
            }else{
                outTime = ClockingFragment.getDate(out, "HH:mm");
            }

            String date = ClockingFragment.getDate(in, "EEE, MMM d");
            String inTime = ClockingFragment.getDate(in, "HH:mm");

            historyArray.add(date + "\n Clocked In: " + inTime + "\n Clocked Out: " + outTime + "\n");
            idArray.add(String.valueOf(id));
        }
        TextView histAvail = (TextView)myView.findViewById(R.id.noHist);
        if (historyArray.isEmpty()){
            histAvail.setText("No History Available!");
        }else {
            histAvail.setText("");
        }
        return historyArray;
    }

    public ArrayList<String> getIdArray(){
        System.out.println(idArray);
        return idArray;
    }

    public void setText(){
        TextView histAvail = (TextView)myView.findViewById(R.id.noHist);
        histAvail.setText("No History Available!");
    }


}
  • Sounds like you might want look into the empty view property of ListView: http://cyrilmottier.com/2011/06/20/listview-tips-tricks-1-handle-emptiness/ – Kevin Coppock Aug 09 '16 at 23:07
  • @kcoppock Yes, its not that part thats difficult. Its the setting the textview from inside HistoryAdapter thats the issue – Jacques Rascagneres Aug 09 '16 at 23:09
  • Why do you want to do it from the adapter though? If you configure your empty view from the fragment, it should display automatically when the adapter is empty. – Kevin Coppock Aug 09 '16 at 23:09
  • @kcoppock You can see that I have that already. Ctrl-F histAvail,setText -- This is however in the insertData method which is only ran when the fragment is created. I wanted it in the adapter because the code ran when the button is pressed is in there – Jacques Rascagneres Aug 09 '16 at 23:12
  • Possible duplicate of [How to create interface between Fragment and adapter?](http://stackoverflow.com/questions/15444375/how-to-create-interface-between-fragment-and-adapter) – Janus Varmarken Aug 09 '16 at 23:34

1 Answers1

1

Updated: Create a interface. Like this:

HistoryAdapterListener.java

public interface HistoryAdapterListener {
    void callSetText();
}

In your adapter create objects for HistoryAdapterListener and Context.(Just below line to your DatabaseHandler db)

private HistoryAdapterListener mHistoryAdapterListener;
private Context mContext;

And set them in your constructor.We are going to pass in the HistoryFragment instance for the HistoryAdapterListener parameter (see how the fragment is updated to implement the interface below).

public HistoryAdapter (ArrayList<String> list, Context context, ArrayList<String> idArray, DatabaseHandler db, HistoryAdapterListener listener){
        this.list = list;
        this.context = context;
        this.idArray = idArray;
        this.db = db;
        //here my codes begin
        mContext = context;
        mHistoryAdapterListener = listener;
        //here it is ended
    }

We are still in your adapter. We are not done yet. Lets call interface method.

 @Override
    public View getView(final int position, View convertView, ViewGroup parent){
        ...
        deleteBtn.setOnClickListener(new View.OnClickListener(){
            @Override
            public void onClick(View v){
                ...
                //RUN setText() in HistoryFragment from here!
                if(mHistoryAdapterListener != null){
                mHistoryAdapterListener.callSetText();
                }
            }
        });
        return view;
    }

Now. We call a interface method in your adapter. And we set the interface object to reference of a creator context. So now implementing interface to your fragment so when the interface method will call, your implement method will trigger. In your fragment, first implement the interface.

public class HistoryFragment extends Fragment implements HistoryAdapterListener{ 
... 
}

After doing this Android Studio will warn you to override methods of implemented class. So again in your fragment override the implemented interface method.

@Override
public void callSetText(){
setText();
}

That's it!

edit: Sorry. I didn't use IDE for this answer. There is some mistakes. I updated. Go check again.

Eren Utku
  • 1,731
  • 1
  • 18
  • 27
  • I get this error: java.lang.ClassCastException: uk.co.rascagneres.clocking_app.MainActivity cannot be cast to uk.co.rascagneres.clocking_app.HistoryAdapterListener at uk.co.rascagneres.clocking_app.HistoryAdapter.(HistoryAdapter.java:32) Line 32 = mHistoryAdapterListener = (HistoryAdapterListener) context; – Jacques Rascagneres Aug 09 '16 at 23:22
  • @JacquesRascagneres there is a small mistake in the solution proposed here. You need to have an explicit HistoryAdapterListener parameter in your HistoryAdapter constructor and pass in your HistoryFragment instance as the parameter-value. I submitted an edit that fixes this, but it is still pending. Best – Janus Varmarken Aug 09 '16 at 23:27
  • @JanusVarmarken Perhaps post the edits on pastebin and link them to me? – Jacques Rascagneres Aug 09 '16 at 23:28
  • @JacquesRascagneres No need to do that. What you need is already described here: http://stackoverflow.com/questions/15444375/how-to-create-interface-between-fragment-and-adapter – Janus Varmarken Aug 09 '16 at 23:35
  • @JanusVarmarken I'm not really sure whats happening in that one. Its confusing me a little – Jacques Rascagneres Aug 09 '16 at 23:40
  • @JacquesRascagneres Hey. I updated my answer. Go and check again. @ Janus Varmarken thanks for suggestions. I dont know how to accept that. I really look but i could not find. – Eren Utku Aug 10 '16 at 06:53
  • @ErenUtku if the update is just adding the variable types I already worked that out, still getting the error – Jacques Rascagneres Aug 10 '16 at 09:35
  • @JacquesRascagneres No. I updated your constructor method also. Probably you are calling your adapter in your MainActivity. You have to call adapter in your fragment. – Eren Utku Aug 10 '16 at 11:24