onClick fragments could not find method
Asked Answered
E

2

5

Im trying to create a ToDo list. I will admit Im still learning how to use fragments but I think my problem is a conflict with how fragments are designed. Right now I have a fragment for tasks. Where I will be adding in tasks and there is a List under. When I type in I click the add button and it should show up on the list. I also have an list_inner_view where there is a check box.

Right now in the xml I have the android:onClick = "addTaskNow" method invoked.

Here is my code.

My fragment_tasks.xml

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".FragmentTasks" >

    <EditText
        android:id="@+id/editText1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:ems="10" >

        <requestFocus />
    </EditText>

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_alignParentTop="true"
        android:layout_marginRight="14dp"
        android:text="Add" 
        android:onClick="addTaskNow"/>

    <ListView
        android:id="@+id/list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_below="@+id/button1" >
    </ListView>

</RelativeLayout>

My FragmentTasks.java

package com.example.navbar;

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

import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.Toast;

/**
 * A simple {@link Fragment} subclass.
 * 
 */
public class FragmentTasks extends Fragment {

    public FragmentTasks() {
        // Required empty public constructor
    }

    protected TaskerDbHelper db;
    List<Task> list;
    MyAdapter adapt;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View rootView = inflater.inflate(R.layout.fragment_tasks, container, false);
        //return inflater.inflate(R.layout.fragment_tasks, container, false);
        db = new TaskerDbHelper(getActivity());
        list = db.getAllTasks();
        adapt = new MyAdapter(getActivity(), R.layout.list_inner_view, list);
        ListView listTask = (ListView) rootView.findViewById(R.id.list);
        listTask.setAdapter((ListAdapter) adapt);

        Button b = (Button) rootView.findViewById(R.id.button1);
        return rootView;
    }


    public void addTaskNow(View v) {
        EditText t = (EditText) v.findViewById(R.id.editText1);


        String s = t.getText().toString();
        if (s.equalsIgnoreCase("")) {
            Toast.makeText(getActivity(), "enter the task description first!!",
                    Toast.LENGTH_LONG);
        } else {
            Task task = new Task(s, 0);
            db.addTask(task);
            Log.d("tasker", "data added");
            t.setText("");
            adapt.add(task);
            adapt.notifyDataSetChanged();
        }

    }

    private class MyAdapter extends ArrayAdapter<Task> {

        Context context;
        List<Task> taskList = new ArrayList<Task>();
        int layoutResourceId;

        public MyAdapter(Context context, int layoutResourceId,
                List<Task> objects) {
            super(context, layoutResourceId, objects);
            this.layoutResourceId = layoutResourceId;
            this.taskList = objects;
            this.context = context;
        }

        /**
         * This method will DEFINe what the view inside the list view will
         * finally look like Here we are going to code that the checkbox state
         * is the status of task and check box text is the task name
         */
        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            CheckBox chk = null;
            if (convertView == null) {
                LayoutInflater inflater = (LayoutInflater) context
                        .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                convertView = inflater.inflate(R.layout.list_inner_view,
                        parent, false);
                chk = (CheckBox) convertView.findViewById(R.id.checkBox1);
                convertView.setTag(chk);

                chk.setOnClickListener(new View.OnClickListener() {

                    @Override
                    public void onClick(View v) {
                        CheckBox cb = (CheckBox) v;
                        Task changeTask = (Task) cb.getTag();
                        changeTask.setStatus(cb.isChecked() == true ? 1 : 0);
                        db.updateTask(changeTask);
                        /*Toast.makeText(
                                getApplicationContext(),
                                "Clicked on Checkbox: " + cb.getText() + " is "
                                        + cb.isChecked(), Toast.LENGTH_LONG)
                                .show();
                    } */

                }});
            } else {
                chk = (CheckBox) convertView.getTag();
            }
            Task current = taskList.get(position);
            chk.setText(current.getTaskName());
            chk.setChecked(current.getStatus() == 1 ? true : false);
            chk.setTag(current);
            Log.d("listener", String.valueOf(current.getId()));
            return convertView;


    }




}}
Enforcement answered 11/8, 2014 at 20:30 Comment(0)
C
5

I've always found using the android:onClick property in layout files to make the code difficult to navigate. The reason behind your code not working is likely due to @Lena Bru's answer (The method needs to be in the activity).

I would recommend you do the following:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    // ...

    Button b = (Button) rootView.findViewById(R.id.button1);
    b.setOnClickListener(mButtonClickListener);
    return rootView;
}

private OnClickListener mButtonClickListener = new OnClickListener() {
    public void onClick(View v) {
        addTaskNow();
    }
}

Then remove the android:onClick property from fragment_tasks.xml.

In response to your previous comment, you would have had an activity implement onClick, and specified in the xml file to point to onClick. In general I find it's usually better to avoid having your fragments/activities implementing your click listeners, because it causes confusion when there are multiple buttons.

Additionally, to avoid a NullPointerException in addTaskNow, you need to change a couple things. You are calling v.findViewById(R.id.editText1), which is going to return null. This is because findViewById can only return views which are contained inside that view. The view you are passing into addTaskNow is going to be the button, not your root view, which contains the R.id.editText1.

To resolve this, your best option is to make the an EditText member variable in your fragment, and initialize it in onCreateView with R.id.editText1, like you do with your button. As a result, you no longer need a View as a parameter of addTaskNow.

Cravat answered 12/8, 2014 at 2:24 Comment(2)
Thanks! That problem is fixed but now I have a null pointer exception error in the addTaskNow method. Specifically at the String s = t.getText().toString();Enforcement
Oh, that's because your findViewById(R.id.editText1) is returning null. I'll update the answer.Cravat
L
14

the method "addTaskNow" needs to be inside the activity the fragment was added to. If you want the fragment to handle the click you either need to forward the click listener to the fragment, or set the click listener inside the fragment. onClick works only for activities, not fragments.

Luck answered 11/8, 2014 at 20:35 Comment(2)
Thank you for your swift response. So I implemented OnClickListner and it had to add unimplemented methods. So it created a onClick(View v) method. I removed the addTaskNow method and copied and pasted what was inside that into the OnClick method. It doesnt work. Can you just explain a little more on what I have to do. Thanks!Enforcement
can you elaborate on the statement "it doesnt work"? the app crashes? the method isnt executed ?Luck
C
5

I've always found using the android:onClick property in layout files to make the code difficult to navigate. The reason behind your code not working is likely due to @Lena Bru's answer (The method needs to be in the activity).

I would recommend you do the following:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    // ...

    Button b = (Button) rootView.findViewById(R.id.button1);
    b.setOnClickListener(mButtonClickListener);
    return rootView;
}

private OnClickListener mButtonClickListener = new OnClickListener() {
    public void onClick(View v) {
        addTaskNow();
    }
}

Then remove the android:onClick property from fragment_tasks.xml.

In response to your previous comment, you would have had an activity implement onClick, and specified in the xml file to point to onClick. In general I find it's usually better to avoid having your fragments/activities implementing your click listeners, because it causes confusion when there are multiple buttons.

Additionally, to avoid a NullPointerException in addTaskNow, you need to change a couple things. You are calling v.findViewById(R.id.editText1), which is going to return null. This is because findViewById can only return views which are contained inside that view. The view you are passing into addTaskNow is going to be the button, not your root view, which contains the R.id.editText1.

To resolve this, your best option is to make the an EditText member variable in your fragment, and initialize it in onCreateView with R.id.editText1, like you do with your button. As a result, you no longer need a View as a parameter of addTaskNow.

Cravat answered 12/8, 2014 at 2:24 Comment(2)
Thanks! That problem is fixed but now I have a null pointer exception error in the addTaskNow method. Specifically at the String s = t.getText().toString();Enforcement
Oh, that's because your findViewById(R.id.editText1) is returning null. I'll update the answer.Cravat

© 2022 - 2024 — McMap. All rights reserved.