我一直在关注这个并试图解决问题一天,但没有运气。我通常会把问题作为最后的衡量标准,所以我现在有点绝望,因为在其他问题中建议的任何事情都不适合我......而且我一直在尝试数百种解决方案。可能是我在找出问题的正确方法时遇到了问题。
以下是我项目中的内容:
我的项目中所有活动都扩展的基础片段活动类:
public abstract class BaseFragmentActivity extends SherlockFragmentActivity implements IActivity {
protected CacheFragment cacheFragment;
/*
* (non-Javadoc)
*
* @see
* com.actionbarsherlock.app.SherlockActivity#onOptionsItemSelected(com.
* actionbarsherlock.view.MenuItem)
*/
@Override
public boolean onOptionsItemSelected(final MenuItem item) {
NavigationHandler.switchToActivity(this, item.getItemId());
return true;
}
/*
* (non-Javadoc)
*
* @see android.app.Activity#onCreate(android.os.Bundle)
*/
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.getSupportActionBar().setHomeButtonEnabled(this.isHomeButtonEnabled());
this.getSupportActionBar().setDisplayHomeAsUpEnabled(this.isHomeDisplayedAsUp());
}
/**
* Returns whether the home button is enabled.
*
* @return <code>TRUE</code> if the home button is enabled.
*/
public abstract boolean isHomeButtonEnabled();
/**
* Returns whether the home button should be displayed as an up button with
* a arrow on the left.
*
* @return <code>TRUE</code> if the home button should be shown with an
* arrow.
*/
public abstract boolean isHomeDisplayedAsUp();
/**
* Gets the cache manager of the given fragment activity.
*/
public CacheManager getCacheManager() {
if (this.cacheFragment == null) {
this.cacheFragment = CacheFragment.getOrCreateCacheFragment(this.getSupportFragmentManager(), this);
}
return this.cacheFragment.getCacheManager();
}
/*
* (non-Javadoc)
*
* @see com.actionbarsherlock.app.SherlockFragmentActivity#onPause()
*/
@Override
protected void onPause() {
super.onPause();
if (this.cacheFragment != null) {
this.cacheFragment.getCacheManager().flushDiskCache();
}
}
}
具有两种不同布局(纵向布局)和横向布局的家庭活动,它扩展了基本活动类:
人像:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".HomeActivity" >
<fragment
android:id="@+id/teaserFragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
class="com.nikolov.ivan.android.metalafisha.fragments.TeaserListFragment" >
</fragment>
</RelativeLayout>
风景:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:baselineAligned="true"
android:orientation="horizontal"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".HomeActivity" >
<fragment
android:id="@+id/teaserFragment"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="2"
class="com.nikolov.ivan.android.metalafisha.fragments.TeaserListFragment" >
</fragment>
<fragment
android:id="@+id/articleFragment"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginLeft="@dimen/article_detail_landscape_margin_left"
android:layout_weight="3"
class="com.nikolov.ivan.android.metalafisha.fragments.ArticleFragment" >
</fragment>
</LinearLayout>
预告片段:
布局:
<?xml version="1.0" encoding="utf-8"?>
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/lvItems"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:choiceMode="singleChoice" >
</ListView>
文章片段:
布局:
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/scrollArticle"
android:layout_width="fill_parent"
android:layout_height="wrap_content" >
<LinearLayout
android:id="@+id/layoutLinear"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
</LinearLayout>
</ScrollView>
缓存片段:
public class CacheFragment extends SherlockFragment {
private static final String TAG = "CacheFragment";
private CacheManager cacheManager;
public CacheFragment() {
}
/**
* Gets the application cache fragment or creates a new one.
*/
public static CacheFragment getOrCreateCacheFragment(final FragmentManager fm, final Context context) {
CacheFragment result = (CacheFragment) fm.findFragmentByTag(CacheFragment.TAG);
if (result == null) {
result = new CacheFragment();
result.cacheManager = new CacheManager(context);
FragmentTransaction ft = fm.beginTransaction();
ft.add(result, CacheFragment.TAG);
ft.commit();
}
return result;
}
public CacheManager getCacheManager() {
return this.cacheManager;
}
/*
* (non-Javadoc)
*
* @see
* android.support.v4.app.Fragment#onCreateView(android.view.LayoutInflater,
* android.view.ViewGroup, android.os.Bundle)
*/
@Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
return null;
}
/*
* (non-Javadoc)
*
* @see android.support.v4.app.Fragment#onCreate(android.os.Bundle)
*/
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.setRetainInstance(true);
}
}
缓存片段的想法是没有UI,并且在配置更改期间使用和保留。所有磁盘访问都在不同于主要线程的线程上完成。
现在有两种情况:
logcat的:
09-08 15:41:37.104: E/AndroidRuntime(1731): FATAL EXCEPTION: main
09-08 15:41:37.104: E/AndroidRuntime(1731): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.nikolov.ivan.android.metalafisha/com.nikolov.ivan.android.metalafisha.HomeActivity}: android.view.InflateException: Binary XML file line #21: Error inflating class fragment
09-08 15:41:37.104: E/AndroidRuntime(1731): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2663)
09-08 15:41:37.104: E/AndroidRuntime(1731): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679)
09-08 15:41:37.104: E/AndroidRuntime(1731): at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:3815)
09-08 15:41:37.104: E/AndroidRuntime(1731): at android.app.ActivityThread.access$2400(ActivityThread.java:125)
09-08 15:41:37.104: E/AndroidRuntime(1731): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2037)
09-08 15:41:37.104: E/AndroidRuntime(1731): at android.os.Handler.dispatchMessage(Handler.java:99)
09-08 15:41:37.104: E/AndroidRuntime(1731): at android.os.Looper.loop(Looper.java:123)
09-08 15:41:37.104: E/AndroidRuntime(1731): at android.app.ActivityThread.main(ActivityThread.java:4627)
09-08 15:41:37.104: E/AndroidRuntime(1731): at java.lang.reflect.Method.invokeNative(Native Method)
09-08 15:41:37.104: E/AndroidRuntime(1731): at java.lang.reflect.Method.invoke(Method.java:521)
09-08 15:41:37.104: E/AndroidRuntime(1731): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
09-08 15:41:37.104: E/AndroidRuntime(1731): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
09-08 15:41:37.104: E/AndroidRuntime(1731): at dalvik.system.NativeStart.main(Native Method)
09-08 15:41:37.104: E/AndroidRuntime(1731): Caused by: android.view.InflateException: Binary XML file line #21: Error inflating class fragment
09-08 15:41:37.104: E/AndroidRuntime(1731): at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:582)
09-08 15:41:37.104: E/AndroidRuntime(1731): at android.view.LayoutInflater.rInflate(LayoutInflater.java:618)
09-08 15:41:37.104: E/AndroidRuntime(1731): at android.view.LayoutInflater.inflate(LayoutInflater.java:407)
09-08 15:41:37.104: E/AndroidRuntime(1731): at android.view.LayoutInflater.inflate(LayoutInflater.java:320)
09-08 15:41:37.104: E/AndroidRuntime(1731): at android.view.LayoutInflater.inflate(LayoutInflater.java:276)
09-08 15:41:37.104: E/AndroidRuntime(1731): at com.actionbarsherlock.internal.ActionBarSherlockCompat.setContentView(ActionBarSherlockCompat.java:840)
09-08 15:41:37.104: E/AndroidRuntime(1731): at com.actionbarsherlock.app.SherlockFragmentActivity.setContentView(SherlockFragmentActivity.java:262)
09-08 15:41:37.104: E/AndroidRuntime(1731): at com.nikolov.ivan.android.metalafisha.HomeActivity.onCreate(HomeActivity.java:27)
09-08 15:41:37.104: E/AndroidRuntime(1731): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
09-08 15:41:37.104: E/AndroidRuntime(1731): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2627)
09-08 15:41:37.104: E/AndroidRuntime(1731): ... 12 more
09-08 15:41:37.104: E/AndroidRuntime(1731): Caused by: java.lang.IllegalStateException: Fragment com.nikolov.ivan.android.metalafisha.fragments.ArticleFragment did not create a view.
09-08 15:41:37.104: E/AndroidRuntime(1731): at android.support.v4.app.FragmentActivity.onCreateView(FragmentActivity.java:293)
09-08 15:41:37.104: E/AndroidRuntime(1731): at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:558)
09-08 15:41:37.104: E/AndroidRuntime(1731): ... 21 more
当我在切换到横向模式之前创建了 CacheFragment 时,似乎发生了一些奇怪的事情。
我注意到的另一件事是,当Android文档声明不应该为没有UI片段调用时,我会看到对 onCreateView 的调用。
我确保我在布局文件中有ID,我甚至检查它们是否对应用程序是全局唯一的以及许多其他似乎合理的东西,但我仍然看到相同的结果。唯一不会发生这种情况的方法是,如果我不在事务中添加 CacheFragment ,那么实际上没有任何意义......
根据消息,Android似乎将 CacheFragment 与 ArticleFragment 混淆......
任何帮助将不胜感激,因为我似乎没有想法我可能做错了什么!
答案 0 :(得分:1)
所以...经过几天敲打我的脑袋并试图确保这不是我的代码是错误的,我在Android代码中寻找解决方案,我在几分钟内找到了它。从第一步开始,我应该首先查看Android问题跟踪器......
从我的示例中可以看出,我有两种不同方向的布局。发生的事情是,当为肖像创建活动时,只添加一个UI片段而另一个片段是无头的。无头片段被添加到 viewId == 0 。这对理解正在发生的事情非常重要。
现在看一下support-v4 / r7代码,更具体地说是FragmentActivity类的第225行到第303行:
@Override
public View onCreateView(String name, Context context, AttributeSet attrs) {
if (!"fragment".equals(name)) {
return super.onCreateView(name, context, attrs);
}
String fname = attrs.getAttributeValue(null, "class");
TypedArray a = context.obtainStyledAttributes(attrs, FragmentTag.Fragment);
if (fname == null) {
fname = a.getString(FragmentTag.Fragment_name);
}
int id = a.getResourceId(FragmentTag.Fragment_id, View.NO_ID);
String tag = a.getString(FragmentTag.Fragment_tag);
a.recycle();
View parent = null; // NOTE: no way to get parent pre-Honeycomb.
int containerId = parent != null ? parent.getId() : 0;
if (containerId == View.NO_ID && id == View.NO_ID && tag == null) {
throw new IllegalArgumentException(attrs.getPositionDescription()
+ ": Must specify unique android:id, android:tag, or have a parent with an id for " + fname);
}
// If we restored from a previous state, we may already have
// instantiated this fragment from the state and should use
// that instance instead of making a new one.
Fragment fragment = id != View.NO_ID ? mFragments.findFragmentById(id) : null;
if (fragment == null && tag != null) {
fragment = mFragments.findFragmentByTag(tag);
}
if (fragment == null && containerId != View.NO_ID) {
fragment = mFragments.findFragmentById(containerId);
}
if (FragmentManagerImpl.DEBUG) Log.v(TAG, "onCreateView: id=0x"
+ Integer.toHexString(id) + " fname=" + fname
+ " existing=" + fragment);
if (fragment == null) {
fragment = Fragment.instantiate(this, fname);
fragment.mFromLayout = true;
fragment.mFragmentId = id != 0 ? id : containerId;
fragment.mContainerId = containerId;
fragment.mTag = tag;
fragment.mInLayout = true;
fragment.mFragmentManager = mFragments;
fragment.onInflate(this, attrs, fragment.mSavedFragmentState);
mFragments.addFragment(fragment, true);
} else if (fragment.mInLayout) {
// A fragment already exists and it is not one we restored from
// previous state.
throw new IllegalArgumentException(attrs.getPositionDescription()
+ ": Duplicate id 0x" + Integer.toHexString(id)
+ ", tag " + tag + ", or parent id 0x" + Integer.toHexString(containerId)
+ " with another fragment for " + fname);
} else {
// This fragment was retained from a previous instance; get it
// going now.
fragment.mInLayout = true;
// If this fragment is newly instantiated (either right now, or
// from last saved state), then give it the attributes to
// initialize itself.
if (!fragment.mRetaining) {
fragment.onInflate(this, attrs, fragment.mSavedFragmentState);
}
mFragments.moveToState(fragment);
}
if (fragment.mView == null) {
throw new IllegalStateException("Fragment " + fname
+ " did not create a view.");
}
if (id != 0) {
fragment.mView.setId(id);
}
if (fragment.mView.getTag() == null) {
fragment.mView.setTag(tag);
}
return fragment.mView;
}
这是 onCreateView 方法。现在深入了解以下一行:
int containerId = parent != null ? parent.getId() : 0;
让我们假设我们以纵向模式启动了应用程序。这意味着我们的活动中有两个片段:TeaserListFragment及其ID和无头片段。如果我们现在切换方向,我们将不得不添加另一个片段 - ArticleFragment,它是横向布局文件中的第二个片段。以下是将要发生的事情:
第255行:
fragment = mFragments.findFragmentById(containerId);
这将返回无头片段(因为上面提到的viewId)而不是 null ,这就是错误发生的原因。我设法调试它并将containerId的值更改为-1,它工作正常。通常,解决方案是注释掉以下代码:
if (fragment == null && containerId != View.NO_ID) {
fragment = mFragments.findFragmentById(containerId);
}
这些是第254到256行。同时将containerId的默认值设为-1应该没问题,但我相信删除多余的 if 更好,以便保留未设置的检查的ID ...