executePendingTransactions 的递归入口
Posted
技术标签:
【中文标题】executePendingTransactions 的递归入口【英文标题】:Recursive entry to executePendingTransactions 【发布时间】:2014-04-04 17:57:33 【问题描述】:我有一个 MainDrawer 到 Fragment 活动,它有一个导航抽屉布局我和我的主要内容,我可以在其中加载新的片段。我加载的一个片段是 calle StatisticsTab 片段。这个片段包含一个标签主机,每个标签都是它自己的列表视图项目片段。一旦我单击一个 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 中具有列表视图的选项卡:
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();
【问题讨论】:
ViewPager: Recursive entry to executePendingTransactions 的可能重复项 【参考方案1】:您正试图通过 FragmentTabHost 使用嵌套在其他片段中的片段。
在您的 StatisticsTab 片段中,更改以下内容:
mTabHost.setup(getActivity(), getFragmentManager(), R.id.realtabcontent);
到这里:
mTabHost.setup(getActivity(), getChildFragmentManager(), R.id.realtabcontent);
然后,确保使用父 FragmentManager 提交主片段更改,方法是将BreweryStatistics.onArticleSelected()
中的getFragmentManager()
更改为getActivity().getSupportFragmentManager()
。
见:ViewPager: Recursive entry to executePendingTransactionsNested Fragments using support library v4 revision 11
【讨论】:
我将在哪里更改为 getSupportFragmentManager() 与 getChildFragmentManager()? 抱歉,误读了您的活动代码,您在抽屉活动中正确使用了 getSupportFragmentManager()。请参阅我的更新答案以获得澄清。 太棒了,但这实际上是我最初的想法,当我尝试从选项卡中的 ListView 中进行选择时,我得到了一个奇怪的 ID 错误。我会很快把它改回来并告诉你错误。 这是我在啤酒厂统计选项卡中遇到的错误,并尝试从列表视图中选择一个项目:gist.github.com/anonymous/14131f62e19f8e0b04cc 在 BreweryStatistics.onArticleSelected() 中,调用 getFragmentManager() 返回最初由 FragmentTabHost 设置提供的子 FragmentManager。这个片段管理器独立于 Activity 的主片段管理器,因此不会对主片段管理器的视图有任何引用。您需要将 getFragmentManager() 替换为 getActivity().getSupportFragmentManager() ,一切都应该很好。以上是关于executePendingTransactions 的递归入口的主要内容,如果未能解决你的问题,请参考以下文章
即使在 FragmentManager.executePendingTransactions() 之后,也不会立即调用 Fragment 中的 onCreateView()
java.lang.IllegalStateException: Recursive entry to executePendingTransactions