【问题标题】:Call an activity method from a fragment从片段调用活动方法
【发布时间】:2012-09-21 12:05:18
【问题描述】:

尝试从片段调用我的活动中的方法。我希望片段提供方法数据并在方法返回时获取数据。我想实现类似于调用静态方法,但不使用静态,因为它会在活动中产生问题。

对 Fragment 不熟悉,所以我需要一个简单的教学解释!

谢谢!

【问题讨论】:

    标签: android android-fragments


    【解决方案1】:

    从片段到活动:

    ((YourActivityClassName)getActivity()).yourPublicMethod();
    

    从活动到片段:

    FragmentManager fm = getSupportFragmentManager();
    
    //if you added fragment via layout xml
    YourFragmentClass fragment = (YourFragmentClass)fm.findFragmentById(R.id.your_fragment_id);
    fragment.yourPublicMethod();
    

    如果您通过代码添加片段并在添加片段时使用tag 字符串,请改用findFragmentByTag

    YourFragmentClass fragment = (YourFragmentClass)fm.findFragmentByTag("yourTag");
    

    【讨论】:

    • 要小心,因为如果演员表不起作用会发生意想不到的事情......:S
    • 为了避免演员阵容问题,请使用:Activity act = getActivity(); if (act instanceof YourActivityClassName) ((YourActivityClassName) act).yourPublicMethod(); }
    • 投射 Activity 是糟糕的设计和不安全的。 Fragment 不限于特定的 Activity。
    • Fragments 意味着可以在任何 Activity 中重复使用和设置。如果我有 5 个活动使用相同的片段怎么办? Marco 的答案是正确的,也是片段间和 Activity-Fragment 通信的良好实践。
    • @Kay 不一定。片段可以用作任何更大活动的“片段”。例如,创建响应式 UI。我很少使用相同的片段并将其附加到不同的活动主机。
    【解决方案2】:

    您可能应该尝试将片段与活动分离,以防您想在其他地方使用它。您可以通过创建您的活动实现的接口来做到这一点。

    所以你会定义一个如下所示的接口:

    例如,假设您想给活动一个字符串并让它返回一个整数:

    public interface MyStringListener{
        public Integer computeSomething(String myString);
    }
    

    这可以在片段或单独的文件中定义。

    然后您将让您的活动实现该接口。

    public class MyActivity extends FragmentActivity implements MyStringListener{
    
      @Override
      public Integer computeSomething(String myString){
       /** Do something with the string and return your Integer instead of 0 **/ 
       return 0;
      }
    
    }
    

    然后在您的片段中,您将有一个 MyStringListener 变量,您将在片段的 onAttach(Activity activity) 方法中设置侦听器。

    public class MyFragment {
    
            private MyStringListener listener;
    
            @Override
            public void onAttach(Context context) {
                super.onAttach(context);
                try {
                    listener = (MyStringListener) context;
                } catch (ClassCastException castException) {
                    /** The activity does not implement the listener. */
                }
            }
    
        }
    

    编辑(17.12.2015):onAttach(Activity activity) is deprecated, use onAttach(Context context) instead, it works as intended

    第一个答案肯定有效,但它将您当前的片段与主机活动结合起来。如果您想在另一个活动中使用它,将片段与主机活动分离,这是一种很好的做法。

    【讨论】:

    • 对于其他人来说,虽然公认的答案显然确实有效,但从设计的角度来看,这是更好、更安全的方法。
    • 这个答案在代码设计方面要好得多。如果 Activity 被错误地投射,它也不会导致崩溃
    • +1 但我不会在 onAttach 中使用 try-catch。让它失败。如果监听器是可选的(也就是说,失败是不合适的),在片段中添加一个 set/addListener 方法。
    • 对面通讯请见:developer.android.com/training/basics/fragments/…。使用片段的接口(这也是执行片段->活动通信的安全方法,如上所述),如果您想根据片段->活动采取行动,您也可以从您的活动中调用片段中的方法通讯。
    • 我认为 MyFragment 覆盖 onDetach 并将侦听器设置为 null 以避免内存泄漏也很重要。
    【解决方案3】:

    对于 Kotlin 开发人员

    (activity as YourActivityClassName).methodName()
    

    对于 Java 开发人员

    ((YourActivityClassName) getActivity()).methodName();
    

    【讨论】:

    • 如果我们运行这段代码,它会在 kotlin 中出错。还有其他方法吗?
    • 当我运行它时。我得到 ActivityClass 的空值,我认为这不是在 kotlin 中执行此操作的正确方法,即使没有错误。或者可能是一个错误?
    • @JakeGarbo 正确的方式,否则 12 人没有投票给它。第二件事有时 getActivity() 返回 null 检查那些关于 SO 的问题。
    【解决方案4】:

    在我了解更多片段的工作原理后更新。每个片段都属于一个父活动。所以只需使用:

    getActivity().whatever
    

    从片段内部。这是一个更好的答案,因为您避免了多余的演员表。如果您无法使用此解决方案避免演员阵容,请使用以下解决方案。

    ============

    你要做的就是投射到外部活动

    ((MainActivity) getActivity()).Method();
    

    创建一个新实例会混淆 android 框架并且它无法识别它。 另见:

    https://stackoverflow.com/a/12014834/1984636

    https://stackoverflow.com/a/2042829/1984636

    【讨论】:

      【解决方案5】:

      虽然我完全喜欢 Marco 的回答,但我认为公平地指出,您也可以使用基于发布/订阅的框架来实现相同的结果,例如,如果您使用事件总线,您可以执行以下操作

      片段:

      EventBus.getDefault().post(new DoSomeActionEvent()); 
      

      活动:

       @Subscribe
      onSomeActionEventRecieved(DoSomeActionEvent doSomeActionEvent){
      //Do something
      
      }
      

      【讨论】:

        【解决方案6】:

        在 kotlin 中,您可以从片段中调用活动方法,如下所示:

        var mainActivity: MainActivity = activity as MainActivity
                mainActivity.showToast() //Calling show toast method of activity
        

        【讨论】:

          【解决方案7】:

          感谢@BIJAY_JHA 和@Manaus。我使用 Kotlin 版本来调用我的 signIn() 方法,该方法位于 Activity 中并且我从 Fragment 调用。我在 Android 中使用导航架构,因此侦听器接口模式不在片段中:

           (activity as MainActivity).signIn() 
          

          【讨论】:

            【解决方案8】:

            我是这样做的:

            首先制作界面

            interface NavigationInterface {
                fun closeActivity()
            }
            

            接下来确保活动实现接口并覆盖接口方法

            class NotesActivity : AppCompatActivity(), NavigationInterface {
            
                override fun onCreate(savedInstanceState: Bundle?) {
                    super.onCreate(savedInstanceState)
                    setContentView(R.layout.activity_notes)
                    setSupportActionBar(findViewById(R.id.toolbar))
                }
            
                override fun closeActivity() {
                    this.finish()
                }
            }
            

            然后确保在片段中创建接口监听器

            private lateinit var navigationInterface: NavigationInterface
            
            override fun onCreateView(
                    inflater: LayoutInflater, container: ViewGroup?,
                    savedInstanceState: Bundle?
            ): View? {
                //establish interface communication
                activity?.let {
                    instantiateNavigationInterface(it)
                }
                // Inflate the layout for this fragment
                return inflater.inflate(R.layout.fragment_notes_info, container, false)
            }
            
            private fun instantiateNavigationInterface(context: FragmentActivity) {
                navigationInterface = context as NavigationInterface
            }
            

            然后你可以像这样拨打电话:

            view.findViewById<Button>(R.id.button_second).setOnClickListener {
                navigationInterface.closeActivity()
            }
            

            【讨论】:

              【解决方案9】:

              要通过片段访问在 Activity 中声明的函数,请使用接口,如 marco 的回答所示。

              如果您没有标签或 id,则可以通过您的 Activity 访问在 Fragment 中声明的函数

              private void setupViewPager(ViewPager viewPager) {
                  //fragmentOne,fragmentTwo and fragmentThree are all global variables
                  fragmentOne= new FragmentOne();
                  fragmentTwo= new FragmentTwo();
                  fragmentThree = new FragmentThree();
              
                  viewPagerAdapteradapter = new ViewPagerAdapter(getSupportFragmentManager());
                  viewPagerAdapteradapter.addFragment(fragmentOne, "Frag1");
                  viewPagerAdapteradapter.addFragment(fragmentTwo, "Frag2");
                  viewPagerAdapteradapter.addFragment(fragmentThree, "Frag3");
              
                  //viewPager has to be instantiated when you create the activity:
                  //ViewPager viewPager = (ViewPager)findViewById(R.id.pager);
                  //setupViewPager(viewPager);
                  //Where R.id.pager is the id of the viewPager defined in your activity's xml page.
              
                  viewPager.setAdapter(viewPagerAdapteradapter);
              
              
                  //frag1 and frag2 are also global variables
                  frag1 = (FragmentOne)viewPagerAdapteradapter.mFragmentList.get(0);
                  frag2 = (FragmentTwo)viewPagerAdapteradapter.mFragmentList.get(1);;
              
              
                  //You can use the variable fragmentOne or frag1 to access functions declared in FragmentOne
              
              
              }
              

              这是 ViewpagerAdapterClass

                  class ViewPagerAdapter extends FragmentPagerAdapter {
                  public final List<Fragment> mFragmentList = new ArrayList<>();
                  private final List<String> mFragmentTitleList = new ArrayList<>();
              
                  public ViewPagerAdapter(FragmentManager manager) {
                      super(manager);
                  }
              
                  @Override
                  public Fragment getItem(int position) {
                      return mFragmentList.get(position);
                  }
              
                  @Override
                  public int getCount() {
                      return mFragmentList.size();
                  }
              
                  public void addFragment(Fragment fragment, String title) {
                      mFragmentList.add(fragment);
                      mFragmentTitleList.add(title);
                  }
              
                  @Override
                  public CharSequence getPageTitle(int position) {
                      return mFragmentTitleList.get(position);
                  }
              }
              

              这个答案适合像我这样的菜鸟。祝你有美好的一天。

              【讨论】:

                【解决方案10】:

                这是来自 Fragment 类...

                ((KidsStoryDashboard)getActivity()).values(title_txt,bannerImgUrl);
                

                来自活动类的代码...

                 public void values(String title_txts, String bannerImgUrl) {
                    if (!title_txts.isEmpty()) {
                
                //Do something to set text 
                    }
                    imageLoader.displayImage(bannerImgUrl, htab_header_image, doption);
                }
                

                【讨论】:

                  【解决方案11】:

                  我一直在寻找最好的方法来做到这一点,因为并非我们要调用的每个方法都位于具有相同 Activity Parent 的 Fragment 中。

                  在你的片段中

                  public void methodExemple(View view){
                  
                          // your code here
                  
                          Toast.makeText(view.getContext(), "Clicked clicked",Toast.LENGTH_LONG).show();
                      }
                  

                  在你的活动中

                  new ExempleFragment().methodExemple(context); 
                  

                  【讨论】:

                    【解决方案12】:

                    我已经尝试了这个线程中显示的所有方法,但没有一个对我有用,试试这个。它对我有用。

                    ((MainActivity) getContext().getApplicationContext()).Method();
                    

                    【讨论】:

                      【解决方案13】:
                      ((your_activity) getActivity).method_name()
                      

                      your_activity 是您的活动名称,method_name() 是您要调用的方法的名称。

                      【讨论】:

                        【解决方案14】:

                        Kotlin 试试

                        class DataForm : Fragment() {
                            override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
                                Tasks(this).getData()
                            }
                        
                            fun getResponse(response: String) {
                                // code
                            }
                        }
                        
                        class Tasks(private val context: Any) {
                            fun getData() {
                        
                                val getContext = (context as DataForm).activity
                                val getFragment = (context as DataForm)
                        
                                val responseListener = Response.Listener<String> { response ->
                                    getFragment.getResponse(response)
                                }
                        
                                val errorListener = Response.ErrorListener { error ->
                                    error.printStackTrace();
                                }
                        
                                val stringRequest = StringRequest(Request.Method.GET, url, responseListener, errorListener)
                                Volley.newRequestQueue(getContext).add(stringRequest)
                            }
                        }
                        

                        【讨论】:

                        • 我喜欢这个,因为它消除了孩子对父母的知识水平。片段不应该直接调用父方法。
                        【解决方案15】:

                        ((YourActivityName)getActivity()).functionName();

                        例如:((SessionActivity)getActivity()).changeFragment();

                        注意:类名应该是公开的

                        【讨论】:

                          【解决方案16】:

                          从片段到活动:

                          ((YourActivityClassName)requireActivity()).yourPublicMethod();

                          【讨论】:

                            【解决方案17】:

                            从各自的片段中调用活动方法的最佳方式

                            (activity as YourActivity).activtiyMethod()
                            

                            从您的活动中使用此行。例如

                            假设您有 Activity A 和方法 add() 以及您的片段 ABC,并且您想从片段 ABC 调用方法 add,

                            (activity as A).add()
                            

                            【讨论】:

                              猜你喜欢
                              • 2013-10-20
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              • 1970-01-01
                              • 2021-12-23
                              • 1970-01-01
                              相关资源
                              最近更新 更多