2013-06-03 31 views
7

Tôi đang xây dựng một ứng dụng với MainActivity mở rộng FragmentActivity và có một ActionBar với ba tab. Tại mỗi tab, tôi muốn đính kèm một ParentFragment nên kiểm soát thao tác vuốt giữa các trang nội bộ. Kết quả phải là nhấn các tab mà người dùng sẽ thay đổi từ các phiên bản khác nhau của ParentFragment và vuốt anh ta nên thay đổi trong số TextViewFragments bên trong mỗi ParentFragment.
Bây giờ tôi có thể chuyển đổi hoàn toàn giữa ba tab, nhưng vấn đề là ParentFragment không được hiển thị chính xác, có vẻ như nó không được tạo bởi vì tôi thậm chí không thể thấy các hàm onCreate(), onCreateView()onViewCreated() trong chế độ xem LogCat.
Tôi nghĩ rằng vấn đề nằm trong lớp tùy chỉnh TabListener và các chức năng của nó nhưng tôi thực sự không thể hiểu được vấn đề là gì. Tôi đã cố gắng tìm kiếm trên nhiều trang web và tôi đã xem xét rất nhiều ví dụ nhưng không có ví dụ nào liên quan đến cùng một tình huống.
Tôi bỏ lỡ điều gì hoặc tôi đang làm gì sai ở đây?Android: ActionBar, TabListener và support.v4.Fragment

Đây là MainActivity tôi:

import java.util.Random; 
    import android.app.ActionBar; 
    import android.app.ActionBar.Tab; 
    import android.graphics.drawable.Drawable; 
    import android.os.Bundle; 
    import android.support.v4.app.Fragment; 
    import android.support.v4.app.FragmentActivity; 
    import android.support.v4.app.FragmentTransaction; 
    import android.support.v4.view.ViewPager; 
    import android.view.Gravity; 
    import android.view.LayoutInflater; 
    import android.view.Menu; 
    import android.view.MenuItem; 
    import android.view.View; 
    import android.view.ViewGroup; 
    import android.widget.TextView; 
    import android.widget.Toast; 
    import com.viewpagerindicator.PageIndicator; 

public class MainActivity extends FragmentActivity { 

    MyAdapter mAdapter; 
    ViewPager mPager; 
    PageIndicator mIndicator;  
    private View mCustomView; 
    private static final Random RANDOM = new Random(); 

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

     // Set up the action bar. 
     ActionBar.LayoutParams params = new ActionBar.LayoutParams(
       ActionBar.LayoutParams.MATCH_PARENT, 
       ActionBar.LayoutParams.MATCH_PARENT, Gravity.CENTER); 
     final ActionBar actionBar = getActionBar(); 
     actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); 
     actionBar.setDisplayShowTitleEnabled(false); 
     actionBar.setDisplayUseLogoEnabled(false); 
     actionBar.setDisplayShowHomeEnabled(false); 


      actionBar.addTab(actionBar 
        .newTab() 
        .setIcon(getIcon(0, true)) 
        .setTabListener(
          new TabListener<ParentFragment>(this, "home", 
            ParentFragment.class))); 

      actionBar.addTab(actionBar 
        .newTab() 
        .setIcon(getIcon(1, false)) 
        .setTabListener(
          new TabListener<ParentFragment>(this, "apps", 
            ParentFragment.class))); 

      actionBar.addTab(actionBar 
        .newTab() 
        .setIcon(getIcon(2, false)) 
        .setTabListener(
          new TabListener<ParentFragment>(this, "settings", 
            ParentFragment.class))); 

    } 

    @Override 
    public boolean onCreateOptionsMenu(Menu menu) { 
     return true; 
    } 

    @Override 
    public boolean onOptionsItemSelected(MenuItem item) { 

    } 


    public static class TabListener<T extends Fragment> implements 
      ActionBar.TabListener { 

     private Fragment mFragment; 
     private final FragmentActivity mActivity; 
     private final String mTag; 
     private final Class<T> mClass; 
     private final Bundle mArgs; 
     private FragmentTransaction fft; 
      public static final String TAG = TabListener.class.getSimpleName(); 

     public TabListener(FragmentActivity activity, String tag, Class<T> clz) { 

      this(activity, tag, clz, null); 
     } 

     public TabListener(FragmentActivity activity, String tag, Class<T> clz, 
       Bundle args) { 

      mActivity = activity; 
      mTag = tag; 
      mClass = clz; 
      mArgs = args; 

      mFragment = mActivity.getSupportFragmentManager() 
        .findFragmentByTag(mTag); 
      if (mFragment != null && !mFragment.isDetached()) { 

       fft = mActivity.getSupportFragmentManager().beginTransaction(); 
       fft.detach(mFragment); 
       fft.commit(); 
      } 
     } 

     public void onTabSelected(Tab tab, android.app.FragmentTransaction ft) { 

      System.out.println(TAG + (" - ") + " -> mTag " 
        + mTag + " selected!"); 
      fft = mActivity.getSupportFragmentManager().beginTransaction(); 

      if (mFragment == null) { 
       mFragment = Fragment.instantiate(mActivity, mClass.getName()); 

       fft.add(android.R.id.content, mFragment, mTag); 

      } else { 
       System.out.println(TAG + (" - ") + " -> Fragment con mTag = " + mTag 
         + " trovato con tag!"); 
       fft.attach(mFragment); 
       fft.commit(); 
      } 
     } 

     @Override 
     public void onTabReselected(Tab tab, android.app.FragmentTransaction ft) { 

     } 

     @Override 
     public void onTabUnselected(Tab tab, android.app.FragmentTransaction ft) { 

      mFragment = mActivity.getSupportFragmentManager() 
        .findFragmentByTag(mTag); 
      System.out.println(TAG + (" - ") + " -> mTag " 
        + mTag + " unselected!"); 

      if (mFragment != null && !mFragment.isDetached()) { 
       fft = mActivity.getSupportFragmentManager().beginTransaction(); 
       fft.detach(mFragment); 
       fft.commit(); 
      } 
     } 

    } 

    public Drawable getIcon(int tabPosition, boolean selected) { 

     switch (tabPosition) { 
     case 0: 
      return getResources().getDrawable(R.drawable.actionbar_home); 

     case 1: 
      return getResources().getDrawable(R.drawable.actionbar_apps); 

     case 2: 
      return getResources().getDrawable(R.drawable.actionbar_settings); 

     } 
     return null; 
    } 

} 

Và đây là ParentFragment tôi mà exteds nay là lớp android.support.v4.app.Fragment:

import android.os.Bundle; 
import android.support.v4.app.Fragment; 
import android.support.v4.view.ViewPager; 
import android.view.LayoutInflater; 
import android.view.View; 
import android.view.ViewGroup; 
import com.viewpagerindicator.IconPageIndicator; 
import com.viewpagerindicator.PageIndicator; 

public class ParentFragment extends Fragment { 

    public static final String TAG = ParentFragment.class.getSimpleName(); 

    MyAdapter fragmentAdapter; 
    ViewPager mPager; 
    PageIndicator mIndicator; 



    public static ParentFragment newInstance() { 
System.out.println(TAG + " - newInstance()"); 
    System.out.println(TAG + " - " + methodName()); 
     ParentFragment fragment = new ParentFragment(); 
     return fragment; 
    } 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
System.out.println(TAG + " - onCreate()"); 
     System.out.println(TAG + " - " + methodName()); 

     super.onCreate(savedInstanceState); 
     setRetainInstance(true); 

    } 

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

System.out.println(TAG + " - onCreateView()"); 
     System.out.println(TAG + " - " + methodName()); 
     fragmentAdapter = new MyAdapter(getFragmentManager()); 

     View view = inflater.inflate(R.layout.simple_icons, container, false); 
     mPager = (ViewPager) view.findViewById(R.id.pager); 
     mPager.setAdapter(fragmentAdapter); 

     return view; 
    } 

    @Override 
    public void onViewCreated(View view, Bundle savedInstanceState) { 
     System.out.println(TAG + " - onViewCreated()"); 
     System.out.println(TAG + " - " + methodName()); 
     super.onViewCreated(view, savedInstanceState); 

     mIndicator = (IconPageIndicator) getActivity().findViewById(R.id.indicator); 
     mIndicator.setViewPager(mPager);   
    } 
} 

Đây là lớp MyAdapter:

import android.os.Bundle; 
import android.support.v4.app.Fragment; 
import android.support.v4.app.FragmentManager; 
import android.support.v4.app.FragmentTransaction; 
import android.support.v4.view.PagerAdapter; 
import android.view.View; 
import android.view.ViewGroup; 
import com.viewpagerindicator.IconPagerAdapter; 

public class MyAdapter extends PagerAdapter { 

    FragmentManager myFragmentMgr; 
    private FragmentTransaction mCurTransaction; 

    protected static final String[] CONTENT = new String[] { "This", "Is", "A", "Test", }; 
    protected static final int[] ICONS = new int[] { 
      R.drawable.icon_page_indicator, 
      R.drawable.icon_page_indicator, 
      R.drawable.icon_page_indicator, 
      R.drawable.perm_group_calendar, 
      R.drawable.perm_group_camera, 
      R.drawable.perm_group_device_alarms, 
      R.drawable.perm_group_location 
    }; 

    private int mCount = CONTENT.length; 

    public MyAdapter(FragmentManager fm) { 
     super(); 
     myFragmentMgr = fm; 
    } 

    @Override 
    public int getCount() { 

     return 3; 
    } 

    @Override 
    public Object instantiateItem(ViewGroup viewGroup, int position) { 

     ParentFragment fragment = ParentFragment.newInstance(); 
     return fragment; 
    } 

    @Override 
    public void destroyItem(ViewGroup viewGroup, int position, Object obj) { 

     if (mCurTransaction == null) { 
      mCurTransaction = myFragmentMgr.beginTransaction(); 
     } 
     mCurTransaction.detach((Fragment)obj); 
    } 

    @Override 
    public boolean isViewFromObject(View arg0, Object arg1) { 
     return false; 
    } 

    public Fragment getItem(int position) { 
     Bundle args = new Bundle(); 
     args.putInt(TextViewFragment.POSITION_KEY, position); 
     return TextViewFragment.newInstance(args); 
    } 

    @Override 
    public CharSequence getPageTitle(int position) { 

     return "Fragment # " + position; 
    } 

    public int getIconResId(int index) { 

     return ICONS[index % ICONS.length]; 
    } 

    public void setCount(int count) { 
      if (count > 0 && count <= 10) { 
       mCount = count; 
       notifyDataSetChanged(); 
      } 
     } 
} 

và lớp cuối cùng TextViewFragment:

import android.os.Bundle; 
import android.support.v4.app.Fragment; 
import android.view.LayoutInflater; 
import android.view.View; 
import android.view.View.OnClickListener; 
import android.view.ViewGroup; 
import android.widget.TextView; 
import android.widget.Toast; 

public class TextViewFragment extends Fragment { 

    public static final String POSITION_KEY = "POSITION"; 
    public static final String TITLE_KEY = "TITLE"; 

    public static TextViewFragment newInstance(Bundle args) { 
     TextViewFragment fragment = new TextViewFragment(); 
     fragment.setArguments(args); 
     return fragment; 
    } 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
    } 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
      Bundle savedInstanceState) { 
     return inflater.inflate(R.layout.fragment_test, container, false); 
    } 

    @Override 
    public void onViewCreated(View view, Bundle savedInstanceState) { 
     super.onViewCreated(view, savedInstanceState); 

     TextView textview = (TextView) view.findViewById(R.id.textViewPosition); 
     final int position; 
     if (getArguments() != null) { 
      position = getArguments().getInt(POSITION_KEY); 
      textview.setText(Integer.toString(position)); 
     } else { 
      position = 0; 
      textview.setText("Child Fragment"); 
     } 

     textview.setOnClickListener(new OnClickListener() { 

      @Override 
      public void onClick(View v) { 

       Toast.makeText(v.getContext(), "Clicked Position: " + position, 
         Toast.LENGTH_LONG).show(); 
      } 
     }); 
    }  
} 

----- EDIT: GIẢI PHÁP -----

tôi không thể trả lời câu hỏi của riêng tôi vì "uy tín thấp" nhưng tôi chia sẻ anyway các giải pháp, để giúp đỡ người khác và hy vọng sẽ phục hồi một số phiếu bầu.

Cuối cùng tôi đã tìm ra cách để làm mọi thứ có hiệu quả đối với tôi, tôi hy vọng điều này có thể hữu ích cho bất kỳ ai khác gặp phải vấn đề tương tự. Như tôi nghi ngờ, vấn đề nằm trong TabListener. Vấn đề của tôi đã được giải quyết việc thay đổi phần đó với mã này:

public static class TabListener<T extends Fragment> implements 
      ActionBar.TabListener { 
    private Fragment mFragment; 
    private final FragmentActivity mActivity; 
    private final String mTag; 
    private final Class<T> mClass; 
    private final Bundle mArgs; 
    private FragmentTransaction fft; 

    public TabListener(FragmentActivity activity, String tag, Class<T> clz) { 

     this(activity, tag, clz, null); 
    } 

    public TabListener(FragmentActivity activity, String tag, Class<T> clz, 
      Bundle args) { 

     mActivity = activity; 
     mTag = tag; 
     mClass = clz; 
     mArgs = args; 

     System.out.println(TAG + " - " + methodName() + " - Constructor of TabListener -> mTag = " 
       + mTag); 
     // Check to see if we already have a fragment for this tab, probably 
     // from a previously saved state. If so, deactivate it, because our 
     // initial state is that a tab isn't shown. 
     mFragment = mActivity.getSupportFragmentManager() 
       .findFragmentByTag(mTag); 
     if (mFragment != null && !mFragment.isDetached()) { 

      fft = mActivity.getSupportFragmentManager().beginTransaction(); 
      fft.detach(mFragment); 
      fft.commit(); 
      mActivity.getSupportFragmentManager() 
        .executePendingTransactions(); 
     } 
    } 

    public void onTabSelected(Tab tab, android.app.FragmentTransaction ft) { 

     Fragment tmp = mActivity.getSupportFragmentManager() 
       .findFragmentByTag(mTag); 

     fft = mActivity.getSupportFragmentManager().beginTransaction(); 

     if (mFragment == null) { 

      System.out.println(TAG + " - " + methodName() + " - add mFragment " + mTag); 
      // If not, instantiate and add it to the activity 
      mFragment = Fragment.instantiate(mActivity, mClass.getName()); 
      fft.add(android.R.id.content, mFragment, mTag); 
      fft.commit(); 
      mActivity.getSupportFragmentManager() 
        .executePendingTransactions(); 
     } else { 
      System.out.println(TAG + " - " + methodName() + " - attach mFragment " + mTag); 
      // If it exists, simply attach it in order to show it 
      fft.attach(mFragment); 
      fft.commit(); 
      mActivity.getSupportFragmentManager() 
        .executePendingTransactions(); 
     } 
    } 

    @Override 
    public void onTabReselected(Tab tab, android.app.FragmentTransaction ft) { 
     System.out.println(TAG + " - " + methodName() + " - mFragment " + mTag); 

    } 

    @Override 
    public void onTabUnselected(Tab tab, android.app.FragmentTransaction ft) { 

     mFragment = mActivity.getSupportFragmentManager() 
       .findFragmentByTag(mTag); 

     if (mFragment != null && !mFragment.isDetached()) { 
      System.out.println(TAG + " - " + methodName() + " - detach mFragment " + mTag); 
      fft = mActivity.getSupportFragmentManager().beginTransaction(); 
      fft.detach(mFragment); 
      fft.commit(); 
      mActivity.getSupportFragmentManager() 
        .executePendingTransactions(); 
     } 
    } 



    public static final String TAG = TabListener.class.getSimpleName(); 
    private static final int CLIENT_CODE_STACK_INDEX; 

    static { 
     // Finds out the index of "this code" in the returned stack trace - 
     // funny but it differs in JDK 1.5 and 1.6 
     int i = 0; 
     for (StackTraceElement ste : Thread.currentThread().getStackTrace()) { 
      i++; 
      if (ste.getClassName().equals(TabListener.class.getName())) { 
       break; 
      } 
     } 
     CLIENT_CODE_STACK_INDEX = i; 
    } 

    public static String methodName() { 

     if (Thread.currentThread().getStackTrace().length < CLIENT_CODE_STACK_INDEX) 
      return Thread.currentThread().getStackTrace()[CLIENT_CODE_STACK_INDEX] 
        .getMethodName() + "()"; 
     else 
      return new String(
        "methodName() - stackTrace index is out of bound"); 
    } 
} 

Sự khác biệt cơ bản là việc bổ sung sau mỗi commit() của dòng sau:

mActivity.getSupportFragmentManager().executePendingTransactions(); 

Vấn đề này đã thực sự kém tài liệu và có lẽ chỉ xảy ra trong điều kiện cụ thể, nhưng tôi hy vọng giải pháp này tiết kiệm thời gian cho bất kỳ ai khác có cùng vấn đề!

+0

Trong trường hợp của tôi cách thêm 'executePendingTransanctions' ném một lỗi đệ quy. Dù sao, tôi đã sử dụng mã của bạn mà không có cuộc gọi đó và nó hoạt động. – Axxiss

Trả lời

3

Cảm ơn câu trả lời, tôi đã có cùng một vấn đề chính xác với thư viện hỗ trợ, nơi các mảnh sẽ phủ lên ontop của nhau khi tôi cố chuyển đổi giữa các tab. Đã có một vài biến không sử dụng trong dung dịch vì vậy tôi làm sạch nó lên một chút:

public static class TabListener<T extends Fragment> implements ActionBar.TabListener { 

    private Fragment mFragment; 
    private final FragmentActivity mActivity; 
    private final String mTag; 
    private final Class<T> mClass; 
    private FragmentTransaction fft; 

    public TabListener(FragmentActivity activity, String tag, Class<T> clz) { 

     mActivity = activity; 
     mTag = tag; 
     mClass = clz; 

     // Check to see if we already have a fragment for this tab, probably 
     // from a previously saved state. If so, deactivate it, because our 
     // initial state is that a tab isn't shown. 
     mFragment = mActivity.getSupportFragmentManager().findFragmentByTag(mTag); 
     if (mFragment != null && !mFragment.isDetached()) { 

      fft = mActivity.getSupportFragmentManager().beginTransaction(); 
      fft.detach(mFragment); 
      fft.commit(); 
      mActivity.getSupportFragmentManager() 
      .executePendingTransactions(); 
     } 
    } 

    @Override 
    public void onTabSelected(Tab tab, FragmentTransaction ft) { 

     mFragment = mActivity.getSupportFragmentManager().findFragmentByTag(mTag); 
     fft = mActivity.getSupportFragmentManager().beginTransaction(); 

     if (mFragment == null) { 

      // If not, instantiate and add it to the activity 
      mFragment = Fragment.instantiate(mActivity, mClass.getName()); 
      ft.add(R.id.content_view, mFragment, mTag); 
      //fft.add(android.R.id.content, mFragment, mTag); 
      fft.commit(); 
      mActivity.getSupportFragmentManager().executePendingTransactions(); 
     } else { 

      // If it exists, simply attach it in order to show it 
      fft.attach(mFragment); 
      fft.commit(); 
      mActivity.getSupportFragmentManager().executePendingTransactions(); 
     } 
    } 

    @Override 
    public void onTabReselected(Tab tab, FragmentTransaction ft) { 

    } 

    @Override 
    public void onTabUnselected(Tab tab, FragmentTransaction ft) { 

     mFragment = mActivity.getSupportFragmentManager().findFragmentByTag(mTag); 

     if (mFragment != null && !mFragment.isDetached()) { 
      fft = mActivity.getSupportFragmentManager().beginTransaction(); 
      fft.detach(mFragment); 
      fft.commit(); 
      mActivity.getSupportFragmentManager().executePendingTransactions(); 
     } 
    } 

}

+0

Thận trọng: Bạn không được gọi cam kết() cho giao dịch phân đoạn trong mỗi cuộc gọi lại này — hệ thống gọi nó cho bạn và nó có thể ném một ngoại lệ nếu bạn tự gọi nó. Bạn cũng không thể thêm các giao dịch phân đoạn này vào ngăn xếp lùi –

+0

Bạn không nhận được bất kỳ ngoại lệ nào trên 'commit'? –

Các vấn đề liên quan