将数据从 Activity 传递到已附加的 Fragment 的方法

Posted

技术标签:

【中文标题】将数据从 Activity 传递到已附加的 Fragment 的方法【英文标题】:Passing data from Activity to a method of a Fragment already attached 【发布时间】:2021-08-16 22:10:46 【问题描述】:

我一直在研究这个问题,尽管我找到了信息,但似乎有些细节我没有掌握。我想将信息从 Activity 传递到已附加的 Fragment。这是当前代码:

SearchActivity.java

public class SearchActivity extends AppCompatActivity 

    private static final int FRAG_USERS = 0;
    private static final int FRAG_MESSAGES = 1;
    private int currentFrag = 0;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_search);
        setupActionBar();
        setupViewPager();
    

    private void setupActionBar() 
        ActionBar actionBar = this.getSupportActionBar();
        actionBar.setTitle("");
        actionBar.setDisplayHomeAsUpEnabled(true);
    

    private void setupViewPager() 
        ViewPager2 searchVP2 = findViewById(R.id.searchVP2);
        searchVP2.setAdapter(new SearchPagerAdapter(this));

        TabLayout searchTL = findViewById(R.id.searchTL);
        TabLayoutMediator tabLayoutMediator = new TabLayoutMediator(searchTL, searchVP2, (tab, position) -> 
            switch (position) 
                case 0: 
                    tab.setText(R.string.users);
                    break;
                 case 1: 
                    tab.setText(R.string.messages);
                    break;
                
            
        );
        tabLayoutMediator.attach();

        searchTL.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() 
            @Override
            public void onTabSelected(TabLayout.Tab tab) 
                currentFrag = searchTL.getSelectedTabPosition();
            
            @Override
            public void onTabUnselected(TabLayout.Tab tab)  
            @Override
            public void onTabReselected(TabLayout.Tab tab)  
        );
    

    @Override
    public boolean onCreateOptionsMenu(Menu menu) 
        getMenuInflater().inflate(R.menu.menu_searchable, menu);
        SearchView searchView = (SearchView) menu.findItem(R.id.searchIT).getActionView();
        searchView.setMaxWidth(Integer.MAX_VALUE);
        searchView.setIconified(false);
        searchView.setFocusable(true);
        searchView.requestFocusFromTouch();
        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() 
            @Override
            public boolean onQueryTextSubmit(String query) 
                return false;
            

            @Override
            public boolean onQueryTextChange(String query) 
                if (!TextUtils.isEmpty(query)) 
                    if (currentFrag == FRAG_USERS) 
                        Bundle bundle = new Bundle();
                        bundle.putString(Constants.BUNDLE_SEARCH, query);
                        new SearchUserFragment().setArguments(bundle);
                        //SearchUserFragment.newInstance(query);
                     else 
                        SearchMessageFragment.newInstance(query);
                    
                
                return true;
            
        );
        return true;
    

    @Override
    public boolean onSupportNavigateUp() 
        onBackPressed();
        return true;
    

SearchUserFragment.java(消息片段在这方面是一样的)

public class SearchUserFragment extends Fragment 

    private TextView notFoundTV;
    private RecyclerView searchUserRV;
    private MaterialCardView searchTipCV;
    private Map<String, User> userMap;

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) 
        View view = inflater.inflate(R.layout.fragment_search_message, container, false);
        notFoundTV = view.findViewById(R.id.notFoundTV);
        searchTipCV = view.findViewById(R.id.searchTipCV);
        refreshRV(view);
        return view;
    

    private void refreshRV(View view) 
        userMap = new HashMap<>();
        searchUserRV = view.findViewById(R.id.searchMessageRV);
        searchUserRV.setHasFixedSize(true);
        searchUserRV.setLayoutManager(new LinearLayoutManager(getContext()));
    

    public void searchUser(String query) 
        userMap.clear();
        boolean isUserNameValid = true;

        String finalQuery = query.trim();
        if (finalQuery.isEmpty()) 
            setViewsVisibility(View.GONE, View.VISIBLE, View.GONE);
            isUserNameValid = false;
         else if (finalQuery.length() < 4 || !finalQuery.matches("^[a-zA-Z0-9]+$")) 
            setViewsVisibility(View.GONE, View.VISIBLE, View.GONE);
            isUserNameValid = false;
        

        if (isUserNameValid) 
            FirebaseDatabase.getInstance().getReference()
                    .child(KEY_COLLECTION_USER)
                    .child(finalQuery)
                    .addListenerForSingleValueEvent(new ValueEventListener() 
                @Override
                public void onDataChange(@NonNull DataSnapshot dataSnapshot) 
                    for (DataSnapshot snapshot : dataSnapshot.getChildren()) 
                        User user = snapshot.getValue(User.class);
                        if (user.getUserName().equals(CURRENT_USER.getUserName())) continue;
                        if (user.getUserName().toLowerCase().startsWith(finalQuery.toLowerCase())) 
                            userMap.put(user.getId(), user);
                        
                        checkList();
                    
                

                @Override
                public void onCancelled(@NonNull DatabaseError databaseError)  
            );
        
    

    private void setViewsVisibility(int searchVis, int searchTipVis, int notFoundVis) 
        searchUserRV.setVisibility(searchVis);
        searchTipCV.setVisibility(searchTipVis);
        notFoundTV.setVisibility(notFoundVis);
    

    private void checkList() 
        if (userMap.size() > 0) 
            refreshRV(userMap);
            setViewsVisibility(View.VISIBLE, View.GONE, View.GONE);
         else 
            setViewsVisibility(View.GONE, View.GONE, View.VISIBLE);
        
    

    private void refreshRV(@NotNull Map<String, User> userMap) 
        SearchUserAdapter searchUserAdapter = new SearchUserAdapter(
                getContext(),
                userMap
        );
        searchUserRV.setAdapter(searchUserAdapter);
    

    public static void newInstance(String query) 
        SearchUserFragment searchUserFragment = new SearchUserFragment();
        searchUserFragment.searchUser(query);
    

SearchPagerAdapter.java

public class SearchPagerAdapter extends FragmentStateAdapter 

    public SearchPagerAdapter(@NonNull FragmentActivity fragmentActivity) 
        super(fragmentActivity);
    

    @NonNull
    @Override
    public Fragment createFragment(int position) 
        if (position == 0) 
            return new SearchUserFragment();
         else 
            return new SearchMessageFragment();
        
    

    @Override
    public int getItemCount() 
        return 2;
    

我不明白为什么我在研究期间发现的一些 newInstance() 方法会返回 Fragment 本身。我已经在 SearchUserFragment 中尝试了以下方法:

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        if (getArguments() != null && getArguments().containsKey(BUNDLE_SEARCH)) 
            searchUser(savedInstanceState.getString(BUNDLE_SEARCH));
        
    

    public static SearchUserFragment newInstance(String query) 
        SearchUserFragment searchUserFragment = new SearchUserFragment();

        Bundle args = new Bundle();
        args.putString(BUNDLE_SEARCH, query);
        searchUserFragment.setArguments(args);

        return searchUserFragment;
    

但它没有成功,就像 newInstance() 没有实例化片段的另一个实例一样。应用程序不会崩溃,但当我在 SearchView 中输入内容时不会发生任何事情。

我也尝试过这样做: SearchActivity.java

            @Override
            public boolean onQueryTextChange(String query) 
                if (!TextUtils.isEmpty(query)) 
                    if (currentFrag == FRAG_USERS) 
                        Bundle bundle = new Bundle();
                        bundle.putString(Constants.BUNDLE_SEARCH, query);
                        new SearchUserFragment().setArguments(bundle);
                     else 
                        SearchMessageFragment.newInstance(query);
                    
                
                return true;
            

SearchUserFragment.java

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) 
        View view = inflater.inflate(R.layout.fragment_search_message, container, false);
        notFoundTV = view.findViewById(R.id.notFoundTV);
        searchTipCV = view.findViewById(R.id.searchTipCV);
        refreshRV(view);
        Bundle bundle = this.getArguments();
        if (bundle != null) 
            searchUser(bundle.getString(BUNDLE_SEARCH));
        
        return view;
    

它也没有成功。与上述行为相同。

在代码的当前状态下,我得到了 NullPointerException(理所当然)。当前的代码使我所有的列表和视图都变为空,因为 onCreateView() 由于已经创建而没有被触发。

我只想能够从 SearchActivity 中获取查询,以便完美地从片段中执行 searchUser()/searchMessage()。

【问题讨论】:

这可能会有所帮助,您基本上需要对现有片段的引用,您可以直接调用该方法,无需捆绑:***.com/questions/36503779/… @DanielNugent 我需要为 ViewPager2 设置一个适配器吗?我已经更改了 SearchPagerAdapter 的代码,但我不确定如何处理 SearchActivity 上的 setupViewPager()。当我尝试设置它时,它给了我一个错误,因为 SearchPager 类是从 FragmentPagerAdapter 而不是从 FragmentStateAdapter 扩展的。 看看这里的答案:***.com/questions/55728719/… @DanielNugent 最后一个链接有我想要的。非常感谢:) 【参考方案1】:

感谢@DanielNugent 发布的最后一个链接,我已经能够解决这个问题。

SearchUserFragment.java

public class SearchActivity extends AppCompatActivity 

    private ViewPager2 searchVP2;
    private String globalQuery;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_search);
        setupActionBar();
        setupViewPager();
    

    private void setupActionBar() 
        ActionBar actionBar = this.getSupportActionBar();
        actionBar.setTitle("");
        actionBar.setDisplayHomeAsUpEnabled(true);
    

    private void setupViewPager() 
        searchVP2 = findViewById(R.id.searchVP2);
        searchVP2.setAdapter(new SearchPagerAdapter(this));

        TabLayout searchTL = findViewById(R.id.searchTL);
        TabLayoutMediator tabLayoutMediator = new TabLayoutMediator(searchTL, searchVP2, (tab, position) -> 
            switch (position) 
                case 0: 
                    tab.setText(R.string.users);
                    break;
                
                case 1: 
                    tab.setText(R.string.messages);
                    break;
                
            
        );
        tabLayoutMediator.attach();

        searchTL.addOnTabSelectedListener(new TabLayout.OnTabSelectedListener() 
            @Override
            public void onTabSelected(TabLayout.Tab tab) 
                searchInCurrentFrag(globalQuery, tab.getPosition());
            
            @Override
            public void onTabUnselected(TabLayout.Tab tab)  
            @Override
            public void onTabReselected(TabLayout.Tab tab)  
        );
    

    @Override
    public boolean onCreateOptionsMenu(Menu menu) 
        getMenuInflater().inflate(R.menu.menu_searchable, menu);
        SearchView searchView = (SearchView) menu.findItem(R.id.searchIT).getActionView();
        searchView.setMaxWidth(Integer.MAX_VALUE);
        searchView.setIconified(false);
        searchView.setFocusable(true);
        searchView.requestFocusFromTouch();
        searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() 
            @Override
            public boolean onQueryTextSubmit(String query) 
                return false;
            

            @Override
            public boolean onQueryTextChange(String query) 
                globalQuery = query;
                if (!TextUtils.isEmpty(query)) 
                    searchInCurrentFrag(query, searchVP2.getCurrentItem());
                
                return true;
            
        );
        return true;
    

    private void searchInCurrentFrag(String query, int position) 
        if (query != null) 
            Fragment currentFragment = getSupportFragmentManager().findFragmentByTag("f" + position);
            if (currentFragment instanceof SearchUserFragment) 
                ((SearchUserFragment) currentFragment).searchUser(query);
             else 
                ((SearchMessageFragment) currentFragment).searchMessage(query);
            
        
    

    @Override
    public boolean onSupportNavigateUp() 
        onBackPressed();
        return true;
    

【讨论】:

以上是关于将数据从 Activity 传递到已附加的 Fragment 的方法的主要内容,如果未能解决你的问题,请参考以下文章

将 PendingIntent 中小部件的附加信息传递给 Activity

为啥我无法将调试器附加到已签名的 apk 进程?

Android:将数据(附加)传递给片段

Android - 将数据从 AsyncTask 传递到 Activity

如何将数据从一个 Activity 中的 ListView 传递到另一个 Activity 上的 TextView?

android - 将数据从 Activity 传递到 ViewPager 中的 Fragment