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()
và 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 đề!
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