我的活动包含一个包含项目列表的片段。
活动类:
public class CategoryActivity extends ActionBarActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_subcategory);
setupActionBar();
CategoryFragment fragment = (CategoryFragment) getSupportFragmentManager().findFragmentById(R.id.category_fragment);
fragment.setBrand(mBrand);
}
@Override
public void onDestroy() {
super.onDestroy();
UIUtils.unbindDrawables(findViewById(R.id.RootView));
CategoryFragment fragment = (CategoryFragment) getSupportFragmentManager().findFragmentById(R.id.category_fragment);
if(fragment != null)
getSupportFragmentManager().beginTransaction().remove(fragment).commit();
System.gc();
}
public static class CategoryFragment extends Fragment {
private ListView mListView;
private CategoryAdapter mAdapter;
private Category mRoot;
private List<Category> mCategories;
private Brand brand;
public CategoryFragment(){}
public void setBrand(Brand brand) {
this.brand = brand;
}
private boolean mIsAnimating;
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_category, container, false);
mListView = (ListView) view.findViewById(R.id.list_view);
try {
if (mCategories == null) {
loadCategories(AppController.getInstance().getCategory());
}
if (mCategories != null) {
mAdapter = new CategoryAdapter(getActivity(), mRoot);
mAdapter.setListener(new CategoryAdapter.Listener() {
@Override
public void onCategoryClick(String category) {
if (brand == null) return;
Utils.openQueryView(getActivity(), category, brand);
}
@Override
public void openSubcategory(Category category) {
openSubcategoriesView(category);
}
@Override
public void onBrowseAllClick(Category category) {
if (brand == null) return;
if (category.name.equals(Category.ROOT)) {
Utils.openQueryView(getActivity(), category.name, brand);
} else {
Utils.openStoreActivity(getActivity(), category, brand);
}
}
});
mListView.setAdapter(mAdapter);
}
}catch (Exception e){
LOGD(TAG, e.getMessage());
return view;
}
return view;
}
private void loadCategories(Category root) {
// stuff here... it work well
}
private void openSubcategoriesView(Category category) {
AnalyticsManager.sendScreenView(SCREEN_NAME);
final CategoryFragment fragment = new CategoryFragment();
fragment.setCategories(category);
fragment.setBrand(brand);
if (mIsAnimating) {
return;
}
mIsAnimating = true;
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.setCustomAnimations(R.anim.slide_in_right, 0, 0,
R.anim.slide_out_right);
transaction.add(R.id.category_fragment, fragment);
transaction.addToBackStack(null);
transaction.commit();
mIsAnimating = false;
List<Fragment> fs = getFragmentManager().getFragments();
for(int i = 0; i< fs.size(); i++){
LOGD(TAG, "fragment[" + i + "]: " + fs.get(i).getActivity());
}
}
public void setCategories(Category category) {
loadCategories(category);
}
}
}
活动布局xml:
<fragment android:id="@+id/the_main_fragment" android:tag="firstFragment" android:name="com.greelane.gapp.ui.CategoryActivity$CategoryFragment" android:layout_width="match_parent" android:layout_height="match_parent" /> <LinearLayout android:background="@drawable/header_shadow" android:layout_width="match_parent" android:layout_height="12dp"></LinearLayout> </RelativeLayout>
每当我点击一个项目时,一个新的 CategoryFragment 将被添加到此活动的 FragmentManager 中,并在xml布局(category_fragment id)中使用相同的Fragment类作为子项如果孩子有孩子,这个概念将会重复。
每次点击某个项目时,我都会尝试记录以查看我有多少片段:
功能 openSubcategoriesView
List<Fragment> fs = getFragmentManager().getFragments();
// fs size > 1, but just one instance of CategoryFragment
for(int i = 0; i< fs.size(); i++){
LOGD(TAG, "fragment[" + i + "]: " + fs.get(i).getActivity());
}
导航到活动后第一次点击某个项目,它只创建一个片段,因此 fs 大小为1;
然后我点击返回&gt;点击另一个项目,我看到 fs 大小为2,但我找到了 CategoryFragment 的一个实例。
我不知道它如何与活动中的片段一起使用,但有时我的应用程序在 onCreateActivity setContentView(R.layout.activity_subcategory)的这一行崩溃;
错误日志:
引起:android.view.InflateException:二进制XML文件行#14:错误膨胀类片段
第14行从我的xml布局
开始片段 android:id =“@ + id / category_fragment”......
所以问题是:
为什么我在添加多次后只有一个 CategoryFragment 实例以及如何解决此问题?
为什么有时我会得到上面描述的膨胀异常广告以及如何解决此问题?
#Updated1
第二个问题的错误日志,找不到任何异常堆栈跟踪:
01-21 11:16:54.276 16783-16783/? W/System.err: java.lang.RuntimeException: Unable to start activity ComponentInfo{vn.app.alezaa/com.greelane.gapp.ui.CategoryActivity}: android.view.InflateException: Binary XML file line #14: Error inflating class fragment
01-21 11:16:54.279 16783-16783/? W/System.err: Caused by: android.view.InflateException: Binary XML file line #14: Error inflating class fragment
01-21 11:16:54.282 16783-16783/? W/System.err: Caused by: android.support.v4.app.Fragment$InstantiationException: Unable to instantiate fragment com.greelane.gapp.ui.CategoryActivity$CategoryFragment: make sure class name exists, is public, and has an empty constructor that is public
01-21 11:16:54.286 16783-16783/? W/System.err: Caused by: java.lang.InstantiationException: can't instantiate class com.greelane.gapp.ui.CategoryActivity$CategoryFragment; no empty constructor
#Updated2
android:name=...CategoryActivity.CategoryFragment
代替android:name=...CategoryActivity$CategoryFragment
但仍有相同的错误我编写了我的代码来添加新的CategoryFragment,如:
final CategoryFragment fragment = new CategoryFragment();
fragment.setCategories(category);
fragment.setBrand(brand);
if (mIsAnimating) {
return;
}
mIsAnimating = true;
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction
.setCustomAnimations(R.anim.slide_in_right, 0, 0, R.anim.slide_out_right)
.replace(R.id.container, fragment, category.title)// set tag is title of ctg
.addToBackStack(category.title)
.commit();
mIsAnimating = false;
List<Fragment> fs = getFragmentManager().getFragments();
// `error raised here after two times add CategoryFragment, the **fs** size > 1, but just one instance of it.`
for(int i = 0; i< fs.size(); i++){
LOGD(TAG, "fragment[" + i + "]: " + fs.get(i).getActivity());
}
编辑的xml布局:
<fragment android:id="@+id/the_main_fragment" android:tag="firstFragment" android:name="com.greelane.gapp.ui.CategoryActivity$CategoryFragment" android:layout_width="match_parent" android:layout_height="match_parent" /> <LinearLayout android:background="@drawable/header_shadow" android:layout_width="match_parent" android:layout_height="12dp"></LinearLayout> </RelativeLayout>
或者我需要将CategoryFragment分离到其他类并转向非静态,因为现在我无法删除静态。有什么想法吗?
答案 0 :(得分:0)
要回答您多次加载相同片段的问题,可以查看here,注意部分中的内容
每个片段都需要系统可以使用的唯一标识符 如果重新启动活动,则恢复片段(以及可以执行的操作) 用于捕获片段以执行事务,例如remove 它)。有三种方法可以为片段提供ID:
- 使用唯一ID提供android:id属性。
- 使用唯一字符串提供android:tag属性。
- 如果您不提供前两个,系统将使用容器视图的ID。
因此,您可以多次使用相同的片段,但如果通过layout.xml添加唯一ID和标记,或者如果通过代码添加,则需要使用唯一标记。
在您的情况下,您可以考虑使用Category对象中的一些唯一字段在加载片段时用作TAG,因此您加载的每个CategoryFragment实例都将具有唯一标记,并且在fragmentmanager堆栈中将被视为唯一。
关于你的第二个问题,两个建议
将xml中fragment标签中的class属性更改为android:name并添加完全限定的片段类名,即
android:name = "mypackage.CategoryFragment"
同样根据您的崩溃检查,提到 java.lang.InstantiationException:无法实例化类com.greelane.gapp.ui.CategoryActivity $ CategoryFragment;没有空构造函数。因此,创建一个空的或默认的构造函数,如
public CategoryFragment(){
}
答案 1 :(得分:0)
关于这个错误,我终于想通了
List<Fragment> fs = getFragmentManager().getFragments();
// `error raised here after two times add CategoryFragment, the **fs** size > 1, but just one instance of it.`
for(int i = 0; i< fs.size(); i++){
LOGD(TAG, "fragment[" + i + "]: " + fs.get(i).getActivity());
}
基于该文件,
调用commit()不会立即执行事务。相反,一旦线程能够这样做,它就会将其安排在活动的UI线程(&#34; main&#34;线程)上运行。但是,如果需要,您可以从UI线程调用executePendingTransactions()以立即执行commit()提交的事务。除非事务是其他线程中作业的依赖项,否则通常不需要这样做。
所以我们需要等待一段时间才能完成提交。现在好了。
但仍在等待测试我上面提到的第二个错误。如果有一个好的结果,我会很快得到更新。