【问题标题】:Passing ArrayList from Fragment A to Fragment B when user clicked navbar (of Fragment B)当用户单击导航栏(片段 B)时,将 ArrayList 从片段 A 传递到片段 B
【发布时间】:2020-07-16 04:46:32
【问题描述】:

我是 Android 和 Fragment 的新手,请帮助我。我的应用正在使用导航栏菜单,其中包括主页 (HomeFragment) 和历史记录 (HistoryFragment)。

当用户从主页导航到导航栏并单击历史记录时,我想将 ArrayList (existingRecords) 和记录对象 (todayRecord) 从 HomeFragment 传递到 HistoryFragment。我已配置为将existingRecords 发送到MainActivity 类,如下所示。我不知道如何将todayRecord 传递到意图中。

HomeFragment.class

    @Override
    public void onStop() {
        super.onStop();

        //compare if the date of last record is the same as today
        //if same, update today's record
        Log.d(msg, "The onStop() event");
        if(recordExist){
            updateLastRecord(todayRecord);
            Log.d(msg, "existing record updated");
        }
        //if record not found, add new record
        else {
            addRecord(todayRecord);
            Log.d(msg, "New record added");
        }
        sendDataToMainActivity();
    }

    public void sendDataToMainActivity(){
        Log.d("Android: ", "HomeFragment: Sending Data to MainActivity");
        Intent intent = new Intent(getActivity().getBaseContext(), MainActivity.class);
        intent.putParcelableArrayListExtra("existingRecords", existingRecords);
        getActivity().startActivity(intent);

    }

当用户点击导航栏菜单上的历史记录 (R.id.nav_history) 时,我不知道如何调用 sendReceiveData()。

MainActivity.class

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);
        FloatingActionButton fab = findViewById(R.id.fab);
        fab.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
                        .setAction("Action", null).show();
            }
        });
        DrawerLayout drawer = findViewById(R.id.drawer_layout);
        NavigationView navigationView = findViewById(R.id.nav_view);
        // Passing each menu ID as a set of Ids because each
        // menu should be considered as top level destinations.
        mAppBarConfiguration = new AppBarConfiguration.Builder(
                R.id.nav_home, R.id.nav_history, R.id.nav_slideshow)
                .setDrawerLayout(drawer)
                .build();
        NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment);
        NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
        NavigationUI.setupWithNavController(navigationView, navController);
        
        loadAdmob();
    }

    public void sendReceiveData(){
        
        //receive data from HomeFragment
        Intent intent = getIntent();
        existingRecords = intent.getParcelableArrayListExtra("existingRecords");

        //send data to History fragment
        Bundle bundle=new Bundle();
        bundle.putParcelableArrayList("existingRecords", existingRecords);
        //set Fragmentclass Arguments
        HistoryFragment fragobj=new HistoryFragment();
        fragobj.setArguments(bundle);
        
    }

我已将 HistoryFragment.class 配置为接收数据,但是当我运行代码时,bundle 为 null,因为我无法在 MainActivity 中传递 bundle。

HistoryFragment.class

   public View onCreateView(@NonNull LayoutInflater inflater,
                             ViewGroup container, Bundle savedInstanceState) {
        historyViewModel = ViewModelProviders.of(this).get(HistoryViewModel.class);
        View root = inflater.inflate(R.layout.fragment_history, container, false);
        Bundle bundle = this.getArguments();
        if(bundle!=null){
            // handle your code here.

            existingRecords = savedInstanceState.getParcelableArrayList("existingRecords");
            txtThisMonthSummary = root.findViewById(R.id.txtThisMonthSummary);
            txtThisWeekSummary = root.findViewById(R.id.txtThisWeekSummary);
            txtThisMonthSummary = root.findViewById(R.id.txtYearSummary);
            Log.d("Android: ", "HistoryFragment: Data received");

            summary = new History(existingRecords);
            txtThisWeekSummary.setText(summary.getWeeklySum());
            txtThisMonthSummary.setText(summary.getMonthlySum());
            txtThisYearSummary.setText(summary.getYearlySum());
        }

        return root;
    }

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    tools:openDrawer="start">

    <include
        layout="@layout/app_bar_main"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <com.google.android.material.navigation.NavigationView
        android:id="@+id/nav_view"
        android:layout_width="wrap_content"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:fitsSystemWindows="true"
        app:headerLayout="@layout/nav_header_main"
        app:menu="@menu/activity_main_drawer" />

</androidx.drawerlayout.widget.DrawerLayout>

activity_main_drawer.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    tools:showIn="navigation_view">

    <group android:checkableBehavior="single">
        <item
            android:id="@+id/nav_home"
            android:icon="@drawable/ic_zikir"
            android:title="@string/menu_home" />
        <item
            android:id="@+id/nav_history"
            android:icon="@drawable/ic_achievement"
            android:title="@string/menu_history" />
        <item
            android:id="@+id/nav_slideshow"
            android:icon="@drawable/ic_menu_slideshow"
            android:title="@string/menu_achievement" />
    </group>
</menu>

【问题讨论】:

  • 最简单的方法是在 MainActivity 中使用 ViewModel,并通过 getActivity().getterFunctionForVoewModel() 在两个 Fragment 中使用相同的 ViewModel 实例。如果您将现有记录和今天记录存储在 ViewModel 中,片段和活动都将始终可以访问这些变量的最新值。这也将允许观察它们的值并通过使用 LiveData 包装它们来对更改做出反应。我相信你可以很容易地在网上找到如何做到这一点,如果不是这样的话,这个问题甚至可能是重复的
  • @Rinat 向技术新手推荐 ViewModel !!!
  • 出于好奇:你不是将数据保存在某个地方作为历史片段吗?像 sqlite 或远程服务器?
  • @kelvin 是的 HomeFragment 我使用 SharedPreferences 存储现有记录。我可以在 HistoryFragment 中找回它吗?
  • 你说的记录如果有多条记录我建议你使用Sqlite,Sharedpreds用于键值对存储。

标签: java android android-fragments


【解决方案1】:

根据@kelvin 的反馈,我设法从 HomeFragment 中的 SharedPreferences 中检索数据。我没有想到存储在 SharedPreferences 中的数据可以通过任何类访问。 *菜鸟*

共享偏好名称/密钥:

    public static final String PREFS_NAME = "Daily Zikir";
    public static final String RECORDLIST = "Records";

用于存储数据的代码,在 HomeFragment 中调用:

    public void saveRecords(List records){
        SharedPreferences settings;
        SharedPreferences.Editor editor;
        settings = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
        editor = settings.edit();

        GsonBuilder builder = new GsonBuilder();
        builder.excludeFieldsWithModifiers(Modifier.FINAL, Modifier.TRANSIENT, Modifier.STATIC);
        builder.excludeFieldsWithoutExposeAnnotation();
        Gson sExposeGson = builder.create();
        String jsonRecords = sExposeGson.toJson(records);
        editor.putString(RECORDLIST, jsonRecords);
        editor.commit();

        Log.d("Android: ",  "Jason string saved: "+ jsonRecords);

    }

用于检索数据的代码,在 HistoryFragment 中调用:

    public ArrayList loadRecords() {
        // used for retrieving arraylist from json formatted string
        SharedPreferences settings;
        List records;
        settings = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE);
        if (settings.contains(RECORDLIST)) {
            String jsonFavorites = settings.getString(RECORDLIST, null);

            GsonBuilder builder = new GsonBuilder();
            builder.excludeFieldsWithModifiers(Modifier.FINAL, Modifier.TRANSIENT, Modifier.STATIC);
            builder.excludeFieldsWithoutExposeAnnotation();
            Gson sExposeGson = builder.create();
            Record[] recordItems = sExposeGson.fromJson(jsonFavorites, Record[].class);
            records = Arrays.asList(recordItems);
            records = new ArrayList(records);
        } else
            return null;
        return (ArrayList) records;
    }

将继续探索 SQLlite 和 ViewModel 的使用,但目前还可以。

【讨论】:

  • 如果我错了,请纠正我,但 sqllite 真的很乱而且容易出错,请改用 Room。它基于注释并为您生成所有样板代码。
  • @Rinat 我在培训材料中看到了 SQL 和 Room。很快就会到达那里。谢谢你的建议。
猜你喜欢
  • 1970-01-01
  • 2020-07-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多