有没有办法使用相同的布局动态创建片段并向它们显示数据?

Posted

技术标签:

【中文标题】有没有办法使用相同的布局动态创建片段并向它们显示数据?【英文标题】:Is there a way to dynamically create fragments and display data to them using the same layout? 【发布时间】:2021-09-22 23:23:45 【问题描述】:

我编写了从远程端点获取 JSON 对象的代码。对于这个问题,我传入了一个模拟对象,它是一个对象数组。 我的目标是解构对象并为数组的每个元素在 ViewPager 中创建一个片段。每个片段都应该显示它所代表的对象的 id。 对象如下所示:

'data':['id':1,'id':2]

如果我取消注释 FragmentClass 中的代码,每个片段都会显示“测试”。但是,如果我尝试根据通过参数传递的值设置文本,则会遇到此错误:

java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.Object android.os.Bundle.get(java.lang.String)' on a null object reference

FragmentClass 的代码是:

public class FragmentClass extends Fragment 
    private TextView txtId;

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

        txtId = (TextView) rootView.findViewById(R.id.txtId);
        txtId.setText(getArguments().get("id").toString());

//        txtId.setText("test");
        return rootView;
    

ViewPager 类 ScreenSliderPagerActivity 的代码是:

public class ScreenSliderPagerActivity extends FragmentActivity 
    private ViewPager mPager;
    private PagerAdapter pagerAdapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        Intent intent = getIntent();
        String data = intent.getStringExtra("data");
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_screen_slide);

        // Instantiate a ViewPager and a PagerAdapter.
        mPager = (ViewPager) findViewById(R.id.pager);
        pagerAdapter = new ScreenSlidePagerAdapter(getSupportFragmentManager(), data);
        mPager.setAdapter(pagerAdapter);
    

    @Override
    public void onBackPressed() 
        if (mPager.getCurrentItem() == 0) 
            // If the user is currently looking at the first step, allow the system to handle the
            // Back button. This calls finish() on this activity and pops the back stack.
            super.onBackPressed();
         else 
            // Otherwise, select the previous step.
            mPager.setCurrentItem(mPager.getCurrentItem() - 1);
        
    

    private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter 
        public int NUM_PAGES; //making this a public variable within the inner class allows me to dynamically change the number of fragments created. In this instance, 2 will be created, one for each element of the array.

        public ScreenSlidePagerAdapter(FragmentManager fm, String data) 
            super(fm);
            try 
                JSONObject json = new JSONObject(data);
                JSONArray jsonArray = json.getJSONArray("data");

                NUM_PAGES = jsonArray.length();

                Log.d("NUM_PAGES", String.valueOf(NUM_PAGES)); //2
                FragmentTransaction ft = fm.beginTransaction();
                Bundle args = new Bundle();

// I think the problem is something in the loop, but I cannot seem to figure another way to do this.
                for (int i = 0; i < NUM_PAGES; i++)
                    JSONObject obj = (JSONObject) jsonArray.get(i);

                    FragmentClass fragment = new FragmentClass();
                    ft.add(R.id.pager, fragment);

                    args.putString("id", obj.get("id").toString());
                    fragment.setArguments(args);

                
                ft.commit();

             catch (JSONException e) 
                e.printStackTrace();
            
        

        @Override
        public Fragment getItem(int position) 
            return new FragmentClass();
        

        @Override
        public int getCount() 
            return NUM_PAGES;
        
    

最后,我的包含模拟对象的 MainActivity 是:

public class MainActivity extends AppCompatActivity 
    private Button button;
    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        button = findViewById(R.id.btn);
    
    public void handleClick(View view)
        String mockData = "'data':['id':1,'id':2]";
        Intent intent = new Intent(MainActivity.this, ScreenSliderPagerActivity.class);
        intent.putExtra("data",mockData);
        MainActivity.this.startActivity(intent);

    

【问题讨论】:

AFAIK 你不能通过FragmentTransaction手动执行ViewPager片段事务 你得到空指针异常的原因是你在片段的 onCreate() 中引用了一个视图你应该在 onViewCreated() 中做 findViewById() @BabyishTank 将其移至 onViewCreated() 会产生同样的问题。我认为问题在于 getArguments() 返回 null。 @Zain 手动将片段添加到 ViewPager 的代码似乎工作得很好。你会推荐一个替代品吗? 你是对的,它是 getArguments() 返回 null,这意味着在 viewPager 创建片段期间它根本没有设置参数。 【参考方案1】:

FragmentStatePagerAdapters 不是这样工作的。您不能将适配器的构造函数中的片段添加到片段管理器中,并期望将其添加到正确的位置。您必须在getItem(int) 方法中返回构造的片段带有参数

private class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter 
    public int NUM_PAGES; //making this a public variable within the inner class allows me to dynamically change the number of fragments created. In this instance, 2 will be created, one for each element of the array.
    private ArrayList<FragmentClass> mFragments = new ArrayList<>();

    public ScreenSlidePagerAdapter(FragmentManager fm, String data) 
        super(fm);
        try 
            JSONObject json = new JSONObject(data);
            JSONArray jsonArray = json.getJSONArray("data");

            NUM_PAGES = jsonArray.length();

            Log.d("NUM_PAGES", String.valueOf(NUM_PAGES)); //2
            

            for (int i = 0; i < NUM_PAGES; i++)
                JSONObject obj = (JSONObject) jsonArray.get(i);
                Bundle args = new Bundle();
                FragmentClass fragment = new FragmentClass();
                args.putString("id", obj.get("id").toString());
                fragment.setArguments(args);
                mFragments.add(fragment);
            

         catch (JSONException e) 
            e.printStackTrace();
        
    

    @Override
    public Fragment getItem(int position) 
        return mFragments.get(position);
    

    @Override
    public int getCount() 
        return NUM_PAGES;
    

【讨论】:

感谢您的回复!这更有意义。我确实不得不在实施中改变你的答案。 Bundle 对象的声明需要在 for 循环中,否则创建的所有片段都将携带相同的参数。除此之外,这很好用! 当然,您介意编辑 Bundle 对象的位置以使其完全准确吗? 当然,请随时使用您的声明编辑我的答案。

以上是关于有没有办法使用相同的布局动态创建片段并向它们显示数据?的主要内容,如果未能解决你的问题,请参考以下文章

具有相同布局的多个片段

片段或活动?最好在社交媒体应用中显示用户个人资料?

Android片段布局完成膨胀

如何使用 tabLayout 在 ViewPager 中显示片段?

片段和活动之间没有传递值

使用片段的android studio中不显示动态按钮