将数据从1个片段传输到另一个片段

时间:2014-08-26 22:16:26

标签: android android-fragments android-bundle

目前正在尝试使用捆绑包将信息从我的IncomeFragment和ExpenseFragment传输到HomeFragment,但我不确定如何操作。我尝试过实施他提供的doubleA代码。

这是我的MainActivity中的onAcceptClicked方法,它从相关片段中获取总收入/费用的值,并将其传输到HomeFragment:

public void onAcceptClicked(String fragment, String total) {

    final FragmentManager fm = getFragmentManager();
    final FragmentTransaction ft = fm.beginTransaction();
    if (fragment == "income") {
        HomeFragment homeFrag = new HomeFragment();
        Bundle incomeBundle = new Bundle();
        incomeBundle.putString(IncomeFragment.TAG, total);
        //homeFrag.newInstance(total);
        ft.replace(R.id.content_layout, homeFrag, HomeFragment.TAG);
        ft.commit();
    }
    else if (fragment == "expense"){
        HomeFragment homeFragment = new HomeFragment();
        Bundle expenseBundle = new Bundle();
        expenseBundle.putString("bundleIncome", total);
        homeFragment.setArguments(expenseBundle);
        ft.replace(R.id.content_layout, homeFragment, HomeFragment.TAG);
        ft.commit();
    }
}

我的IncomeFragment中有一个界面,我用它来与我的MainActivity进行通信,所以我可以使用onAcceptClicked方法来传输我的总数。我计划用我的ExpenseFragment做同样的事情。下面的代码是我的IncomeFragment的一个片段:

public interface SendIncomeData {
    public void onAcceptClicked(String fragment, String total);
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case R.id.action_accept:
            //Toast.makeText(getActivity(), stringIncomeTotal, Toast.LENGTH_LONG).show();
            sendIncomeData.onAcceptClicked("income", stringIncomeTotal);
            return true;
        default:
            return super.onOptionsItemSelected(item);

    }
}

不幸的是,我在这行代码中遇到错误

sendIncomeData.onAcceptClicked("income", stringIncomeTotal);

这是错误

java.lang.NullPointerException: Attempt to invoke interface method 'void mos.myapplication.IncomeFragment$SendIncomeData.onAcceptClicked(java.lang.String, java.lang.String)' on a null object reference

我不知道为什么它说有一个空对象引用和/或我如何解决这个错误。

我猜这可能会在我的HomeFragment中显示我的总计时出错,因为我在我的MainActivity或我的IncomeFragment / ExpenseFragment代码中的任何地方都没有调用该方法。我没有使用它的原因是因为我不确定如何获取它以便HomeFragment在应用程序启动时首先打开。

    static HomeFragment newInstance(String total) 
{
    HomeFragment frag = new HomeFragment();
    Bundle args = new Bundle();
    args.putString(TAG, total);
    frag.setArguments(args);
    return frag;
}

我知道这真是一团糟,因为我已经对我的进展进行了几次编辑,但如果有人能帮助我,我真的很感激,我甚至不介意从头开始,只要我可以转移总数并从IncomeFragment>中显示它们。 HomeFragment和ExpenseFragment> HomeFragment。感谢。

3 个答案:

答案 0 :(得分:0)

您应该使用接口在片段之间进行通信。请阅读本教程有关片段通信的内容。 http://developer.android.com/training/basics/fragments/communicating.html

收入片段不知道Home片段是否存在。如果收入片段存在,Home不知道。只有父活动知道片段是否存在。如果在片段和父活动之间设置接口,则可以使用该接口在片段之间进行通信。

HomeFragment

package com.doublea.myapplication2.app;

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.TextView;
import android.widget.Toast;

/**
 * Created by ShaDynastys on 9/1/2014.
 */
public class HomeFragment extends Fragment {
    public static final String TAG = HomeFragment.class.getSimpleName();
    private String total;

    static HomeFragment newInstance(String total) {
        HomeFragment frag = new HomeFragment();
        Bundle args = new Bundle();
        args.putString(TAG, total);
        frag.setArguments(args);
        return frag;
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        super.onCreateView(inflater, container, savedInstanceState);
        View root = inflater.inflate(R.layout.fragment, container, false);
        TextView text = (TextView) root.findViewById(R.id.text);
        text.setText(TAG);
        return root;
    }

    @Override
    public void onResume() {
        super.onResume();
        Bundle bundle = getArguments();
        total = bundle.getString(TAG);
        if (total != null)
            Toast.makeText(getActivity(), total, Toast.LENGTH_LONG).show();

    }
}

IncomeFragment

    package com.doublea.myapplication2.app;

    import android.app.Activity;
    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.Button;
    import android.widget.EditText;
    import android.widget.TextView;

    /**
     * Created by ShaDynastys on 9/1/2014.
     */
    public class IncomeFragment extends Fragment {
        public static final String TAG = IncomeFragment.class.getSimpleName();

        private SendIncomeData sendIncomeData;

        static IncomeFragment newInstance() {
            IncomeFragment frag = new IncomeFragment();
            return frag;
        }

        @Override
        public void onAttach(Activity activity) {
            super.onAttach(activity);
            try {
                sendIncomeData = (SendIncomeData) activity;
            } catch (ClassCastException e) {
                throw new ClassCastException(activity.toString()
                        + " must implement SendIncomeData");
            }
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            setRetainInstance(true);
            View result = inflater.inflate(R.layout.fragment, container, false);
            TextView text = (TextView) result.findViewById(R.id.text);
            text.setText(TAG);
            final EditText editText = (EditText) result.findViewById(R.id.editText);
            editText.setVisibility(View.VISIBLE);


   Button button = (Button) result.findViewById(R.id.button);
        button.setVisibility(View.VISIBLE);
        button.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                sendIncomeData.onAcceptClicked("income", editText.getText().toString());
            }
        });
        return result;
    }

    public interface SendIncomeData {
        public void onAcceptClicked(String fragment, String total);
    }
}

MainActivity

package com.doublea.myapplication2.app;

import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.view.Menu;
import android.view.MenuItem;


public class MainActivity extends FragmentActivity implements IncomeFragment.SendIncomeData {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        setupFragment();
    }

    private void setupFragment() {
        final FragmentManager fm = getSupportFragmentManager();
        final FragmentTransaction ft = fm.beginTransaction();
        IncomeFragment incomeFragment = (IncomeFragment) fm.findFragmentByTag(IncomeFragment.TAG);
        if (incomeFragment == null) {
            incomeFragment = IncomeFragment.newInstance();
            ft.add(R.id.fragment_container, incomeFragment, IncomeFragment.TAG);
        }
        ft.commit();
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {

        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    /*if (fragment == "income") {
        HomeFragment homeFragment = new HomeFragment();
        Bundle incomeBundle = new Bundle();
        incomeBundle.putString("bundleIncome", total);
        homeFragment.setArguments(incomeBundle);
    }
    else if (fragment == "expense"){
        HomeFragment homeFragment = new HomeFragment();
        Bundle expenseBundle = new Bundle();
        expenseBundle.putString("bundleIncome", total);
        homeFragment.setArguments(expenseBundle);
    }*/
    @Override
    public void onAcceptClicked(String fragment, String total) {
        Bundle incomeBundle = new Bundle();
        incomeBundle.putString(IncomeFragment.TAG, total);
        if (fragment == "income") {
            HomeFragment homeFrag = HomeFragment.newInstance(total);
            final FragmentManager fm = getSupportFragmentManager();
            final FragmentTransaction ft = fm.beginTransaction();
            ft.replace(R.id.fragment_container, homeFrag, HomeFragment.TAG);
            ft.commit();
        }
    }
}

快乐的编码。

答案 1 :(得分:0)

首先需要检查bundle是否为null:

bundle = this.getArguments();

if (bundle != null)
{
    // continue with your logic
}

此外,所有Fragment-to-Fragment通信都是通过相关的Activity完成的。两个碎片永远不应该直接通信。有关详细信息,请参阅以下链接:

答案 2 :(得分:0)

很多人会争辩说使用接口是最好的方法,这并不是真正的错误,但有更简单的方法。 编辑:不一定更简单 - 一种方法是通过调用

来获取片段内活动的引用
this.getActivity();

然后在你的活动类中,你可以有一个方法将数据传递给另一个片段,因为它有两个片段的引用。

- 然后实际上有更好的方法(尽管第一部分也可能有用):

在具有需要移动的数据的片段中,您可以从FragmentManager获取对其他片段的引用。这假设您使用字符串ID创建了该片段,如下所示:

Fragment otherFragment;
getSupportFragmentManager().beginTransaction().add(otherFragment, "otherFrag").commit();

然后在包含数据的片段中,您将执行:

FragmentActivity fragmentActivity = (FragmentActivity)getActivity();
    OtherFragment otherFragment = (OtherFragment)fragmentActivity.getSupportFragmentManager().findFragmentByTag("otherFrag");

然后引用OtherFragment(在本例中),您可以执行以下操作:

otherFragment.dataString = "myData";

但是你可能想要进行测试以确保其他片段不会返回null,如果它是null,你可能只想创建它然后因为你已经有了参考FragmentManager。

编辑:我只是说我主观上更喜欢这种方法。