web-dev-qa-db-ja.com

executePendingTransactionsへの再帰的エントリ

MainDrawer to Fragmentアクティビティがあり、これには新しいフラグメントをロードできるナビゲーションドロワーとメインコンテンツのレイアウトがあります。ロードするフラグメントの1つは、StatisticsTab Fragmentです。このフラグメントは、各タブがリストビュー項目の独自のフラグメントであるタブホストを保持します。 ListViewアイテムをクリックすると、別の新しいフラグメントがロードされ、tabHostに表示されなくなり、navigationdrawerを使用してStatisticsTabフラグメントに戻ろうとすると、次のエラーが表示されます。

03-03 10:32:06.884  24185-24185/com.beerportfolio.beerportfoliopro E/AndroidRuntime﹕ FATAL EXCEPTION: main
    Java.lang.IllegalStateException: Recursive entry to executePendingTransactions
            at Android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.Java:1439)
            at Android.support.v4.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.Java:472)
            at Android.support.v4.app.FragmentTabHost.onAttachedToWindow(FragmentTabHost.Java:283)
            at Android.view.View.dispatchAttachedToWindow(View.Java:12307)
            at Android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.Java:2457)
            at Android.view.ViewGroup.dispatchAttachedToWindow(ViewGroup.Java:2464)
            at Android.view.ViewGroup.addViewInner(ViewGroup.Java:3567)
            at Android.view.ViewGroup.addView(ViewGroup.Java:3399)
            at Android.view.ViewGroup.addView(ViewGroup.Java:3344)
            at Android.view.ViewGroup.addView(ViewGroup.Java:3320)
            at Android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.Java:938)
            at Android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.Java:1104)
            at Android.support.v4.app.BackStackRecord.run(BackStackRecord.Java:682)
            at Android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.Java:1467)
            at Android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.Java:440)
            at Android.os.Handler.handleCallback(Handler.Java:730)
            at Android.os.Handler.dispatchMessage(Handler.Java:92)
            at Android.os.Looper.loop(Looper.Java:158)
            at Android.app.ActivityThread.main(ActivityThread.Java:5789)
            at Java.lang.reflect.Method.invokeNative(Native Method)
            at Java.lang.reflect.Method.invoke(Method.Java:525)
            at com.Android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.Java:1027)
            at com.Android.internal.os.ZygoteInit.main(ZygoteInit.Java:843)
            at dalvik.system.NativeStart.main(Native Method)

StatisticsTabフラグメント上でタブをクリックせず、navdrawerを介して別のフラグメントに移動してからStatisticsTabに戻ると、FCはオンになりません。また、NavDrawerの他のフラグメントはどれも、タブに戻ったときに閉じられません。タブが付いているフラグメントだけです。

MainDrawer2:

public class MainDrawer2 extends FragmentActivity
{
    private static final String EXTRA_NAV_ITEM    = "extraNavItem";
    private static final String STATE_CURRENT_NAV = "stateCurrentNav";

    private ActionBarDrawerToggle mDrawerToggle;
    private DrawerLayout mDrawerLayout;

    private NavDrawerListAdapter mDrawerAdapter;
    private ListView mDrawerList;

    private CharSequence mTitle;
    private CharSequence mDrawerTitle;

    private MainNavItem mCurrentNavItem;


    public static Intent createLaunchFragmentIntent(Context context, MainNavItem navItem)
    {
        return new Intent(context, MainDrawer2.class)
                .putExtra(EXTRA_NAV_ITEM, navItem.ordinal());
    }

    @Override
    protected void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.fragment_main);

        mTitle = mDrawerTitle = getTitle();
        mDrawerLayout = (DrawerLayout)findViewById(R.id.drawer_layout);
        mDrawerList   = (ListView)findViewById(R.id.drawer);

        getActionBar().setDisplayHomeAsUpEnabled(true);
        enableHomeButtonIfRequired();

        mDrawerAdapter = new NavDrawerListAdapter(getApplicationContext());
        mDrawerList.setAdapter(mDrawerAdapter);
        mDrawerList.setOnItemClickListener(new ListView.OnItemClickListener()
        {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id)
            {
                displayNavFragment((MainNavItem)parent.getItemAtPosition(position));
            }
        });

        mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout,
                R.drawable.ic_drawer, R.string.app_name, R.string.app_name)
        {
            public void onDrawerClosed(View view)
            {
                getActionBar().setTitle(mTitle);
                invalidateOptionsMenu();
            }

            public void onDrawerOpened(View drawerView)
            {
                getActionBar().setTitle(mDrawerTitle);
                invalidateOptionsMenu();
            }
        };

        mDrawerLayout.setDrawerListener(mDrawerToggle);

        if(getIntent().hasExtra(EXTRA_NAV_ITEM)){
            MainNavItem navItem = MainNavItem.values()
                    [getIntent().getIntExtra(EXTRA_NAV_ITEM,
                    MainNavItem.STATISTICS.ordinal())];
            displayNavFragment(navItem);
        }
        else if(savedInstanceState != null){
            mCurrentNavItem = MainNavItem.values()
                    [savedInstanceState.getInt(STATE_CURRENT_NAV)];
            setCurrentNavItem(mCurrentNavItem);
        }
        else{
            displayNavFragment(MainNavItem.STATISTICS);
        }
    }

    @TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH)
    private void enableHomeButtonIfRequired()
    {
        if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH){
            getActionBar().setHomeButtonEnabled(true);
        }
    }

    @Override
    public void setTitle(CharSequence title)
    {
        mTitle = title;
        getActionBar().setTitle(mTitle);
    }

    @Override
    protected void onPostCreate(Bundle savedInstanceState)
    {
        super.onPostCreate(savedInstanceState);
        // Sync the toggle state after onRestoreInstanceState has occurred.
        mDrawerToggle.syncState();
    }

    @Override
    public void onConfigurationChanged(Configuration newConfig)
    {
        super.onConfigurationChanged(newConfig);
        // Pass any configuration change to the drawer toggles
        mDrawerToggle.onConfigurationChanged(newConfig);
    }

    @Override
    protected void onSaveInstanceState(Bundle outState)
    {
        super.onSaveInstanceState(outState);
        outState.putInt(STATE_CURRENT_NAV, mCurrentNavItem.ordinal());
    }

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

    /*
    @Override
    public boolean onPrepareOptionsMenu(Menu menu)
    {
        // if nav drawer is opened, hide the action items
        boolean drawerOpen = mDrawerLayout.isDrawerOpen(mDrawerList);
        menu.findItem(R.id.action_settings).setVisible(!drawerOpen);
        return super.onPrepareOptionsMenu(menu);
    }
    */



    private void displayNavFragment(MainNavItem navItem)
    {
        if(navItem == mCurrentNavItem){
            return;
        }
        Fragment fragment = Fragment.instantiate(this,
                navItem.getFragClass().getName());
        if(fragment != null){

            getSupportFragmentManager().beginTransaction()
                    .replace(R.id.main, fragment)
                    .commit();
            setCurrentNavItem(navItem);
        }
    }

    private void setCurrentNavItem(MainNavItem navItem)
    {
        int position = navItem.ordinal();
        // If navItem is in DrawerAdapter
        if(position >= 0 && position < mDrawerAdapter.getCount()){
            mDrawerList.setItemChecked(position, true);
        }
        else{
            // navItem not in DrawerAdapter, de-select current item
            if(mCurrentNavItem != null){
                mDrawerList.setItemChecked(mCurrentNavItem.ordinal(), false);
            }
        }
        mDrawerLayout.closeDrawer(mDrawerList);
        setTitle(navItem.getTitleResId());
        mCurrentNavItem = navItem;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case Android.R.id.home:
                if(mDrawerLayout.isDrawerOpen(mDrawerList)) {
                    mDrawerLayout.closeDrawer(mDrawerList);
                }
                else {
                    mDrawerLayout.openDrawer(mDrawerList);
                }
                return true;
            default:
                return super.onOptionsItemSelected(item);
        }
    }




    public void goToSearch(MenuItem item){

        //go to search page
        Fragment Fragment_one;
        FragmentManager man= getSupportFragmentManager();
        FragmentTransaction tran = man.beginTransaction();
        Fragment_one = new Search();

        tran.replace(R.id.main, Fragment_one);//tran.
        tran.addToBackStack(null);
        tran.commit();

    }



}

統計タブ:

public class StatisticsTab extends Fragment  {


    private FragmentTabHost mTabHost;

    //Mandatory Constructor
    public StatisticsTab() {
    }

    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

    }

    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        View rootView = inflater.inflate(R.layout.fragment_tabs,container, false);


        mTabHost = (FragmentTabHost)rootView.findViewById(Android.R.id.tabhost);

        mTabHost.setup(getActivity(), getFragmentManager(), R.id.realtabcontent);

        mTabHost.addTab(mTabHost.newTabSpec("Basic").setIndicator("Basic"),
                StatisticsPage.class, null);
        mTabHost.addTab(mTabHost.newTabSpec("Brewery").setIndicator("Brewery"),
                BreweryStatistics.class, null);
        mTabHost.addTab(mTabHost.newTabSpec("Style").setIndicator("Style"),
                StyleStatistics.class, null);
        mTabHost.addTab(mTabHost.newTabSpec("Taste").setIndicator("Taste"),
                TasteStatisticsPage.class, null);



        return rootView;
    }




}

リストビューを持つtabhostのタブのフラグメントの1つ:

public class BreweryStatistics extends Fragment implements GetBreweryStatisticsJSON.OnArticleSelectedListener {

    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        View v = inflater.inflate(R.layout.brewery_statistics_layout, container, false);

        SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getActivity());
        String userName = prefs.getString("userName", null);
        String userID = prefs.getString("userID", null);

        String url = "myURL";


        //async task to get beer taste tag percents
        GetBreweryStatisticsJSON task = new GetBreweryStatisticsJSON(getActivity());
        task.setOnArticleSelectedListener(this);
        task.execute(url);


        // Inflate the layout for this fragment
        return v;

    }


    @Override
    public void onArticleSelected(String bID){

        //code to execute on click
        Fragment Fragment_one;
        FragmentManager man= getFragmentManager();
        FragmentTransaction tran = man.beginTransaction();
        Fragment_one = new BreweryPage2();
        final Bundle bundle = new Bundle();
        bundle.putString("breweryIDSent", bID);
        Fragment_one.setArguments(bundle);

        tran.replace(R.id.main, Fragment_one);//tran.
        tran.addToBackStack(null);
        tran.commit();

    }


}

リストビューをロードする上記のフラグメントの非同期タスク:

public class GetBreweryStatisticsJSON extends AsyncTask<String, Void, String> {

    Context c;
    private ProgressDialog Dialog;


    public GetBreweryStatisticsJSON(Context context)
    {
        c = context;
        Dialog = new ProgressDialog(c);
    }

    //***************************code for on click
    OnArticleSelectedListener listener;
    public interface OnArticleSelectedListener{
        public void onArticleSelected(String myString);


    }
    public void setOnArticleSelectedListener(OnArticleSelectedListener listener){
        this.listener = listener;


    }
    //*****************************end code for onClick

    protected void onPreExecute() {
        Dialog.setMessage("Analyzing breweries");

        Dialog.setTitle("Loading");
        Dialog.setCancelable(false);
        Dialog.show();
    }


    @Override
    protected String doInBackground(String... arg0) {
        // TODO Auto-generated method stub
        return readJSONFeed(arg0[0]);
    }

    protected void onPostExecute(String result){
        //decode json here
        try{
            JSONArray jsonArray = new JSONArray(result);


            //acces listview
            ListView lv = (ListView) ((Activity) c).findViewById(R.id.yourBreweryStatistics);

            //make array list for beer
            final List<BreweryInfo> tasteList = new ArrayList<BreweryInfo>();



            for(int i = 0; i < jsonArray.length(); i++) {

                String brewery = jsonArray.getJSONObject(i).getString("brewery");
                String rate = jsonArray.getJSONObject(i).getString("rate");
                String breweryID = jsonArray.getJSONObject(i).getString("id");

                int count = i + 1;

                brewery = count + ". " + brewery;

                Log.d("brewery stats", brewery);

                //create object
                BreweryInfo tempTaste = new BreweryInfo(brewery, breweryID, rate);

                //add to arraylist
                tasteList.add(tempTaste);


                //add items to listview
                BreweryInfoAdapter adapter1 = new BreweryInfoAdapter(c ,R.layout.brewer_stats_listview, tasteList);
                lv.setAdapter(adapter1);

                //set up clicks
                lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
                    @Override
                    public void onItemClick(AdapterView<?> arg0, View arg1,
                                            int arg2, long arg3) {
                        BreweryInfo o=(BreweryInfo)arg0.getItemAtPosition(arg2);

                        String bID = o.breweryID;

                        Log.d("breweryID" , bID);

                        //todo: add brewery page link
                        //********************* add listener
                        listener.onArticleSelected(bID);


                    }
                });

            }

        }
        catch(Exception e){

        }

        Dialog.dismiss();

    }

    public String readJSONFeed(String URL) {
        StringBuilder stringBuilder = new StringBuilder();
        HttpClient httpClient = new DefaultHttpClient();
        HttpGet httpGet = new HttpGet(URL);
        try {
            HttpResponse response = httpClient.execute(httpGet);
            StatusLine statusLine = response.getStatusLine();
            int statusCode = statusLine.getStatusCode();
            if (statusCode == 200) {
                HttpEntity entity = response.getEntity();
                InputStream inputStream = entity.getContent();
                BufferedReader reader = new BufferedReader(
                        new InputStreamReader(inputStream));
                String line;
                while ((line = reader.readLine()) != null) {
                    stringBuilder.append(line);
                }
                inputStream.close();
            } else {
                Log.d("JSON", "Failed to download file");
            }
        } catch (Exception e) {
            Log.d("readJSONFeed", e.getLocalizedMessage());
        }
        return stringBuilder.toString();
    }



}
23
Mike

FragmentTabHostを使用して、他のフラグメント内にネストされたフラグメントを使用しようとしています。

StatisticsTabフラグメントで、これを変更します。

_mTabHost.setup(getActivity(), getFragmentManager(), R.id.realtabcontent);
_

これに:

_mTabHost.setup(getActivity(), getChildFragmentManager(), R.id.realtabcontent);
_


次に、getFragmentManager()getActivity().getSupportFragmentManager()内でBreweryStatistics.onArticleSelected()に変更して、親FragmentManagerを使用してメインフラグメントの変更をコミットします。


見る:
ViewPager:executePendingTransactionsへの再帰的エントリ
サポートライブラリv4リビジョン11を使用したネストされたフラグメント

57
Bryan Dunlap