进度条一直显示不消失
在程序中使用进度条,但是出现这个情况:进度条一直显示很久很久都不消失。在程序中使用显示和隐藏进度条的代码片段如下所示
public void showProgressDialog(String msg) { if(progressDialog != null && progressDialog.isShowing()) { progressDialog.dismiss(); progressDialog = null; } progressDialog = ProgressDialog.show(context, "", msg); } public void hideProgressDialog() { if(progressDialog != null && progressDialog.isShowing()) { progressDialog.dismiss(); progressDialog = null; } }
在程序中调用以上方法的代码片段是
@Override public void onRequestStarted(int requestCode) { switch(requestCode) { case REQUEST_GET_TJ: showProgressDialog("正在加载数据,请稍等..."); break; } } @Override public void onRequestFinished(int requestCode, int resultCode, IVideoResult result) { switch(requestCode) { case REQUEST_GET_TJ: hideProgressDialog(); processGetTJ(resultCode, result); break; } }
在Fragment嵌套Fragment时出现以下错误
Binary XML file line #49: Duplicate id 0x7f070071, tag null, or parent id 0x0 with another fragment for com.tvie.ivideo.pad.main.HotVideoFragment
11-18 11:33:45.851: E/AndroidRuntime(8376): android.view.InflateException: Binary XML file line #49: Error inflating class fragment 11-18 11:33:45.851: E/AndroidRuntime(8376): Caused by: java.lang.IllegalArgumentException: Binary XML file line #49: Duplicate id 0x7f070071, tag null, or parent id 0x0 with another fragment for com.tvie.ivideo.pad.main.HotVideoFragment 11-18 11:33:45.851: E/AndroidRuntime(8376): at android.support.v4.app.FragmentActivity.onCreateView(FragmentActivity.java:285) 11-18 11:33:45.851: E/AndroidRuntime(8376): at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:685) 11-18 11:33:45.851: E/AndroidRuntime(8376): ... 23 more
嵌套的Fragment布局如下所示(fragment_main.xml)
<ScrollView android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <LinearLayout android:id="@+id/center_layout" android:layout_width="match_parent" android:layout_height="200dp" android:orientation="horizontal" > <fragment android:id="@+id/hot_video_fragment" android:layout_width="0dp" android:layout_weight="2" android:layout_height="match_parent" class="com.tvie.ivideo.pad.main.HotVideoFragment" /> <fragment android:id="@+id/my_channel_fragment" android:layout_width="0dp" android:layout_weight="1" android:layout_height="match_parent" class="com.tvie.ivideo.pad.main.MyChannelFragment" /> </LinearLayout> <fragment android:id="@+id/recommand_fragment" android:layout_width="match_parent" android:layout_height="wrap_content" class="com.tvie.ivideo.pad.main.RecommandFragment" /> </LinearLayout> </ScrollView>
Fragment嵌套和销毁问题
1、不要直接将Fragement写在XML文件里,这样会导致Fragment对象无法销毁,产生内存溢出。在代码动态的new 和add Fragement才是正确的做法。
2、使用抽屉方法,在XML文件里放两个LinearLayout,然后在代码中将Fragment加进这两个LinearLayout中。
要移动Fragment,就是移动LinearLayout,可以通过修改margin值来达到渐变移动的效果。
记得当Fragment移除屏幕的时候,detach掉它。
动态添加Fragment
参考1:初识Fragmentの动态添加
http://www.doc88.com/p-383778428274.html
参考2:Dynamically add fragment into fragment
http://stackoverflow.com/questions/7915413/dynamically-add-fragment-into-fragment
企图调用LinearLayout的addView方法添加Fragment(如下所示)
经过验证这个方法不可行
private void initializeFragments() { Logger.v(TAG, "@initializeFragments."); recmdFragment = new RecommandFragment(); hotFragment = new HotVideoFragment(); channelFragment = new MyChannelFragment(); linearLayout1.addView(recmdFragment.getView(), new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT)); linearLayout2.addView(hotFragment.getView(), new LayoutParams(linearLayout1.getMeasuredWidth() * 2 / 3, LayoutParams.MATCH_PARENT)); linearLayout2.addView(channelFragment.getView(), new LayoutParams(linearLayout1.getMeasuredWidth() * 1 / 3, LayoutParams.MATCH_PARENT)); }
参考stackoverflow网站上的资料,得到正确添加Fragment的方法
private void initializeFragments() { Logger.v(TAG, "@initializeFragments."); hotFragment = new HotVideoFragment(); channelFragment = new MyChannelFragment(); recmdFragment = new RecommandFragment(); FragmentTransaction trac = getFragmentManager().beginTransaction(); trac.add(R.id.hot_video_fragment, hotFragment); trac.add(R.id.my_channel_fragment, channelFragment); trac.add(R.id.recommand_fragment, recmdFragment); trac.commit(); }
再看下布局文件也被重新定义,将原来Fragment标记全部改为LinearLayout
<ScrollView android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" > <LinearLayout android:id="@+id/linearLayout1" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical"> <LinearLayout android:id="@+id/linearLayout2" android:layout_width="match_parent" android:layout_height="300dp" android:orientation="horizontal" > <LinearLayout android:id="@+id/hot_video_fragment" android:layout_width="0dp" android:layout_weight="2" android:layout_height="match_parent" android:orientation="vertical"/> <LinearLayout android:id="@+id/my_channel_fragment" android:layout_width="0dp" android:layout_weight="1" android:layout_height="match_parent" android:orientation="vertical" /> </LinearLayout> <LinearLayout android:id="@+id/recommand_fragment" android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="vertical" /> </LinearLayout> </ScrollView>
是在onCreateView方法调用initializeFragment的吗?NO,是在onLayoutChange方法中调用
private void initializeView() { linearLayout1.addOnLayoutChangeListener(new View.OnLayoutChangeListener() { @Override public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { initializeFragments(); linearLayout1.removeOnLayoutChangeListener(this); } }); }
变量context竟然null值
先看打印出来的日志
11-18 13:44:49.531: V/MainFragment(21389): @onCreateView 11-18 13:44:49.541: V/MainFragment(21389): @initializeView. create each fragment. 11-18 13:44:49.541: V/MainFragment(21389): @onActivityCreated. data isn't null. data.size >> 5 11-18 13:44:49.541: V/HotVideoFragment(21389): @createHotImageView. context >> null
从日志来看:第二次启动推荐首页,先后要执行MainFragment的onCreateView方法,onActivityCreated方法,但是没有执行HotVideoFragment的onCreateView方法,onActivityCreated方法
新建Fragment会调用onCreate方法
嵌套在Fragment中的子Fragment。每次创建XXXFragment对象时,都会去调用onCreate方法。至少要等XXXFragment的onCreate等方法执行完(即创建完成)再去操作XXXFragment的界面元素才不出问题。
以下日志显示程序运行正常,没有出现context空指针问题
11-18 14:31:36.261: V/MainFragment(25136): @onCreateView 11-18 14:31:36.271: V/MainFragment(25136): @initializeView. create each fragment. 11-18 14:31:36.271: V/MainFragment(25136): @onActivityCreated. data isn't null. data.size >> 5 11-18 14:31:36.271: V/MainFragment(25136): @onActivityCreated. ready >> false 11-18 14:31:36.271: V/MainFragment(25136): @onLayoutChange 11-18 14:31:36.271: V/MainFragment(25136): @initializeFragments. add fragments to parent. 11-18 14:31:36.281: V/RecommandFragment(25136): @onCreate 11-18 14:31:36.281: V/RecommandFragment(25136): @onCreateView 11-18 14:31:36.291: V/HotVideoFragment(25136): @onCreate 11-18 14:31:36.291: V/HotVideoFragment(25136): @onCreateView 11-18 14:31:36.341: V/MainFragment(25136): @onActivityCreated. after 73 ms, ready >> true 11-18 14:31:36.351: V/MainFragment(25136): @renderInFragments
程序中的代码片段,在onActivityCreated方法中创建线程进入等待状态
final long start = System.currentTimeMillis(); new Thread() { public void run() { while(!isReady() || !recmdFragment.isReady() || !hotFragment.isReady()) { try { Thread.sleep(1); } catch (InterruptedException e) { } } long end = System.currentTimeMillis(); Logger.v(TAG, "@onActivityCreated. after " + (end - start) + " ms, ready >> " + isReady()); handler.sendEmptyMessage(1); } }.start();
其中新建XXXFragment的onCreate方法的调用执行只跟FragmentTransaction.add方法有关系。纯粹调用XXXFragment的构造方法不会去调用执行onCreate方法,可是执行FragmentTransaction.add方法之后就不同,XXXFragment的onCreate方法就被调用。同样,当调用FragmentTransaction.remove方法之后,XXXFragment的onDestroy方法也会被调用。当然,在调用FragmentTransaction的add或remove方法之后必须调用FragmentTransaction的commit方法。
先看下打印出来的日志
11-18 15:12:53.971: V/MainFragment(29470): @onCreateView 11-18 15:12:53.971: V/MainFragment(29470): @initializeView. create each fragment. 11-18 15:12:53.971: V/MainFragment(29470): @initializeFragments. add fragments by FragmentTransaction. 11-18 15:12:53.971: V/MainFragment(29470): @onActivityCreated. data isn't null. data.size >> 5 11-18 15:12:53.971: V/MainFragment(29470): @onActivityCreated. ready >> false 11-18 15:12:53.971: V/RecommandFragment(29470): @onCreate 11-18 15:12:53.971: V/RecommandFragment(29470): @onCreateView 11-18 15:12:53.981: V/HotVideoFragment(29470): @onCreate 11-18 15:12:53.981: V/HotVideoFragment(29470): @onCreateView 11-18 15:12:54.011: V/MainFragment(29470): @onActivityCreated. after 41 ms, ready >> false 11-18 15:12:54.011: V/MainFragment(29470): @onLayoutChange 11-18 15:12:54.021: V/MainFragment(29470): @renderInFragments ... 11-18 15:13:37.021: V/MainFragment(29470): @onDestroyView. remove fragments. by FragmentTransaction. 11-18 15:13:37.031: V/HotVideoFragment(29470): @onDestroyView 11-18 15:13:37.031: V/HotVideoFragment(29470): @onDestroy 11-18 15:13:37.031: V/RecommandFragment(29470): @onDestroyView 11-18 15:13:37.031: V/RecommandFragment(29470): @onDestroy
再看下调用FragmentTransaction的add和remove方法的代码片段
private void initializeFragments() { Logger.v(TAG, "@initializeFragments. add fragments by FragmentTransaction."); FragmentTransaction trac = getFragmentManager().beginTransaction(); trac.add(R.id.hot_video_fragment, hotFragment); trac.add(R.id.my_channel_fragment, channelFragment); trac.add(R.id.recommand_fragment, recmdFragment); trac.commit(); } @Override public void onDestroyView() { Logger.v(TAG, "@onDestroyView. remove fragments. by FragmentTransaction."); super.onDestroyView(); FragmentTransaction trac = getFragmentManager().beginTransaction(); trac.remove(hotFragment); trac.remove(channelFragment); trac.remove(recmdFragment); trac.commit(); hotFragment = null; channelFragment = null; recmdFragment = null; linearLayout1 = null; }