Metode Android Fragment onClick button

91

Saya mencoba memanggil metode ini di onClick (View v) XML saya, tetapi tidak berfungsi dengan Fragment. Ini adalah kesalahannya.

01-17 12:38:36.840: E/AndroidRuntime(4171): java.lang.IllegalStateException: 
Could not find a method insertIntoDb(View) in the activity class main.MainActivity 
for onClick handler on view class android.widget.Button with id 'btn_conferma'

Kode Java:

public void insertIntoDb(View v) {
...
} 

XML:

<Button
        android:id="@id/btn_conferma"
        style="?android:attr/borderlessButtonStyle"
        android:layout_width="0.0dip"
        android:layout_height="45dp"
        android:layout_marginLeft="2dp"
        android:layout_weight="1.0"
        android:background="@drawable/bottoni"
        android:gravity="center_horizontal|center_vertical"
        android:onClick="insertIntoDb"
        android:text="SALVA"
        android:textColor="#ffffff"
        android:textSize="16sp" />
pengguna3160725
sumber
1
Silakan posting lebih banyak stacktrace dan kode yang relevan
Emmanuel
2
Seperti yang dinyatakan di sini developer.android.com/guide/topics/ui/controls/… , "Aktivitas yang menghosting tata letak kemudian harus menerapkan metode yang sesuai.". Dalam kasus Anda, Anda menerapkan metode yang sesuai di fragmen Anda. Karena itu, ia melontarkan IllegalStateException karena tidak bisa menemukan metode yang sesuai dalam aktivitas. Mungkin, Anda dapat menerapkan trik seperti yang ditunjukkan dalam posting ini stackoverflow.com/a/6271637/2515815
hcelaloner
Metode insertIntoDb (View) harus ada di main.MainActivity dan bukan di kelas Fragment.
betorcs
solusi terbaik stackoverflow.com/questions/7570575/…
AndroidGeek
kemungkinan duplikat dari Cara menangani klik tombol menggunakan XML onClick dalam Fragmen
Advokat Organik

Jawaban:

185

Aktivitas Anda harus ada

public void insertIntoDb(View v) {
...
} 

bukan Fragmen.

Jika Anda tidak ingin aktivitas di atas. tombol inisialisasi dalam fragmen dan setel pemroses ke hal yang sama.

<Button
    android:id="@+id/btn_conferma" // + missing

Kemudian

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

   View view = inflater.inflate(R.layout.fragment_rssitem_detail,
    container, false);
   Button button = (Button) view.findViewById(R.id.btn_conferma);
   button.setOnClickListener(new OnClickListener()
   {
             @Override
             public void onClick(View v)
             {
                // do something
             } 
   }); 
   return view;
}
Raghunandan
sumber
Hal ini menyebabkan fragmen macet dalam proyek saya yang menggunakan API 21. Adakah perbaikan / saran alternatif?
Darth Coder
@Coder saya rasa tidak. Anda perlu menunjukkan kodenya. Ini mungkin tidak terkait dengan kode ini yang diposting di sini
Raghunandan
@Sanu tidak ada hubungannya dengan lollipop pra lollipop. posting pertanyaan lain dengan detail ..
Raghunandan
Peristiwa klik tidak pernah dipicu ketika saya melakukan seperti jawaban di atas.
Ted
4
Saya sedikit terkejut dengan komentar di atas. Jangan tersinggung, tetapi hanya mengatakan "itu tidak berhasil" tanpa memposting detail apa pun sangat tidak profesional ... Dan bagi saya, "itu berhasil".
zzheng
15

Opsi lainnya adalah membuat fragmen Anda mengimplementasikan View.OnClickListener dan mengganti onClick (View v) dalam fragmen Anda. Jika Anda perlu membuat fragmen berbicara dengan aktivitas cukup tambahkan antarmuka dengan metode yang diinginkan dan minta aktivitas mengimplementasikan antarmuka dan mengganti metodenya.

public class FragName extends Fragment implements View.OnClickListener { 
    public FragmentCommunicator fComm;
    public ImageButton res1, res2;
    int c;

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_test, container, false);
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        try {
            fComm = (FragmentCommunicator) activity;
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()
                    + " must implement FragmentCommunicator");
        }
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        res1 = (ImageButton) getActivity().findViewById(R.id.responseButton1);
        res1.setOnClickListener(this);
        res2 = (ImageButton) getActivity().findViewById(R.id.responseButton2);
        res2.setOnClickListener(this);
    }
    public void onClick(final View v) { //check for what button is pressed
            switch (v.getId()) {
                case R.id.responseButton1:
                  c *= fComm.fragmentContactActivity(2);
                  break;
                case R.id.responseButton2:
                  c *= fComm.fragmentContactActivity(4);
                  break;
                default:
                  c *= fComm.fragmentContactActivity(100);
                  break;
    }
    public interface FragmentCommunicator{
        public int fragmentContactActivity(int b);
    }



public class MainActivity extends FragmentActivity implements FragName.FragmentCommunicator{
    int a = 10;
    //variable a is update by fragment. ex. use to change textview or whatever else you'd like.

    public int fragmentContactActivity(int b) {
        //update info on activity here
        a += b;
        return a;
    }
}

http://developer.android.com/training/basics/firstapp/starting-activity.html http://developer.android.com/training/basics/fragments/communicating.html

cjayem13
sumber
3
Saya melakukan ini sepanjang waktu, tetapi masih menganggapnya jelek
Alexander Farber
Saya melakukannya juga pada awalnya tetapi sekarang hampir menjadi tangan kedua; ditambah lagi, ini benar-benar membantu dalam aplikasi yang lebih kompleks, tetapi untuk sesuatu yang mendasar tampaknya itu berlebihan.
cjayem13
@ cjayem13, dapatkah Anda menjelaskan "mengapa ini berlebihan"?
eRaisedToX
9

Ini bukan masalah, ini adalah desain Android. Lihat disini :

Anda harus mendesain setiap fragmen sebagai komponen aktivitas modular dan dapat digunakan kembali. Artinya, karena setiap fragmen menentukan tata letaknya sendiri dan perilakunya sendiri dengan callback daur hidupnya sendiri, Anda dapat menyertakan satu fragmen dalam beberapa aktivitas, jadi Anda harus mendesain untuk digunakan kembali dan menghindari manipulasi langsung satu fragmen dari fragmen lain.

Solusi yang mungkin adalah melakukan sesuatu seperti ini di MainActivity Anda:

Fragment someFragment;    

...onCreate etc instantiating your fragments

public void myClickMethod(View v){
    someFragment.myClickMethod(v);
}

lalu di kelas Fragmen Anda:

public void myClickMethod(View v){
    switch(v.getid()){
       // Your code here
    }
 } 
CzarMatt
sumber
4

Yang lain telah mengatakan bahwa metode di onClick dicari dalam aktivitas, bukan fragmen. Namun, jika Anda benar-benar menginginkannya, itu adalah mungkin.

Pada dasarnya, setiap tampilan memiliki tag (mungkin null). Kami menyetel tag tampilan root ke fragmen yang meluaskan tampilan itu. Kemudian, mudah untuk mencari tampilan orang tua dan mengambil fragmen yang berisi tombol yang diklik. Sekarang, kita menemukan nama metode dan menggunakan refleksi untuk memanggil metode yang sama dari fragmen yang diambil. Mudah!

di kelas yang diperluas Fragment:

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.fragment_id, container, false);

    OnClickFragments.registerTagFragment(rootView, this); // <========== !!!!!

    return rootView;
}

public void onButtonSomething(View v) {
    Log.d("~~~","~~~ MyFragment.onButtonSomething");
    // whatever
}

semua aktivitas diturunkan dari ButtonHandlingActivity yang sama:

public class PageListActivity extends ButtonHandlingActivity

ButtonHandlingActivity.java:

public class ButtonHandlingActivity extends Activity {

    public void onButtonSomething(View v) {
        OnClickFragments.invokeFragmentButtonHandlerNoExc(v);
//or, if you want to handle exceptions:
//      try {
//          OnClickFragments.invokeFragmentButtonHandler(v);
//      } catch ...
    }

}

Itu harus mendefinisikan metode untuk semua penangan onClick xml.

com / example / customandroid / OnClickFragments.java:

package com.example.customandroid;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import android.app.Fragment;
import android.view.View;

public abstract class OnClickFragments {
    public static class FragmentHolder {
        Fragment fragment;
        public FragmentHolder(Fragment fragment) {
            this.fragment = fragment;
        }
    }
    public static Fragment getTagFragment(View view) {
        for (View v = view; v != null; v = (v.getParent() instanceof View) ? (View)v.getParent() : null) {
            Object tag = v.getTag();
            if (tag != null && tag instanceof FragmentHolder) {
                return ((FragmentHolder)tag).fragment;
            }
        }
        return null;
    }
    public static String getCallingMethodName(int callsAbove) {
        Exception e = new Exception();
        e.fillInStackTrace();
        String methodName = e.getStackTrace()[callsAbove+1].getMethodName();
        return methodName;
    }
    public static void invokeFragmentButtonHandler(View v, int callsAbove) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException {
        String methodName = getCallingMethodName(callsAbove+1);
        Fragment f = OnClickFragments.getTagFragment(v);
        Method m = f.getClass().getMethod(methodName, new Class[] { View.class });
        m.invoke(f, v);
    }
    public static void invokeFragmentButtonHandler(View v) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException {
        invokeFragmentButtonHandler(v,1);
    }
    public static void invokeFragmentButtonHandlerNoExc(View v) {
        try {
            invokeFragmentButtonHandler(v,1);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }
    public static void registerTagFragment(View rootView, Fragment fragment) {
        rootView.setTag(new FragmentHolder(fragment));
    }
}

Dan petualangan berikutnya akan menjadi kebingungan proguard ...

PS

Ini tentu saja terserah Anda untuk mendesain aplikasi Anda sehingga data tinggal di Model daripada di Aktivitas atau Fragmen (yang merupakan Pengontrol dari MVC , sudut pandang Model-View-Controller ). The View adalah apa yang Anda mendefinisikan melalui xml, ditambah kelas tampilan kustom (jika Anda mendefinisikan mereka, kebanyakan orang hanya menggunakan kembali apa yang sudah ada). Aturan praktis: jika beberapa data pasti harus selamat dari pergantian layar, itu adalah milik Model .

18446744073709551615
sumber
3
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {

    View view = inflater.inflate(R.layout.writeqrcode_main, container, false);
    // Inflate the layout for this fragment

    txt_name = (TextView) view.findViewById(R.id.name);
    txt_usranme = (TextView) view.findViewById(R.id.surname);
    txt_number = (TextView) view.findViewById(R.id.number);
    txt_province = (TextView) view.findViewById(R.id.province);
    txt_write = (EditText) view.findViewById(R.id.editText_write);
    txt_show1 = (Button) view.findViewById(R.id.buttonShow1);

    txt_show1.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Log.e("Onclick","Onclick");

            txt_show1.setVisibility(View.INVISIBLE);
            txt_name.setVisibility(View.VISIBLE);
            txt_usranme.setVisibility(View.VISIBLE);
            txt_number.setVisibility(View.VISIBLE);
            txt_province.setVisibility(View.VISIBLE);
        }
    });
    return view;
}

Kamu tidak apa-apa !!!!

Pong Petrung
sumber
3
Bisakah Anda menjelaskan bagaimana ini menjawab pertanyaan? Apa yang Anda maksud dengan kalimat Anda di akhir?
Teepeemm
3

Untuk pengguna Kotlin:

override fun onCreateView(
    inflater: LayoutInflater,
    container: ViewGroup?, 
    savedInstanceState: Bundle?) : View?
{
    // Inflate the layout for this fragment
    var myView = inflater.inflate(R.layout.fragment_home, container, false)
    var btn_test = myView.btn_test as Button
    btn_test.setOnClickListener {
        textView.text = "hunny home fragment"
    }

    return myView
}
Jayant Dhingra
sumber