2014-01-17 3 views
65

Я пытаюсь вызвать метод в моем onClick (View v) XML, но не работает с фрагментом. Это ошибка.Android Fragment onClick button Метод

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' 

MainActivity.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" /> 
+1

Пожалуйста, напишите больше о стеке и соответствующем коде – Emmanuel

+2

Как указано здесь http://developer.android.com/guide/topics/ui/controls/button.html#HandlingEvents, тогда необходимо выполнить операцию, в которой размещается макет соответствующий метод ». В вашем случае вы реализовали соответствующий метод в своем фрагменте. Из-за этого он выбрасывает IllegalStateException, потому что не может найти соответствующий метод в активности. Возможно, вы можете применить трюк, как показано в этом сообщении. Http://stackoverflow.com/a/6271637/2515815 – hcelaloner

+0

Метод insertIntoDb (View) должен быть в main.MainActivity, а не в классе Fragment. – betorcs

ответ

135

Ваша деятельность должна иметь

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

не фрагмент.

Если вы не хотите, чтобы вышеуказанное в действии. инициализировать кнопку в фрагменте и установить прослушиватель на то же самое.

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

Тогда

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

Как вы думаете, вы могли бы дать мне несколько советов/идей здесь http: //goo.gl/E37NSu – eddy

+0

Это приводит к сбою фрагмента в моем проекте, который использует API 21. Любые альтернативные исправления/предложения? –

+0

@ DarthCoder я так не думаю. Вам нужно представить код. Он не может быть связан с этим кодом, размещенным здесь – Raghunandan

4

Это не проблема, это дизайн Android. См here:

Вы должны разработать каждый фрагмент как модульные и многоразовые деятельности компонента. То есть, поскольку каждый фрагмент определяет свой собственный макет и его собственное поведение с его собственными обратными вызовами жизненного цикла, вы можете включить один фрагмент в несколько действий, поэтому вы должны проектировать для повторного использования, а избегать прямого манипулирования одним фрагментом из другого фрагмента.

Возможный обходной путь будет делать что-то подобное в вашем MainActivity:

Fragment someFragment;  

...onCreate etc instantiating your fragments 

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

, а затем в классе Фрагмент:

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

Другим вариантом может быть ваш фрагмент реализации View.OnClickListener и переопределить OnClick (View v) в пределах вашего фрагмента. Если вам нужно, чтобы ваш фрагмент разговаривал с активностью, просто добавьте интерфейс с помощью желаемого метода (-ов) и активируйте его действие и переопределите его методы.

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

+2

Я делаю это все время, но все равно думаю, что это уродливо –

+0

Я тоже сделал это поначалу, но теперь он стал почти второй рукой; плюс это действительно помогло в более сложных приложениях, но для чего-то основного, похоже, слишком много. – cjayem13

+1

В моем случае это сработало очень хорошо. Благодаря! – AlvaroSantisteban

3

Остальные уже говорили, что методы OnClick ищутся в деятельности, а не фрагменты. Тем не менее, если вы действительно этого хотите, это возможно.

В принципе, каждый вид имеет тег (возможно, null). Мы устанавливаем тег корневого представления на фрагмент, который раздувает это представление. Затем легко найти родительский взгляд и получить фрагмент, содержащий нажатую кнопку. Теперь мы узнаем имя метода и используем отражение для вызова того же метода из извлеченного фрагмента. Легко!

в классе, который простирается 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 
} 

все виды деятельности получены из того же ButtonHandlingActivity:

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

} 

Он должен определять методы для всех обработчиков xml onClick.

ком/пример/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)); 
    } 
} 

И следующее приключение будет ProGuard запутывания ...

PS

Это, конечно, зависит от вас для разработки вашего приложения, чтобы данные находились в Model, а не в действиях или фрагментах (которые являются Контроллеры от MVC, Model-View-Controller). View - это то, что вы определяете через xml, а также пользовательские классы представления (если вы их определяете, большинство людей просто повторно используют то, что уже есть). Эмпирическое правило: если некоторые данные обязательно должны пережить поворот экрана, они относятся к Модель.

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

Вы в порядке !!!!

+3

Не могли бы вы объяснить, как это отвечает на вопрос? Что вы подразумеваете под своим предложением в конце? – Teepeemm

Смежные вопросы