3

我正在实现SherlockFragmentActivity一个ViewPager嵌入式。ViewPager 显示正确,但是其中的内容(片段本身)是混合的。

在我的情况下,我有一个带有三个选项卡的视图寻呼机,我想为每个选项卡加载一个片段。发生的情况是:第二个片段加载到第一个选项卡中,当我单击第三个选项卡并返回第二个选项卡时,它显示在那里。

此外,当我单击第二个选项卡时,它会加载第一个选项卡的片段,然后突然加载第二个选项卡的内容,覆盖以前的内容。

它在不同的选项卡中加载了错误的内容。


更新

在调试时,我看到当我打开第二个选项卡(添加到TabsAdapteras ContactActivityFragment)时,它调用适配器类的onActivityCreated方法 和,这是第一个选项卡,而不是第二个选项卡。所以第一个选项卡的内容加载到了错误的位置。getViewContactInfoFragment


这是我的代码。知道可能会发生什么吗?

ContactActivity.java

public class ContactActivity extends SherlockFragmentActivity implements     OnCreateOptionsMenuListener
{

public ActionBarSherlock mSherlock = ActionBarSherlock.wrap(this);
private TabHost mTabHost;
private ViewPager  mViewPager;
private TabsAdapter mTabsAdapter;

private TextView mContactNameTextView;
private ImageView mContactIconImageView;

private Context mContext;

private final String FRAGMENT_POSITION = "fragment_position";
private final String CONTACT_ID = "contact_id"; 
private Long mContactId;

private ContactController mContactController;
private Contact mContact;


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

    mSherlock.setUiOptions(ActivityInfo.UIOPTION_SPLIT_ACTION_BAR_WHEN_NARROW);

    setContentView(R.layout.contact_activity);

    // retrieve the extra values from the intent
    mContactId = getIntent().getExtras().getLong(CONTACT_ID);

    // set the tab host to hold the fragments and the viewpager
    mTabHost = (TabHost)findViewById(android.R.id.tabhost);
    mTabHost.setup();

    mViewPager = (ViewPager)findViewById(R.id.pager);

    mTabsAdapter = new TabsAdapter(this, mTabHost, mViewPager);

    // create the bundle to set the values to send to the fragment
    Bundle bundle = new Bundle();
    bundle.putLong(CONTACT_ID, mContactId);

    mTabsAdapter.addTab(mTabHost.newTabSpec("info").setIndicator(getString(R.string.fragment_contact_title_info)), ContactInfoFragment.class, bundle);
    mTabsAdapter.addTab(mTabHost.newTabSpec("activity").setIndicator(getString(R.string.fragment_contact_title_activity)), ContactActivityFragment.class, bundle);
    mTabsAdapter.addTab(mTabHost.newTabSpec("stats").setIndicator(getString(R.string.fragment_contact_title_stats)), ContactStatsFragment.class, bundle);

    mContext = getSupportActionBar().getThemedContext();

    // Set the action bar properties
    getSupportActionBar().setDisplayShowTitleEnabled(true);
    getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    getSupportActionBar().setNavigationMode(ActionBar.DISPLAY_SHOW_TITLE);

    // initialize the elements
    mContactNameTextView = (TextView) findViewById(R.id.textViewContactName);
    mContactIconImageView = (ImageView) findViewById(R.id.imageViewContactIcon);

    // initialize the contact controller
    mContactController = new ContactController(mContext);

    // initialize the contact object
    mContact = new Contact();
}

@Override
protected void onSaveInstanceState(Bundle outState) 
{
    super.onSaveInstanceState(outState);
    outState.putString("tab", mTabHost.getCurrentTabTag());
}

@Override
public boolean onOptionsItemSelected(MenuItem item) 
{    
    switch (item.getItemId()) 
    {        
        // If the user clicks the home icon 
        case android.R.id.home:            
            Intent i = new Intent(this, HomeActivity.class);
            i.putExtra(FRAGMENT_POSITION, "4");
            i.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            startActivity(i);
            break;
        default:            
            break;  
   }

    return true;
}

@Override
public void onResume()
{
    super.onResume();

    mContact = mContactController.getContactById(mContactId);

    // set the action bar title as the contact name. 
    // if the name is null, print the phone number which is set as 
    // the id of the contact in case it's an unmapped contact 
    getSupportActionBar().setTitle(mContact.getmDisplayName() == null ? mContact.getM_id().toString() : mContact.getmDisplayName());

    // set the contact name.
    // if the name is null, print the phone number which is set as 
    // the id of the contact in case it's an unmapped contact
    mContactNameTextView.setText(mContact.getmDisplayName() == null ? mContact.getM_id().toString() : mContact.getmDisplayName());

    // retrieve the contact image based on the URI
    Bitmap contactIconBitmap = mContactController.getContactPicture(mContactId);
    mContactIconImageView.setImageBitmap(contactIconBitmap);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) 
{
    // do nothing, since the menu items must be added on specific fragments
    return true;
}

/**
 * This is a helper class that implements the management of tabs and all
 * details of connecting a ViewPager with associated TabHost.  It relies on a
 * trick.  Normally a tab host has a simple API for supplying a View or
 * Intent that each tab will show.  This is not sufficient for switching
 * between pages.  So instead we make the content part of the tab host
 * 0dp high (it is not shown) and the TabsAdapter supplies its own dummy
 * view to show as the tab content.  It listens to changes in tabs, and takes
 * care of switch to the correct paged in the ViewPager whenever the selected
 * tab changes.
 */
public static class TabsAdapter extends FragmentPagerAdapter implements TabHost.OnTabChangeListener, ViewPager.OnPageChangeListener 
{
    private final Context mContext;
    private final TabHost mTabHost;
    private final ViewPager mViewPager;
    private final ArrayList<TabInfo> mTabs = new ArrayList<TabInfo>();

    static final class TabInfo 
    {
        private final String tag;
        private final Class<?> clss;
        private final Bundle args;

        TabInfo(String _tag, Class<?> _class, Bundle _args) 
        {
            tag = _tag;
            clss = _class;
            args = _args;
        }
    }

    static class DummyTabFactory implements TabHost.TabContentFactory 
    {
        private final Context mContext;

        public DummyTabFactory(Context context) 
        {
            mContext = context;
        }

        public View createTabContent(String tag) 
        {
            View v = new View(mContext);
            v.setMinimumWidth(0);
            v.setMinimumHeight(0);
            return v;
        }
    }

    public TabsAdapter(FragmentActivity activity, TabHost tabHost, ViewPager pager) 
    {
        super(activity.getSupportFragmentManager());
        mContext = activity;
        mTabHost = tabHost;
        mViewPager = pager;
        mTabHost.setOnTabChangedListener(this);
        mViewPager.setAdapter(this);
        mViewPager.setOnPageChangeListener(this);
    }

    public void addTab(TabHost.TabSpec tabSpec, Class<?> clss, Bundle args) 
    {
        tabSpec.setContent(new DummyTabFactory(mContext));
        String tag = tabSpec.getTag();

        TabInfo info = new TabInfo(tag, clss, args);
        mTabs.add(info);
        mTabHost.addTab(tabSpec);
        notifyDataSetChanged();
    }

    @Override
    public int getCount() 
    {
        return mTabs.size();
    }

    @Override
    public Fragment getItem(int position) 
    {
        TabInfo info = mTabs.get(position);

        return Fragment.instantiate(mContext, info.clss.getName(), info.args);

    }

    public void onTabChanged(String tabId) 
    {
        int position = mTabHost.getCurrentTab();
        mViewPager.setCurrentItem(position);
    }

    public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) 
    {
    }

    public void onPageSelected(int position) 
    {
        // Unfortunately when TabHost changes the current tab, it kindly
        // also takes care of putting focus on it when not in touch mode.
        // The jerk.
        // This hack tries to prevent this from pulling focus out of our
        // ViewPager.
        TabWidget widget = mTabHost.getTabWidget();
        int oldFocusability = widget.getDescendantFocusability();
        widget.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
        mTabHost.setCurrentTab(position);
        widget.setDescendantFocusability(oldFocusability);
    }

    public void onPageScrollStateChanged(int state) 
    {
    }   
}   
}

ContactInfoFragment.java

public class ContactInfoFragment extends SherlockListFragment
{
private Activity mActivity;
private Menu mOptionsMenu;
private ListView mListView;

private final String CONTACT_ID = "contact_id"; 
private Long mContactId;
private List<Contact> mContactsData = new ArrayList<Contact>();
private List<PhoneNumber> mPhoneNumbers = new ArrayList<PhoneNumber>();
private final String[] mListHeaders = { "Phone Numbers" };

private ContactController mContactController;
private PhoneNumberController mPhoneNumberController;
private Contact mContact;
private PhoneNumber mPhoneNumber;
private SeparatedListAdapter mSeparatedListAdapter;

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

    savedInstanceState = getArguments();

    // set the contact id
    mContactId = savedInstanceState.getLong(CONTACT_ID);

    // initialize controllers
    mContactController = new ContactController(getActivity().getApplicationContext());
    mPhoneNumberController = new PhoneNumberController(getActivity().getApplicationContext());
}

@Override
public void onSaveInstanceState(Bundle savedInstanceState)
{
    super.onSaveInstanceState(savedInstanceState);
    savedInstanceState.putString("class_name", "ContactInfoFragment");
}

@Override
public void onAttach(Activity activity) 
{
    super.onAttach(activity);
    mActivity = activity;
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 
{
    // inflate the layout 
    View view = inflater.inflate(R.layout.contact_info_fragment, container, false);

    return view;
}

@Override
public void onStart() 
{
    super.onStart();
}

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

    mContact = mContactController.getContactById(mContactId);
    mPhoneNumbers = mPhoneNumberController.getPhoneNumbersByContact(mContact);

    mListView = (ListView) mActivity.findViewById(android.R.id.list);

    ContentAdapter mAdapter = new ContentAdapter(getActivity().getApplicationContext(), android.R.id.list, mPhoneNumbers);

    // add the items for the adapter
    for (PhoneNumber phoneNumber : mPhoneNumbers)
    {
        mAdapter.add(phoneNumber);
    } 

    mSeparatedListAdapter = new SeparatedListAdapter(mActivity.getApplicationContext());

    // Add Sections
    mSeparatedListAdapter.addSection("Phone Numbers", mAdapter);

    mAdapter.notifyDataSetChanged();
    mSeparatedListAdapter.notifyDataSetChanged();
    mListView.setAdapter(mSeparatedListAdapter);

    mListView.setOnItemClickListener(new OnItemClickListener() 
    {
        public void onItemClick(AdapterView<?> parent, View view, int position, long duration) 
        {
            // if the user clicks a number, it will open the dialer to call the number
            Intent intent = new Intent(Intent.ACTION_DIAL);
            intent.setData(Uri.parse("tel:"+view.getTag(R.string.phone_number_action_call).toString()));
            intent.setFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
            startActivity(intent);
        }
    });
}

@Override
public void onResume() 
{
    super.onResume();

    setHasOptionsMenu(true);
}

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater)
{
    mOptionsMenu = menu;

    menu.add("People")
        .setIcon(R.drawable.ic_menu_contacts)
        .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);

    menu.add("Share")
        .setIcon(R.drawable.ic_menu_share)
        .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
}

private void changeOptionsMenu(int position)
{
    mOptionsMenu.clear();

    if(position == 0)
    {
        mOptionsMenu.add("People")
            .setIcon(R.drawable.ic_menu_contacts)
            .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);

        mOptionsMenu.add("Share")
            .setIcon(R.drawable.ic_menu_share)
            .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
    }
    else if(position == 1)
    {
        mOptionsMenu.add("People")
            .setIcon(R.drawable.ic_menu_contacts)
            .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);

        mOptionsMenu.add("Days")
            .setIcon(R.drawable.ic_menu_days)
            .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);

        mOptionsMenu.add("Share")
            .setIcon(R.drawable.ic_menu_share)
            .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
    }
    else
    {
        mOptionsMenu.add("People")
            .setIcon(R.drawable.ic_menu_contacts)
            .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);

        mOptionsMenu.add("Share")
            .setIcon(R.drawable.ic_menu_share)
            .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
    }
}

public class ContentAdapter extends ArrayAdapter<PhoneNumber>
{
    Context mContext;
    List<PhoneNumber> mPhoneNumbersList;
    private LayoutInflater mInflater;

    public ContentAdapter(Context context, int textViewResourceId, List<PhoneNumber> phoneNumbers) 
    {
        super(context, textViewResourceId);
        mContext = context;
        this.mPhoneNumbersList = phoneNumbers;
        mInflater = mActivity.getLayoutInflater();
    }

    // An alternative for the ArrayAdapter.addAll() method, since the native 
    // is not supported by API level lesser then 11.
    public void addAll(ArrayList<PhoneNumber> list)
    {
        for(PhoneNumber phoneNumber : list)
        {
            this.add(phoneNumber);
        }
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent)
    {
        View row = convertView;
        ViewHolder holder = new ViewHolder();

        if(row == null)
        {
            row = mInflater.inflate(R.layout.contact_info_list_item, parent, false);

            holder.phoneNumber = (TextView) row.findViewById(R.id.textViewContactNumber);
            holder.phoneNumberType = (TextView) row.findViewById(R.id.textViewNumberType);

            row.setTag(holder);
        }
        else
        {
            holder = (ViewHolder) row.getTag();
        }

        // TODO: make a join to get the contact and phone number instead of calling method by method
        PhoneNumber phoneNumber = mPhoneNumbersList.get(position);

        if(phoneNumber != null)
        {
            holder.phoneNumber.setText(phoneNumber.getmPhoneNumberValue());
            holder.phoneNumberType.setText(CallUtils.getPhoneNumberType(phoneNumber.getmPhoneNumberType()));
            row.setTag(R.string.phone_number_action_call, phoneNumber.getmPhoneNumberValue());
        }

        return row;
    }
}

public class ViewHolder
{
    TextView phoneNumber;
    TextView phoneNumberType;
}
}

ContactActivityFragment.java

public class ContactActivityFragment extends SherlockListFragment
{
private Activity mActivity;
private Menu mOptionsMenu;
private ListView mListView;

private final String CONTACT_ID = "contact_id"; 
private Long mContactId;
private List<Contact> mContactsData = new ArrayList<Contact>();
private List<Call> mCallsList = new ArrayList<Call>();
private final String[] mListHeaders = { "Calls" };

private Call mCall;
private Contact mContact;
private PhoneNumber mPhoneNumber;
private CallController mCallController;
private ContactController mContactController;
private PhoneNumberController mPhoneNumberController;
private SeparatedListAdapter mSeparatedListAdapter;

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

    savedInstanceState = getArguments();

    // set the contact id
    mContactId = savedInstanceState.getLong(CONTACT_ID);

    // initialize controllers
    mCallController = new CallController(getActivity().getApplicationContext());
    mContactController = new ContactController(getActivity().getApplicationContext());
    mPhoneNumberController = new PhoneNumberController(getActivity().getApplicationContext());

    // initialize models
    mCall = new Call();
}

@Override
public void onSaveInstanceState(Bundle savedInstanceState)
{
    super.onSaveInstanceState(savedInstanceState);
    savedInstanceState.putString("class_name", "ContactInfoFragment");
}

@Override
public void onAttach(Activity activity) 
{
    super.onAttach(activity);
    mActivity = activity;
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) 
{
    // inflate the layout 
    View view = inflater.inflate(R.layout.contact_info_fragment, container, false);

    return view;
}

@Override
public void onStart() 
{
    super.onStart();
}

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

    mCallsList = mCallController.getCallsByContact(mContactId);

    mContact = mContactController.getContactById(mContactId);

    mListView = (ListView) mActivity.findViewById(android.R.id.list);

    ContentAdapter mAdapter = new ContentAdapter(getActivity().getApplicationContext(), android.R.id.list, mCallsList);

    // add the items for the adapter
    for (Call callList : mCallsList)
    {
        mAdapter.add(callList);
    } 

    mSeparatedListAdapter = new SeparatedListAdapter(mActivity.getApplicationContext());

    // Add Sections
    mSeparatedListAdapter.addSection("Phone Numbers", mAdapter);

    mAdapter.notifyDataSetChanged();
    mSeparatedListAdapter.notifyDataSetChanged();
    mListView.setAdapter(mSeparatedListAdapter);
}

@Override
public void onResume() 
{
    super.onResume();

    setHasOptionsMenu(true);
}

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater menuInflater)
{
    mOptionsMenu = menu;

    menu.add("People")
        .setIcon(R.drawable.ic_menu_contacts)
        .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);

    menu.add("Share")
        .setIcon(R.drawable.ic_menu_share)
        .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
}

private void changeOptionsMenu(int position)
{
    mOptionsMenu.clear();

    if(position == 0)
    {
        mOptionsMenu.add("People")
            .setIcon(R.drawable.ic_menu_contacts)
            .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);

        mOptionsMenu.add("Share")
            .setIcon(R.drawable.ic_menu_share)
            .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
    }
    else if(position == 1)
    {
        mOptionsMenu.add("People")
            .setIcon(R.drawable.ic_menu_contacts)
            .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);

        mOptionsMenu.add("Days")
            .setIcon(R.drawable.ic_menu_days)
            .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);

        mOptionsMenu.add("Share")
            .setIcon(R.drawable.ic_menu_share)
            .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
    }
    else
    {
        mOptionsMenu.add("People")
            .setIcon(R.drawable.ic_menu_contacts)
            .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);

        mOptionsMenu.add("Share")
            .setIcon(R.drawable.ic_menu_share)
            .setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
    }
}

public class ContentAdapter extends ArrayAdapter<Call>
{
    Context mContext;
    List<Call> mCallsList;
    private LayoutInflater mInflater;

    public ContentAdapter(Context context, int textViewResourceId, List<Call> calls) 
    {
        super(context, textViewResourceId);
        mContext = context;
        this.mCallsList = calls;
        mInflater = mActivity.getLayoutInflater();
    }

    // An alternative for the ArrayAdapter.addAll() method, since the native 
    // is not supported by API level lesser then 11.
    public void addAll(ArrayList<Call> callsList)
    {
        for(Call call : callsList)
        {
            this.add(call);
        }
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent)
    {
        View row = convertView;
        ViewHolder holder = new ViewHolder();

        if(row == null)
        {
            row = mInflater.inflate(R.layout.contact_info_list_item, parent, false);

            holder.phoneNumber = (TextView) row.findViewById(R.id.textViewContactNumber);
            holder.phoneNumberType = (TextView) row.findViewById(R.id.textViewNumberType);

            row.setTag(holder);
        }
        else
        {
            holder = (ViewHolder) row.getTag();
        }

        // TODO: make a join to get the contact and phone number instead of calling method by method
        Call call = mCallsList.get(position);

        if(call != null)
        {
            holder.phoneNumber.setText(call.getCallDuration().toString());
            holder.phoneNumberType.setText(call.getCallDate());
        }

        return row;
    }
}

public class ViewHolder
{
    TextView phoneNumber;
    TextView phoneNumberType;
} 
}
4

0 回答 0