进度条一直显示不消失

在程序中使用进度条,但是出现这个情况:进度条一直显示很久很久都不消失。在程序中使用显示和隐藏进度条的代码片段如下所示

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;
}