Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android - Fragment from support library doesn't compatible well with 4.3 platform

I encounter a weird problem while using the support library.


I want to make a dynamic navigation tabs with fragments switching on the 2.3.3 platform, just like what API Demo did .

enter image description here


everything goes fine on 2.3.3 platform, but when I took a look at the same activity on the 4.3 platform, I found that something quite weird.

the SupportFragmentManagement cannot detach the fragment, seems like the tab selecting callback didn't execute correctly;

following pictures show how my demo go enter image description here

and here's my code:

package net.zengweizhi.android.gettingstarted.lesson05.test;
import net.zengweizhi.android.gettingstarted.R;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

// using the api from support library

import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.support.v7.app.ActionBar;
import android.support.v7.app.ActionBar.Tab;
import android.support.v7.app.ActionBar.TabListener;
import android.support.v7.app.ActionBarActivity;
public class NavigationTabsWithFragmentsV9 extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_navigation_tabs, menu);
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.actionButton_addTab:
            addTab();
            break;
        case R.id.actionButton_removeTab:
            removeTab();
            break;
        default:
            break;
        }
        return super.onOptionsItemSelected(item);
    }

    private int mTabSeq = 0;

    private void addTab(){
        getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);

        mTabSeq++;

        Tab tab = getSupportActionBar().newTab();
        tab.setText("TAB " + mTabSeq);
        tab.setTabListener(new MyTabListener(this));
        getSupportActionBar().addTab(tab);
    }

    private void removeTab(){
        Tab tab = getSupportActionBar().getSelectedTab();
        getSupportActionBar().removeTab(tab);

        Fragment fragment = getSupportFragmentManager().findFragmentByTag(tab.getText().toString());
        getSupportFragmentManager().beginTransaction().remove(fragment).commit();
        if( getSupportActionBar().getTabCount() == 0 ){
            getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
        }
    }

    private static final class MyTabListener  implements TabListener {
        private NavigationTabsWithFragmentsV9 mActivity;
        public MyTabListener(NavigationTabsWithFragmentsV9 activity /*,Fragment fragment*/){
            mActivity = activity;
        }

        @Override
        public void onTabReselected(Tab tab, FragmentTransaction ft) {
            // Do nothing
        }

        @Override
        public void onTabSelected(Tab tab, FragmentTransaction ft) {
            Object obj = tab.getTag();
            if( null == obj ){
                Bundle args = new Bundle();
                args.putString(SimpleFragment.EXTRA_OUTPUT_MESSAGE, tab.getText().toString());
                Fragment fragment = Fragment.instantiate(mActivity, SimpleFragment.class.getName(), args);
                ft.add(android.R.id.content, fragment, tab.getText().toString());

                tab.setTag(obj = fragment);
            }

            ft.attach((Fragment)obj);
        }

        @Override
        public void onTabUnselected(Tab tab, FragmentTransaction ft) {
            if( null != mActivity.getSupportFragmentManager().findFragmentByTag(tab.getText().toString()) ){
                ft.detach((Fragment)tab.getTag());
            }
        }

    }

    public static final class SimpleFragment extends Fragment {
        public static final String EXTRA_OUTPUT_MESSAGE = "output_message";

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            View fragmentView = inflater.inflate(R.layout.fragment_simple, container, false);

            String outputMesasge = null;
            if( null != getArguments() ){
                outputMesasge = getArguments().getString(EXTRA_OUTPUT_MESSAGE);
            }
            if( null == outputMesasge || 0 == outputMesasge.trim().length() ){
                outputMesasge = getString(R.string.demo_text);
            }
            TextView textView = (TextView) fragmentView.findViewById(R.id.textView_simpleFragmentOutput);
            textView.setText(outputMesasge);

            return fragmentView;
        }
    }
}

But when I change all thesupport api to the regular api(default platform api), everything goes fine on 4.3 platform(but this one doesn't compatible with 2.3.3 platform);

enter image description here

here's the code(nothing difference except the ActionBar and Fragment API)

package net.zengweizhi.android.gettingstarted.lesson05.test;

import net.zengweizhi.android.gettingstarted.R;
import android.os.Bundle;
import android.support.v7.app.ActionBarActivity;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

// use the api from default platform(only in v11 and later)

import android.annotation.SuppressLint;
import android.app.ActionBar;
import android.app.ActionBar.Tab;
import android.app.ActionBar.TabListener;
import android.app.Fragment;
import android.app.FragmentTransaction;

@SuppressLint("NewApi")

public class NavigationTabsWithFragmentsV14 extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    }


    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        getMenuInflater().inflate(R.menu.activity_navigation_tabs, menu);
        return super.onCreateOptionsMenu(menu);
    }

    private int mTabSeq = 0;

    private void addTab(){
        getActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
        mTabSeq++;

        Tab tab = getActionBar().newTab();
        tab.setText("TAB " + mTabSeq);
        tab.setTabListener(new MyTabListener(this));
        getActionBar().addTab(tab);
    }

    private void removeTab(){
        Tab tab = getActionBar().getSelectedTab();
        getActionBar().removeTab(tab);

        Fragment fragment = getFragmentManager().findFragmentByTag(tab.getText().toString());
        getFragmentManager().beginTransaction().remove(fragment).commit();
        if( getActionBar().getTabCount() == 0 ){
            getActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
        }
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case R.id.actionButton_addTab:
            addTab();
            break;
        case R.id.actionButton_removeTab:
            removeTab();
            break;
        default:
            break;
        }
        return super.onOptionsItemSelected(item);
    }

    private static final class MyTabListener  implements TabListener {
        private NavigationTabsWithFragmentsV14 mActivity;
        public MyTabListener(NavigationTabsWithFragmentsV14 activity /*,Fragment fragment*/){
            mActivity = activity;
        }

        @Override
        public void onTabReselected(Tab tab, FragmentTransaction ft) {
            // Do nothing
        }

        @Override
        public void onTabSelected(Tab tab, FragmentTransaction ft) {
            Object obj = tab.getTag();
            if( null == obj ){ // initialize fragment to tab
                Bundle args = new Bundle();
                args.putString(SimpleFragment.EXTRA_OUTPUT_MESSAGE, tab.getText().toString());
                Fragment fragment = Fragment.instantiate(mActivity, SimpleFragment.class.getName(), args);
                ft.add(android.R.id.content, fragment, tab.getText().toString());

                tab.setTag(obj = fragment);
            }
            ft.attach((Fragment)obj);
        }

        @Override
        public void onTabUnselected(Tab tab, FragmentTransaction ft) {
            if( null != mActivity.getFragmentManager().findFragmentByTag(tab.getText().toString()) ){
                ft.detach((Fragment)tab.getTag());
            }
        }
    }

    public static final class SimpleFragment extends Fragment {
        public static final String EXTRA_OUTPUT_MESSAGE = "output_message";

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            View fragmentView = inflater.inflate(R.layout.fragment_simple, container, false);

            String outputMesasge = null;
            if( null != getArguments() ){
                outputMesasge = getArguments().getString(EXTRA_OUTPUT_MESSAGE);
            }
            if( null == outputMesasge || 0 == outputMesasge.trim().length() ){
                outputMesasge = getString(R.string.demo_text);
            }
            TextView textView = (TextView) fragmentView.findViewById(R.id.textView_simpleFragmentOutput);
            textView.setText(outputMesasge);

            return fragmentView;
        }
    }
}

I can make a compatible version by using (values-v14/classes.xml) and following code

try {
    Class<?> clazz = Class.forName(getString(R.string.class_navigationTabsAndFragmentsActivity));
    startActivity(clazz);
} catch (ClassNotFoundException ex) {
    showTextByToast(ex.getMessage());
}

but I still want to know what's going on in the support library version, can anyone help me to figure out this problem?

like image 824
Robb Tsang Avatar asked Nov 01 '22 11:11

Robb Tsang


1 Answers

Google releases Nexus 5 and a new support library (v19), this version fixed this bug enter image description here

like image 200
Robb Tsang Avatar answered Nov 08 '22 06:11

Robb Tsang