Android Fragment onClick düğmesi Yöntemi


91

OnClick (View v) XML'imdeki yöntemi çağırmaya çalışıyorum, ancak Fragment ile çalışmıyor. Bu hata.

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'

Java kodu:

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" />

1
Lütfen yığın izini ve ilgili kodu daha fazla gönderin
Emmanuel

2
Burada developer.android.com/guide/topics/ui/controls/… ' de belirtildiği gibi , "Düzeni barındıran Etkinlik daha sonra ilgili yöntemi uygulamalıdır." Sizin durumunuzda, parçanıza karşılık gelen yöntemi uyguladınız. Bu nedenle, etkinlikte karşılık gelen yöntemi bulamadığından IllegalStateException oluşturur. Belki, bu yazıda gösterildiği gibi bir numara uygulayabilirsiniz. Stackoverflow.com/a/6271637/2515815
hcelaloner

İnsertIntoDb (View) yöntemi, Fragment sınıfında değil, main.MainActivity'de olmalıdır.
betorcs


Yanıtlar:


187

Aktiviteniz olmalıdır

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

Parça değil.

Yukarıdakileri aktivitede istemiyorsanız. parçadaki düğmeyi başlatın ve dinleyiciyi aynı şekilde ayarlayın.

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

Sonra

@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;
}

Bu, parçanın API 21 kullanan projemde çökmesine neden oluyor. Herhangi bir alternatif düzeltme / öneri var mı?
Darth Coder

@DarthCoder sanmıyorum. Kodu sunmanız gerekiyor. Burada yayınlanan bu kodla ilgili olmayabilir
Raghunandan

@Sanu'nun lolipop öncesi lolipop ile ilgisi yok. ayrıntılarla başka bir soru gönderin ..
Raghunandan

Yukarıdaki yanıtı yaptığımda tıklama etkinliği asla tetiklenmiyor.
Ted

4
Yukarıdaki yorumlar beni biraz şaşırttı. Alınma ama herhangi bir ayrıntı göndermeden sadece "işe yaramıyor" demek hiç profesyonelce değil ... Ve bana gelince, "sadece işe yarıyor".
zzheng

15

Diğer bir seçenek, parçanızın View.OnClickListener uygulamasını uygulaması ve parçanızın içindeki onClick (View v) öğesini geçersiz kılması olabilir. Parçanızın etkinlikle konuşmasını istiyorsanız, sadece istenen yöntem (ler) ile bir arabirim ekleyin ve etkinliğin arabirimi uygulamasını ve yöntem (ler) ini geçersiz kılmasını sağlayın.

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


3
Bunu her zaman yapıyorum ama yine de bunun çirkin olduğunu düşünüyorum
Alexander Farber

İlk başta ben de yaptım ama şimdi neredeyse ikinci el oldu; artı aslında daha karmaşık uygulamalarda yardımcı oldu, ancak temel bir şey için aşırı gibi görünüyor.
cjayem13

@ cjayem13, lütfen "neden aşırı derecede öldürme olduğunu" açıklar mısınız?
eRaisedToX

9

Bu bir sorun değil, bu bir Android tasarımı. Buraya bakın :

Her bir parçayı modüler ve yeniden kullanılabilir bir etkinlik bileşeni olarak tasarlamalısınız. Yani, her parça kendi düzenini ve kendi davranışını kendi yaşam döngüsü geri aramalarıyla tanımladığı için, bir parçayı birden çok etkinliğe dahil edebilirsiniz, bu nedenle yeniden kullanım için tasarlamalı ve bir parçayı başka bir parçadan doğrudan değiştirmekten kaçınmalısınız.

Olası bir çözüm, MainActivity'nizde şuna benzer bir şey yapmak olabilir:

Fragment someFragment;    

...onCreate etc instantiating your fragments

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

ve ardından Fragment sınıfınızda:

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

4

Diğerleri, onClick'teki yöntemlerin parçalarda değil etkinliklerde arandığını zaten söyledi. Yine de, gerçekten istiyorsan , mümkün.

Temel olarak, her görünümün bir etiketi vardır (muhtemelen boştur). Kök görünümün etiketini bu görünümü şişiren parçaya ayarladık. Ardından, görünüm üst öğelerini aramak ve tıklanan düğmeyi içeren parçayı almak kolaydır. Şimdi, yöntemin adını buluyoruz ve aynı yöntemi alınan parçadan çağırmak için yansımayı kullanıyoruz. Kolay!

genişleyen bir sınıfta 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
}

tüm etkinlikler aynı ButtonHandlingActivity'den türetilir:

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 ...
    }

}

Tüm xml onClick işleyicileri için yöntemler tanımlaması gerekir.

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));
    }
}

Ve bir sonraki macera proguard şaşırtma olacak ...

PS

Verilerin yaşayan böylece uygulama tasarlamak için size elbette kadar taşımaktadır Modeli ziyade (vardır Etkinlikler veya Fragments içinde Kontrolörler gelen MVC , Model-View-Controller bakış açısından). Görünüm Eğer xml yoluyla tanımlamak, artı özel görünüm sınıfları (bunları tanımlarsanız, çoğu insan sadece zaten ne olduğunu yeniden) budur. Dikkat etmeniz gereken bir kural: bazı veriler kesinlikle ekran dönüş hayatta gerekiyorsa, ait oldukları Modeli .


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;
}

Tamamsın !!!!


3
Bunun soruyu nasıl yanıtladığını açıklayabilir misiniz? Sonundaki cümlenizle neyi kastediyorsunuz?
Teepeemm

3

Kotlin kullanıcıları için:

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
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.