5

У меня есть фрагмент с методом setName(), который изменяет текст EditText с помощью функции setText.Доступ к методу фрагмента из действия ViewPager

Каков наилучший способ вызова этого метода из активности, которая размещает этот фрагмент с помощью ViewPager?

Другими словами, как я могу получить доступ к методам фрагмента (которые, например, изменяют макет фрагмента) из Activity, который размещает этот фрагмент с помощью ViewPager?

Я спрашиваю об этом, потому что я пробовал несколько способов, но всегда с ошибками.

+0

Вы можете попытаться создать переменную экземпляра фрагмента с 's etName() 'в вашем классе Activity. Назначьте переменную фрагменту, когда вы его создаете. вы можете затем вызвать 'fragment.setName()' из своей активности – Scott

+0

У меня возникла эта проблема, но вызов функции fragment.setName() с помощью хранимой ссылки на нее не является проблемой. Проблема в том, что из фрагмента getActivity() возвращает значение null, так что представления не могут быть доступны. Однако я могу получить доступ к представлениям из активности, а фрагмент COULD помещает информацию в представления, принадлежащие фрагменту при конфигурации. Но позже getActivity() возвращает значение null и может ли это быть чем-то, когда viewPager управляет контекстом, так что getActivity на самом деле недействителен? Итак, нужно было бы запросить представление из Viewpager? Я спрашиваю. – carl

ответ

3

Вы можете получить доступ к общедоступным методам в пределах фрагментов, хранящихся у вашего ViewPager. Вам необходимо либо (1) сохранить ссылку на Fragment при ее создании и добавить ее в список, который будет поддерживать ваш адаптер пейджера, либо (2) вам нужно получить ссылку на фрагмент из самого пейджера-адаптера. Например:

Fragment fragmentA = null; //instance variable 

fragmenA = new Fragment(); //whereever you instantiate your fragment 

Если ваш метод

public void setName(String args){ 
    //do something 
} 

все вы могли бы сделать, это вызвать этот метод из ссылки на фрагмент, принадлежащих вашей ViewPager

fragmentA.setName(args); 

Вы передаются любые аргументы вам нужно просто вызвать обычный метод. Обратите внимание, что это ТОЛЬКО работает, если вы вызываете метод внутри фрагмента из его содержащего ViewPager или FragmentActivity. Если вы хотите сделать обратный фрагмент для активности, вам нужно использовать inerface.

+0

Да, я знаю это уже. Но что, если я пытаюсь создать его, используя что-то вроде Frag1 fragment = (Frag1) mAppSectionsAdapter.getItem (0) ;? Как я должен использовать метод без исключения null-указателя? – JZweige

+0

Это как fragment.getView() всегда null! – JZweige

+0

Вы хотите получить ссылку с вашего адаптера? Я не на своем компьютере, но позже могу отправить код, если это проблема. – Rarw

8

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

Первая проблема, которую я обнаружил в ViewPager, заключается в том, что получить ссылку на фрагмент практически невозможно. Фрагменты создаются динамически в getItem(), и поэтому вы не можете установить идентификатор, и они автоматически переустанавливаются swicher, так что вы также не можете найти его по тегу. Есть некоторые способы сделать это, но все они обходные пути. (Update data in ListFragment as part of ViewPager)

То, как я решил, было использовать по существу двойной обратный вызов. Фрагмент A имеет интерфейс, реализованный основной активностью, а основная активность имеет интерфейс, реализованный с помощью фрагмента B. Напр. кнопка clink in Fragment A вызывается функция обратного вызова в главной операции, которая, в свою очередь, вызывает обратный вызов во фрагменте B. Посмотрите на код ниже. Надеюсь, я разместил все, и это поможет. Кстати, я только пробовал это с ViewPager, но я предполагаю, что он будет работать с любым сообщением Фрагмента.

Главная Avtivity Java:

import android.os.Bundle; 
import android.support.v4.app.Fragment; 
import android.support.v4.app.FragmentActivity; 
import android.support.v4.app.FragmentManager; 
import android.support.v4.app.FragmentPagerAdapter; 
import android.support.v4.view.ViewPager; 

public class MainActivity extends FragmentActivity implements FragmentA.Caller { 

    SectionsPagerAdapter mSectionsPagerAdapter; 
    ViewPager mViewPager; 
    PassCallToB passOnToB = null; 
    FragmentManager myManager = null; 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 
     mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager()); 
     mViewPager = (ViewPager) findViewById(R.id.pager); 
     mViewPager.setAdapter(mSectionsPagerAdapter); 
    } 

    public class SectionsPagerAdapter extends FragmentPagerAdapter { 

     public SectionsPagerAdapter(FragmentManager fm) { 
      super(fm); 
      MyManager = fm; 
     } 

     @Override 
     public Fragment getItem(int position) { 
      Fragment fragment = null; 
      if(position == 0) { 
       fragment = new FragmentA(); 
      } else if (position == 1) { 
       fragment = new FragmentB(); 
       passOnToB = (PassCallToB)fragment; 
      } 
      return fragment; 
     } 

     @Override 
     public int getCount() { 
      return 2; 
     } 

     @Override 
     public CharSequence getPageTitle(int position) { 
      switch (position) { 
      case 0: 
       return "Frag A"; 
      case 1: 
       return "Frag B"; 
      } 
      return null; 
     } 

     public void setCallback() { 
      List<Fragment> frags = myManager.getFragments(); 
      for(Fragment fragment : frags) { 
       if(fragment instanceof FragmentB){ 
        passOnToB = (PassCallToB)fragment; 
       } 
      } 
     } 
    } 

    public interface PassCallToB { 
     public void passItOn(); 
    } 

    @Override 
    public void CallB() { 
     if(passOnToB instanceof Fragment) 
      passOnToB.passItOn(); 
     else { 
      mSectionsPagerAdapter.setCallback(); 
      passOnToB.passItOn(); 
     } 
    } 
} 

Основная деятельность XML:

<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:id="@+id/pager" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    tools:context=".MainActivity" > 

    <android.support.v4.view.PagerTitleStrip 
     android:id="@+id/pager_title_strip" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:layout_gravity="top" 
     android:background="#33b5e5" 
     android:paddingBottom="4dp" 
     android:paddingTop="4dp" 
     android:textColor="#fff" /> 

</android.support.v4.view.ViewPager> 

Фрагмент ява:

import android.app.Activity; 
import android.os.Bundle; 
import android.support.v4.app.Fragment; 
import android.support.v4.app.FragmentActivity; 
import android.view.LayoutInflater; 
import android.view.View; 
import android.view.View.OnClickListener; 
import android.view.ViewGroup; 
import android.widget.Button; 

public class FragmentA extends Fragment { 

    Button btnCallB = null; 

    Caller listener = null; 

    public FragmentA() { 
    } 

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

     btnCallB = (Button)rootView.findViewById(R.id.btnCallB); 
     btnCallB.setOnClickListener(new OnClickListener() { 

      @Override 
      public void onClick(View view) { 
       listener.CallB(); 
      } 

     }); 

     return rootView; 
    } 

    public interface Caller { 
     public void CallB(); 
    } 

    @Override 
    public void onAttach(Activity activity) { 
     super.onAttach(activity); 
     if (activity instanceof FragmentActivity) { 
      listener = (Caller) activity; 
     } else { 
      throw new ClassCastException(activity.toString() + " must implemenet listener"); 
     } 
    } 

    @Override 
     public void onDetach() { 
     super.onDetach(); 
     listener = null; 
     } 
} 

фрагмент в 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" > 


    <TextView 
     android:id="@+id/textView1" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_alignParentLeft="true" 
     android:layout_alignParentTop="true" 
     android:text="This is Fragment A" /> 

    <Button 
     android:id="@+id/btnCallB" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_alignParentLeft="true" 
     android:layout_below="@+id/textView1" 
     android:text="Call Fragment B" /> 

</RelativeLayout> 

Фрагмент B Java:

import android.os.Bundle; 
import android.support.v4.app.Fragment; 
import android.view.LayoutInflater; 
import android.view.View; 
import android.view.ViewGroup; 
import android.widget.Toast; 

public class FragmentB extends Fragment implements MainActivity.PassCallToB { 

    public FragmentB() { 
    } 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle inState) { 
     View rootView = inflater.inflate(R.layout.fragment_b, container, false); 
     return rootView; 
    } 

    @Override 
    public void passItOn() { 
     Toast.makeText(getActivity(), "Hello from B", Toast.LENGTH_SHORT).show(); 

    } 
} 

Фрагмент B 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" > 

    <TextView 
     android:id="@+id/textView1" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:layout_alignParentLeft="true" 
     android:layout_alignParentTop="true" 
     android:text="This is Fragment B" /> 

</RelativeLayout> 
+0

Это не работает при повороте. Потому что, когда вы вращаете активность, а фрагменты воссоздаются, что также воссоздает ваш SectionsPagerAdapter, но никогда не вызывает getItem (Android воссоздает фрагменты без вызова getItem), то есть passOnToB остается null. – rve

+0

Я отредактировал мой код, чтобы он работал после поворота экрана. Трюк заключается в том, чтобы установить обратный вызов не только в getItem(), но также включить в адаптер пейджера настраиваемый метод, который будет искать через фрагменты и установить обратный вызов вручную, когда будет найден правильный фрагмент. Теперь вам нужно только проверить, установлен ли обратный вызов и установить его, если нет в методе passOn. Надеюсь, это несколько ясно. – ckn

+0

Любая идея с моей? http://stackoverflow.com/questions/39907625/why-is-accessing-textview-of-a-fragment-inside-activity-throwing-an-error – Si8

1

Фрагмент

private static FragmentName instance; 

public static synchronized FragmentName getInstance() 
{ 
    return instance; 
} 

@Override 
public void onCreate(@Nullable Bundle savedInstanceState) { 
super.onCreate(savedInstanceState); 
instance=this; 
.... 
} 

public void methodName() 
{...} 

активность

FragmentName.getInstance().methodName(); 
Смежные вопросы