Android 片段标记vs实用地将片段添加到布局中

Android 片段标记vs实用地将片段添加到布局中,android,static,calendar,Android,Static,Calendar,最终更新 结果发现我把问题全搞错了。这就是我使用片段标签的方式。请参阅下面我的答案以获得完整的解释 更新3: 所以我一直在胡闹几个小时,没有这样的运气。我已经能够使它达到一个不会崩溃的点。但现在我相信我知道问题可能是什么了。它将我的calendarAdapter设置为null,因为它是null,但不是出于我的意图。似乎onCreateView运行了两次,一次是在发送任何内容之前,一次是在我正式发送一些参数之后。这当然不应该发生。。。我想。我将提供在底部设置ActionBar的部分,这样您就可以让

最终更新

结果发现我把问题全搞错了。这就是我使用片段标签的方式。请参阅下面我的答案以获得完整的解释

更新3: 所以我一直在胡闹几个小时,没有这样的运气。我已经能够使它达到一个不会崩溃的点。但现在我相信我知道问题可能是什么了。它将我的
calendarAdapter
设置为null,因为它是null,但不是出于我的意图。似乎
onCreateView
运行了两次,一次是在发送任何内容之前,一次是在我正式发送一些参数之后。这当然不应该发生。。。我想。我将提供在底部设置ActionBar的部分,这样您就可以让我知道我是否做了一些错误的事情,以便将此行为设置为正确的方式


出于某种原因,我对这件事有意见,我不知道为什么。我有一个名为
MainDisplayActivity
的活动和一个名为
MainDislpayFragment
的片段。正如您所想象的,活动在appstart上设置了片段。这就是问题所在,我一直试图将来自日历的三个数字作为参数发送到
newInstance
构造函数中。然后,我从构造函数中创建了日历。但我的应用程序崩溃了。奇怪的是,当我阻止静态字段使用日历时,应用程序按预期工作,但试图使用来自构造函数的任何内容的日历会导致崩溃。这是一个示例方法:

private static Calendar cal;

static MainDisplayFragment newInstance(Context context, int y, int m, int d) {

    c = context;
    MainDisplayFragment f = new MainDisplayFragment();
    //static global Calendar now
            cal = Calendar.getInstance();
            cal.set(y, m, d);
}//end of static newInstance method
现在重要的是要注意,即使我尝试取出日历并将其放入onCreate中,并且只保留作为全局返回的静态int,并将它们设置在那里,它仍然会导致崩溃。值得注意的错误和奇怪的事情是,出于某种原因,它似乎认为日历是空的。正如你所知道的,它肯定是被创造出来的。但现在我开始认为日历和静态字段存在问题。如果没有,那么我可能有一个错误,但如果可以的话,我想排除这个错误。谢谢大家的回复

更新:我应该提到,我使用日历信息只是为了传递到我的
MyCalendarAdapter
。不管我只是将数字作为参数还是日历本身发送,它都会崩溃。我看到的第一个空异常是我试图设置
MyCalendarAdapter

第75行将是此处的最后一个lin:

public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    view = inflater.inflate(R.layout.main_fragment, container, false);
    calendarAdapter = new MyCalendarAdapter(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH));
更新2


经过更多的胡闹,我意识到问题出在
MyCalendarAdapter
上,但这是一个毫无意义的问题。如果实例化一个calendarAdapter时没有参数,它似乎工作得很好,但是如果有参数,它就会崩溃。这是
MyCalendarAdapter
的两个构造函数,因此人们可以看到没有任何问题,这使情况变得更糟,因为我不知道如何解决这个问题。同样重要的是要知道,我试图移动到片段的这段代码最初来自一个活动,它工作得非常好

public MyCalendarAdapter() {
    thisMonth = Calendar.getInstance();
    now = new MonthDisplayHelper(thisMonth.get(Calendar.YEAR), thisMonth.get(Calendar.MONTH));//creating Helper for month display
    currentDay = thisMonth.get(Calendar.DAY_OF_MONTH);//sets current day

    ...

}

public MyCalendarAdapter(int year, int month, int currentDay) {
    thisMonth = Calendar.getInstance();
    now = new MonthDisplayHelper(year, month);
    this.currentDay = currentDay;

    ...

}
完整的错误列表


设置片段的操作栏部分

@Override
public boolean onNavigationItemSelected(int itemPosition, long itemId) {
    Toast.makeText(this, "Position is "+itemPosition, Toast.LENGTH_SHORT).show();
    if(itemPosition == 0) {
        FragmentTransaction ft = getFragmentManager().beginTransaction();

        //check to see if one already exists and remove it
        Fragment prev = getFragmentManager().findFragmentByTag(MAIN_FRAGMENT);
        if(prev!=null) {
            ft.remove(prev);
            Toast.makeText(this, "Fragment was found", Toast.LENGTH_SHORT).show();
        }
        MyCalendarAdapter calendarAdapter = new MyCalendarAdapter(year, month, day);
        //Log.d("MAINDISPLAYACTIVTY", "calendarAdapter year is "+calendarAdapter.getCalendar().getYear());
        currentFragment = MainDisplayFragment.newInstance(this, year, month, day, calendarAdapter);
        ft.add((MainDisplayFragment)currentFragment, MAIN_FRAGMENT);
        ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
        //ft.addToBackStack(null); //i do not want this behavior
        ft.commit();
        return true;
    }
... continues on with the other cases
在设置操作栏的活动中创建

final ActionBar bar = getActionBar();
    bar.setDisplayShowTitleEnabled(false);
    bar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
    bar.setListNavigationCallbacks(new ArrayAdapter<String>(bar.getThemedContext(), android.R.layout.simple_list_item_1, android.R.id.text1,
                                                    new String[]{"MONTH", "WEEK", "DAY"}), this);

    if(savedInstanceState == null) {
        bar.setSelectedNavigationItem(0);
    } else {
        bar.setSelectedNavigationItem(savedInstanceState.getInt(SELECTED_NAVIGATION_STATE));
    }
final ActionBar=getActionBar();
bar.setDisplayShowTitleEnabled(假);
设置导航模式(操作栏导航模式列表);
bar.setListNavigationCallbacks(新的ArrayAdapter(bar.getThemedContext(),android.R.layout.simple_列表_项_1,android.R.id.text1,
新字符串[]{“月”、“周”、“日”}),this);
如果(savedInstanceState==null){
bar.setSelectedNavigationItem(0);
}否则{
bar.setSelectedNavigationItem(savedInstanceState.getInt(SELECTED_NAVIGATION_STATE));
}

所以我找到了我的问题所在。这是Android文档中关于碎片的不太清楚的东西。我在main.xml文件中使用了
标记。我正确地使用了它,在创建片段时,我也正确地设置了它。不幸的是,我没有得到我所希望的行为

事实证明,如果在xml中使用fragment标记,那么当
setContentView
运行时,它也会立即运行fragment类(至少当它在文件中遇到标记时)。这意味着,如果您的片段依赖于您从中启动它的活动的信息,它将不会拥有它,并且基本上会运行两次;当setContentView运行时,以及当您实际运行片段时。这很重要,因为我假设您可以选择任何一种方式来运行片段。但在现实中,你设计应用程序的方式或方法实际上决定了你应该走哪条路,硬编码一个片段,还是在飞行中实用


也许这对android专家来说是显而易见的,但我对碎片还不熟悉,所以我猜这是新手犯的错误。无论哪种情况,Android文档中都应该详细说明这一点。希望这能帮助其他对此完全困惑的人。

在这里实例化日历没有问题。能否向我们展示日历静态字段声明、如何访问它以及NPE的堆栈跟踪?@m0skit0添加了更多信息。至少相关的种类什么是currentDate,它设置在哪里?抱歉,这在上面的代码示例中不可见。打字错误我又把它弄得乱七八糟了。在这里,我决定将其命名为
cal
,但在我的代码中,它实际上是
currentDate
,哪一行是MainDisplayFragment.java:75?无论如何,您必须在第一个错误时首先修复XML。
final ActionBar bar = getActionBar();
    bar.setDisplayShowTitleEnabled(false);
    bar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
    bar.setListNavigationCallbacks(new ArrayAdapter<String>(bar.getThemedContext(), android.R.layout.simple_list_item_1, android.R.id.text1,
                                                    new String[]{"MONTH", "WEEK", "DAY"}), this);

    if(savedInstanceState == null) {
        bar.setSelectedNavigationItem(0);
    } else {
        bar.setSelectedNavigationItem(savedInstanceState.getInt(SELECTED_NAVIGATION_STATE));
    }