0

问题:

当我尝试通过父 Activity 从另一个片段中引用一个片段的布局时。我试图访问的布局始终为空。

我相信这与通过 Activity 的 newInstance() 方法创建时未调用 onCreate() 和 onCreateView() 有关。这是我有点陌生的 Android 领域,我不能 100% 确定 Activity 和 Fragment 生命周期如何交互。背景的简要概述和问题底部包含的所有代码。

这很可能是一个我目前看不到的简单修复。为了完整起见,包括了细节。

背景:

问题是,我有两个Fragments由一个Activity班级托管。该类Activity由一个标准基Activity类组成,我将其用于整个应用程序的许多活动。这保持对 ActionBar Fragments 布局的引用(用于更改标题、图像等)并包含用于获取新 ActionBar 实例等的方法。(此处的关键方法setActionBarTitle(title)- 稍后提及)包含在下面的代码[1]

Activity包含两个 Fragment的继承类的第二部分是特定于任务的Activity,在本例中是帮助Activity

这是Activity加载操作栏片段(通过newInstance(title)基类中的方法)和相应的片段,在本例中为帮助片段。[2]

哪里出错了:

在该onAttach()方法中,我得到了对父级Activity-的引用Activity_Help

问题出onCreateView()在我的帮助Fragment [3]中。目标是访问 Activity_Help 的 setActionBarTitle 方法。

由于 Activity_Help 扩展了 Activity 基类 (General_Activity),因此setActionBarTitle()方法和存储的 actionBarLayout 都可以访问。似乎它应该可以访问更改操作栏片段文本所需的所有内容?

然而,事情就是这样。。

  • [Fragment_Help]parentActivity.setActionBarTitle("New title");导致..

  • [General_Activity]fragmentActionBar.setTitle(newTitle);导致..

  • [Fragment_Example1_ActionBar]TextView tvTitle = (TextView) actionBarLayout.findViewById(R.id.tvCustomActionBarTitle);错误行 - actionBarLayout 为空

操作栏片段的完整代码包含在最底部。[4]

我相信首先提到的是在 Activity_Help.fragmentActionBar 中没有保持它的布局。当第二次访问以更改 时TextView,布局为空,因此为 NPE。

任何建议将不胜感激!

超类活动代码 [1]

public class General_Activity extends Activity
{
     Fragment_Example1_ActionBar fragmentActionBar;

         ....

         // Start Help Activity
         case R.id.bMenuHelp:
        Intent helpIntent = new Intent(this, Activity_Help.class);
        helpIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
        startActivity(helpIntent);
        break;

         ....

     // Create a new ActionBar with given title
     public void newActionBarInstance(String initialTitle)
     {
        fragmentActionBar = Fragment_Example1_ActionBar.newInstance(initialTitle);
     }  

     // Create a new ActionBar with no title
     public Fragment_Example1_ActionBar newActionBarInstance()
     {
    return Fragment_Wurth_Example1_ActionBar.newInstance("");
}   

    // Set ActionBar title
    public void setActionBarTitle(String newTitle)
    {
        fragmentActionBar.setTitle(newTitle);
    }
}

Activity_帮助代码 [2]

public class Activity_Help extends General_Activity
{
@Override
protected void onCreate(Bundle savedInstanceState)
{       
    super.onCreate(savedInstanceState);
    setContentView(R.layout.fragment_container_layout);

    FragmentManager fragmentManager = getFragmentManager();

    Fragment_Help fragmentWholeScreen = new Fragment_Help();

    // SC - Create new ActionBar with given title
    newActionBarInstance("Help");

    if (!fragmentWholeScreen.isAdded())
    {
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();           
        fragmentTransaction.add(R.id.fragment_container_layout_example1, fragmentWholeScreen);
        fragmentTransaction.add(R.id.fragment_action_bar, fragmentActionBar);
        fragmentTransaction.commit();
    }
}

};

Fragment_帮助代码 [3]

public class Fragment_Help extends Fragment
{
Activity_Help parentActivity;

@Override
public void onAttach(Activity activity)
{       
    super.onAttach(activity);       
    parentActivity = (Activity_Help) activity;      
}   

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,  Bundle savedInstanceState)
{
    View helpLayout = inflater.inflate(R.layout.fragment_help, null);

    parentActivity.setActionBarTitle("New title");

    return helpLayout;
}

}

Fragment_Example1_Action条形码 [4]

public class Fragment_Example1_ActionBar extends Fragment
{   
OnCustomActionBarItemSelectedListener onCustomActionBarItemSelectedListener;
View actionBarLayout;
String title;

// Pass in original title
@Override
public void onCreate(Bundle savedInstanceState)
{
    Log.i("ACTiON_BAR", "++ ON CREATE ++ " + System.currentTimeMillis());

    super.onCreate(savedInstanceState);     

    Bundle receivedArguments = getArguments();

    title = receivedArguments.getString(App.ACTION_BAR_TITLE_KEY);

    actionBarLayout = getActivity().getLayoutInflater().inflate(R.layout.action_bar_layout, null);  
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,  Bundle savedInstanceState)
{
    Log.i("ACTiON_BAR", "+ ON CREATE VIEW + " + System.currentTimeMillis());

    if (title != null)
    {
        setTitle(title);
    }

    // Get reference to ActionBar buttons and set Listeners
    final ImageButton bActionBarLogo = (ImageButton) actionBarLayout.findViewById(R.id.bCustomActionBarHome);
    final ImageButton bActionBarMenu = (ImageButton) actionBarLayout.findViewById(R.id.bCustomActionBarMenu);
    final ImageButton bActionBarVehicleCheckIn = (ImageButton) actionBarLayout.findViewById(R.id.bCustomActionBarVehicleCheckIn);

    bActionBarLogo.setOnClickListener(actionBarButtonListener);
    bActionBarMenu.setOnClickListener(actionBarButtonListener);
    bActionBarVehicleCheckIn.setOnClickListener(actionBarButtonListener);

    return actionBarLayout;
}

// Intermediate menu button listener calling parent Activity implementation
OnClickListener actionBarButtonListener = new OnClickListener()
{       
    public void onClick(View actionBarItem)
    {
        onCustomActionBarItemSelectedListener.onCustomActionBarItemSelected(actionBarItem);         
    }
};

// Set ActionBar title
public void setTitle(String newTitle)
{
    // Get refence to the title TextView in the custom layout
    TextView tvTitle = (TextView) actionBarLayout.findViewById(R.id.tvCustomActionBarTitle);

    // Set the title
    tvTitle.setText(newTitle);
}

// Set ActionBar text size
public void setTextSize(float textSize)
{
    // Get refence to the title TextView in the custom layout
    TextView tvTitle = (TextView) actionBarLayout.findViewById(R.id.tvCustomActionBarTitle);

    // Set the title
    tvTitle.setTextSize(textSize);
}

// Get reference to parent activity and it's Action Bar listener
@Override
public void onAttach(Activity activity)
{
    Log.i("ACTiON_BAR", "+++ ON ATTACH +++ " + System.currentTimeMillis());

    super.onAttach(activity);

    try
    {
        // Get reference to Activity's implementation of listener
        onCustomActionBarItemSelectedListener = (OnCustomActionBarItemSelectedListener) activity;   
    }
    catch (ClassCastException e)
    {
        // If Activity doesn't implement listener, throw exception explaining error
        throw new ClassCastException(activity.toString() + " must implement OnCustomActionBarItemSelectedListener"); 
    }
}   

// New instance - keep the creation within the class in one place
public static Fragment_Example1_ActionBar newInstance(String initialTitle)
{
    // Package the title up in a bundle
    Bundle titleBundle = new Bundle();
    titleBundle.putString(App.ACTION_BAR_TITLE_KEY, initialTitle);

    Fragment_Example1_ActionBar fragmentActionBar = new Fragment_Example1_ActionBar();
    fragmentActionBar.setArguments(titleBundle);

    return fragmentActionBar;
}

// New instance - keep the creation within the class in one place
public static Fragment_Example1_ActionBar newInstance()
{
    // Package the title up in a bundle
    Bundle titleBundle = new Bundle();
    titleBundle.putString(App.ACTION_BAR_TITLE_KEY, "");

    Fragment_Example1_ActionBar fragmentActionBar = new Fragment_Example1_ActionBar();
    fragmentActionBar.setArguments(titleBundle);

    return fragmentActionBar;
}               
}

干杯!

4

3 回答 3

0

好的,首先,将其设置为静态听起来不太安全。您正在为自己创建一个确定的记忆链接(视图始终处于活动状态->它的上下文是活动->即使在finish发生后活动也始终存在)。

现在,在您的实现中,您正在提交片段事务。当这一切发生时,这是一场异步竞赛,其中碎片开始自行构建。当您尝试使用它们时,您不能假设它们已经完成了整个生命周期。该生命周期的一部分是“onCreateView”方法,这通常是“findByView”返回 null 的原因。

从您的代码来看,我无法为您提供快速修复。只是一个建议——你应该像对待活动一样对待你的片段——如果你想让你的片段从一些初始状态开始——你应该设置它的参数。通过这样做,您无需介入这些生命周期步骤并找到null价值。

于 2013-05-13T16:34:14.693 回答
0

您可以尝试在 oncreatview 中投射活动

parentActivity = (Activity_Help) getActivity();

parentActivity.setActionBarTitle("新标题");

于 2013-05-13T16:26:15.503 回答
0

问题在于 dmon 建议 FragmentTransaction 中的片段正在以错误的顺序初始化

于 2013-06-27T10:43:06.787 回答