編輯:關於Android編程
書籍頁面需要顯示輪播圖組件
down下來用到看書中,是封裝在fragment裡的,我是在BookView中動態調用的,調用方式:
LayoutInflater lif = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); View lubotuView = lif.inflate(R.layout.lunbotu, null); CycleViewPager cycleViewPager = (CycleViewPager) ((Activity) context).getFragmentManager().findFragmentById(R.id.lunbotuCycle); LinearLayout lunbotuLL = (LinearLayout) lubotuView.findViewById(R.id.lunbotuLL); addView(lubotuView);
好使,成功調用。
但是在翻頁過程中,第二次翻到此頁就崩潰了,崩潰信息:
E/AndroidRuntime(6462): android.view.InflateException: Binary XML file line #8: Error inflating class fragment 10-14 06:51:37.676: E/AndroidRuntime(6462): at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:719) 10-14 06:51:37.676: E/AndroidRuntime(6462): at android.view.LayoutInflater.rInflate(LayoutInflater.java:761) 10-14 06:51:37.676: E/AndroidRuntime(6462): at android.view.LayoutInflater.inflate(LayoutInflater.java:498) 10-14 06:51:37.676: E/AndroidRuntime(6462): at android.view.LayoutInflater.inflate(LayoutInflater.java:398) 10-14 06:51:37.676: E/AndroidRuntime(6462): at android.view.LayoutInflater.inflate(LayoutInflater.java:354) 10-14 06:51:37.676: E/AndroidRuntime(6462): at com.sea.testRatingBar.bookView.loadCarouselNode(bookView.java:132) 10-14 06:51:37.676: E/AndroidRuntime(6462): at com.sea.testRatingBar.bookView.loadElement(bookView.java:63) 10-14 06:51:37.676: E/AndroidRuntime(6462): at com.sea.testRatingBar.bookView.(bookView.java:50) 10-14 06:51:37.676: E/AndroidRuntime(6462): at com.sea.testRatingBar.BookPageAdapter.getView(BookPageAdapter.java:55) 10-14 06:51:37.676: E/AndroidRuntime(6462): at com.aphidmobile.flip.FlipViewController.viewFromAdapter(FlipViewController.java:478) 10-14 06:51:37.676: E/AndroidRuntime(6462): at com.aphidmobile.flip.FlipViewController.flippedToView(FlipViewController.java:545) 10-14 06:51:37.676: E/AndroidRuntime(6462): at com.aphidmobile.flip.FlipViewController$2.run(FlipViewController.java:519) 10-14 06:51:37.676: E/AndroidRuntime(6462): at android.os.Handler.handleCallback(Handler.java:733) 10-14 06:51:37.676: E/AndroidRuntime(6462): at android.os.Handler.dispatchMessage(Handler.java:95) 10-14 06:51:37.676: E/AndroidRuntime(6462): at android.os.Looper.loop(Looper.java:136) 10-14 06:51:37.676: E/AndroidRuntime(6462): at android.app.ActivityThread.main(ActivityThread.java:5479) 10-14 06:51:37.676: E/AndroidRuntime(6462): at java.lang.reflect.Method.invokeNative(Native Method) 10-14 06:51:37.676: E/AndroidRuntime(6462): at java.lang.reflect.Method.invoke(Method.java:515) 10-14 06:51:37.676: E/AndroidRuntime(6462): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1283) 10-14 06:51:37.676: E/AndroidRuntime(6462): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1099) 10-14 06:51:37.676: E/AndroidRuntime(6462): at dalvik.system.NativeStart.main(Native Method) 10-14 06:51:37.676: E/AndroidRuntime(6462): Caused by: java.lang.IllegalArgumentException: Binary XML file line #8: Duplicate id 0x7f09000a, tag null, or parent id 0x7f090009 with another fragment for cn.androiddevelop.cycleviewpager.lib.CycleViewPager 10-14 06:51:37.676: E/AndroidRuntime(6462): at android.app.Activity.onCreateView(Activity.java:5002) 10-14 06:51:37.676: E/AndroidRuntime(6462): at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:695) 10-14 06:51:37.676: E/AndroidRuntime(6462): ... 20 more
一看就是fragment重復調用,造成了這個錯誤
解決方案1:所以用完了得remove掉,在CycleViewPager這個fragment中添加個ondestroy方法,當ondestroy銷毀時remove此frg
public void onDestroyView() { super.onDestroyView(); FragmentManager fm = getActivity().getSupportFragmentManager(); Fragment fragment = (fm.findFragmentById(R.id.cyclepic)); FragmentTransaction ft = fm.beginTransaction(); ft.remove(fragment); ft.commit(); }
測試,不好使,Sh*t
解決方案2:優化oncreate生命周期,如果之前創建過,就刪除,老一套:
public CycleViewPager() { } private static View rootView; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // View view = // LayoutInflater.from(getActivity()).inflate(R.layout.view_cycle_viewpager_contet, // null); if (rootView != null) { ViewGroup parent = (ViewGroup) rootView.getParent(); if (parent != null) parent.removeView(rootView); } try { rootView = LayoutInflater.from(getActivity()).inflate(R.layout.view_cycle_viewpager_contet, null); } catch (InflateException e) { }測試,不好使,double Sh*t
解決方案3:這些都不好使,那還試試那個remove的,經過了漫長的邏輯方面的探索,終於鎖定在adapter中,移除所有view之前remove
int childCount0 = viewHolder.ll.getChildCount(); for (int i = 0; i < childCount0; i++) { View v = viewHolder.ll.getChildAt(i); BookView bv = (BookView) v; int bvChildCount = bv.getChildCount(); for (int j = 0; j < bvChildCount; j++) { View bvv = bv.getChildAt(j); if(bvv instanceof LinearLayout){ if(bvv.getId() == R.id.lunbotuLL){ FragmentManager fm = ((Activity) c).getFragmentManager(); Fragment fragment = fm.findFragmentById(R.id.lunbotuCycle); FragmentTransaction ft = fm.beginTransaction(); ft.remove(fragment); ft.commit(); } } } } viewHolder.ll.removeAllViews();測試,還tm不好使,triple Sh*t
解決方法4:思考了一下,邏輯肯定是對的,還是報錯的話,是不是ft.commit這個方法不執行啊,
上網搜到了一篇文章http://blog.csdn.net/picasso_l/article/details/50994143,按照文章說法,添加了一個
fm.executePendingTransactions();即 立即執行 !
測試,好使!
貼一下http://blog.csdn.net/picasso_l/article/details/50994143這個博客的內容,當做記錄,對博主表示感謝:
FragmentTransaction是異步的,commit()僅是相當於把操作加入到FragmentManager的隊列,然後FragmentManager會在某一個時刻來執行,並不是立即執行。所以,真正開始執行commit()時,如果Activity的生命周期發生了變化,比如走到了onPause,或者走到了onStop,或者onDestroy都走完了,那麼就會報出IllegalStateException。
這個地方確實是很坑的,我在做一個功能,需要從FragmentA跳轉到FragmentB,然後調用FragmentB的刷新方法,那我的思路是從FragmentA和B的MainActivity中將A隱藏,將B顯示,然後調用刷新。
於是我先將A隱藏B顯示
private void switchFragment(Fragment newFragment) { FragmentManager fm = getSupportFragmentManager(); FragmentTransaction transaction = fm.beginTransaction(); LogCat.i("newFragment isAdded=" + newFragment.isAdded()); if (newFragment.isAdded()) { transaction.hide(mCurrentFragment).show(newFragment).commitAllowingStateLoss(); } else { transaction.hide(mCurrentFragment).add(R.id.main_content, newFragment).commitAllowingStateLoss(); } mCurrentFragment = newFragment; }
然後,再switchFragment之後調用FragmentB的刷新功能,但是問題出現了,發現FragmentB裡面的一些空間沒有初始化,打了log之後發現,初始化在我的初始化在我的刷新功能後面執行,查了資料發現,FragmentTransaction的commit方法是異步的,難怪~
解決方法:executePendingTransactions
在用FragmentTransaction.commit()方法提交FragmentTransaction對象後,會在進程的主線程中,用異步的方式來執行。如果想要立即執行這個等待中的操作,就要調用這個方法(只能在主線程中調用)。要注意的是,所有的回調和相關的行為都會在這個調用中被執行完成,因此要仔細確認這個方法的調用位置。
於是我重寫switchFragment方法<喎?/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwcmUgY2xhc3M9"brush:java;"> FragmentManager fm = getSupportFragmentManager(); FragmentTransaction transaction = fm.beginTransaction(); if (fragment.isAdded()) { transaction.hide(mCurrentFragment).show(fragment).commitAllowingStateLoss(); } else { transaction.hide(mCurrentFragment).add(R.id.main_content, fragment).commitAllowingStateLoss(); } mCurrentFragment = fragment; fm.executePendingTransactions(); ((DiscoverFragment) fragment).refresh(searchWord);
多加了一句fm.executePendingTransactions()
先上效果圖: 驗證碼采用PHP返回的imageview來實現,xml如下:
最近研究怎麼讓自己的程序節省幾行代碼。仔細想一想,我們在做客戶端類的APP時,最基礎,大量重復的場景就是:1.從服務器請求數據2.解析得到的數據並處理加以封裝3.將封裝好
最近在學習IPC進程間通信,在此記錄下AIDL的使用,並附上一個Demo:服務端每隔一分鐘添加一本書籍,客戶端通過進程間通信,獲取當前服務端的書籍列表,並且服務端對外開放
概要 當手機Modem狀態改變後會將狀態變化信息通知到上層,通過《Android 4.4 Kitkat Phone工作流程淺析(八)__Phone狀態分析》