刷新同一活动中剩余的当前片段(ListView 数据)

Posted

技术标签:

【中文标题】刷新同一活动中剩余的当前片段(ListView 数据)【英文标题】:Refresh Current Fragment (ListView Data) remaining in the same activity 【发布时间】:2014-08-30 06:13:24 【问题描述】:

Activity 调用Fragment,我将显示一个ListView 和两个Buttons。当我单击menu_item(即在线显示)时,我正在更新数据,因此ListView。现在我需要反映更新的数据。单击“在线显示”后如何刷新Fragment。到目前为止,我已经使用了以下代码:

Intent intent = getIntent();
Intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);
finish();
startActivity(intent);

但这将重新启动整个Activity。我只需要刷新当前的Fragment

已编辑:添加代码

活动课

    public class ContactListActivity extends ActionBarActivity 

    ListView listView;
    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        final ActionBar actionBar = getActionBar();
        MenuButtonUtil.enableMenuButton(this);

        FragmentManager fragmentManager = getFragmentManager();

        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();

        MyContactsFragment contactListFragment = new MyContactsFragment ();
        fragmentTransaction.replace(android.R.id.content, contactListFragment);
        fragmentTransaction.commit();
    

    @Override
    public boolean onCreateOptionsMenu(Menu menu) 
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    

    @Override
    public boolean onOptionsItemSelected(MenuItem item) 
        int id = item.getItemId();
        if (id == R.id.show_online) 
            ContentValues values = new ContentValues();
            String where = "((" + ContactsContentProvider.PHONE_ID + " NOTNULL) AND ((" +
                       ContactsContentProvider.PHONE_ID+ " = 17486 )OR (" +
                       ContactsContentProvider.PHONE_ID+ " = 17494 )))";

            values.put(ContactsContentProvider.STATUS, true);
            this.getContentResolver().update(ContactsContentProvider.CONTENT_URI, values, where, null);

            listView = (ListView) this.findViewById(android.R.id.list);
            ((BaseAdapter) listView.getAdapter()).notifyDataSetChanged();

            return true;
        
        return super.onOptionsItemSelected(item);
    


片段

public class MyContactsFragment extends ListFragment

Button allContactsBtn;
Button neeoContactsBtn;
ListView listView;
CustomAdapterForAllContacts adapterForAllContacts;
CustomAdapterForNeeoContacts adapterForNeeoContacts;

@Override
public void onCreate(Bundle savedInstanceState) 
    // TODO Auto-generated method stub
    super.onCreate(savedInstanceState);
    final ActionBar actionBar = getActivity().getActionBar();
    MenuButtonUtil.enableMenuButton(getActivity());
    adapterForNeeoContacts = new CustomAdapterForNeeoContacts();
    adapterForAllContacts = new CustomAdapterForAllContacts();



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

    View view = inflater.inflate(R.layout.contactsfragment, container,false);

    allContactsBtn = (Button) view.findViewById(R.id.allContactsButton);
    neeoContactsBtn = (Button) view.findViewById(R.id.neeoContactsButton);
    listView = (ListView) view.findViewById(android.R.id.list);


    // ==================== Neeo Contacts ============================
    neeoContactsBtn.setOnClickListener(new OnClickListener() 
        @Override
        public void onClick(View v) 
            listView.setAdapter(adapterForNeeoContacts);

        
    );

    // ====================== All Contacts =============================

    allContactsBtn.setOnClickListener(new OnClickListener() 
        @Override
        public void onClick(View v) 
            listView.setAdapter(adapterForAllContacts);
        
    );

    return view;

适配器

private class CustomAdapterForAllContacts extends BaseAdapter 

public CustomAdapterForAllContacts()


    List<Contact> contactsList = getAllContacts();
    @Override
    public int getCount() 
        // TODO Auto-generated method stub
        return contactsList.size();
    

    @Override
    public Contact getItem(int arg0) 
        // TODO Auto-generated method stub
        return contactsList.get(arg0);
    

    @Override
    public long getItemId(int arg0) 
        // TODO Auto-generated method stub
        return arg0;
    

    @Override
    public View getView(int position, View view, ViewGroup viewGroup) 

        if(view==null)
        
            LayoutInflater inflater = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            view = inflater.inflate(R.layout.list_item, viewGroup,false);
        

        TextView contName = (TextView)view.findViewById(R.id.nameText);
        TextView contNumber = (TextView)view.findViewById(R.id.numberText);
        ImageView image = (ImageView)view.findViewById(R.id.contact_image);

        Contact contact = contactsList.get(position);

        String status = contact.getStatus();

        if(contact.getStatus().equals("1"))
            image.setBackgroundResource(com.example.mycontentprovider.R.drawable.person_empty_online);
        else
            image.setBackgroundResource(com.example.mycontentprovider.R.drawable.person_empty_offline);
        

        contName.setText(contact.getName());
        contNumber.setText(contact.getPhoneNumber());
        return view;
    

    public Contact getContactPosition(int position)
    
        return contactsList.get(position);
    
    public List<Contact> getAllContacts()

        List<Contact> contactList = new ArrayList<Contact>(); 

        String URL = "content://com.example.provider.Contacts/contacts";
        Uri baseUri1 = Uri.parse(URL);
        String[] select = ContactsContentProvider.PHONE_ID, ContactsContentProvider.STATUS;

        String where = "((" + ContactsContentProvider.NEEO_USER + " NOTNULL) AND (" +
                                                   ContactsContentProvider.NEEO_USER+ " = 1 )AND (" +
                                                   ContactsContentProvider.STATUS+ " = 1 ))";

        Cursor cursor =  getActivity().getContentResolver().query(baseUri1, select, where, null, "pid");

        for(cursor.moveToFirst(); cursor.moveToNext(); cursor.isAfterLast()) 
            Log.w("Filtered IDS",""+ cursor.getString(cursor.getColumnIndex(ContactsContentProvider.PHONE_ID))+
                    ""+ cursor.getString(cursor.getColumnIndex(ContactsContentProvider.STATUS)));
        


        Uri baseUri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;

        String[] projection = new String[] 
                ContactsContract.CommonDataKinds.Phone._ID,
                ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
                ContactsContract.CommonDataKinds.Phone.NUMBER;

        String selection = "((" + 
                ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " NOTNULL) AND (" +
                ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " != ' ' ))";

        String[] selectionArgs = null;
        String sortOrder = ContactsContract.CommonDataKinds.Phone._ID + " COLLATE LOCALIZED ASC";

        Cursor mCursor= getActivity().getContentResolver().query(baseUri, projection, selection, selectionArgs, sortOrder);

        // Joinging Both Cursors
                CursorJoiner joiner = new CursorJoiner(cursor, new String[] ContactsContentProvider.PHONE_ID , mCursor, new String[] ContactsContract.CommonDataKinds.Phone._ID);
                for (CursorJoiner.Result joinerResult : joiner) 
                    Contact cont = new Contact();
                    Log.e("Result", joinerResult.toString());
                    switch (joinerResult) 
                    case LEFT:
                        // handle case where a row in cursorA is unique
                        break;
                    case RIGHT:
                        // handle case where a row in cursorB is unique
                        cont.setID(mCursor.getString(mCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone._ID)));
                        cont.setName(mCursor.getString(mCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)));
                        cont.setPhoneNumber(mCursor.getString(mCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)));
                        cont.setStatus("0");
                        contactList.add(cont);
                        break;
                    case BOTH:
                        // handle case where a row with the same key is in both cursors
                        cont.setID(mCursor.getString(mCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone._ID)));
                        cont.setName(mCursor.getString(mCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)));
                        cont.setPhoneNumber(mCursor.getString(mCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)));
                        cont.setStatus(cursor.getString(cursor.getColumnIndex(ContactsContentProvider.STATUS)));
                        contactList.add(cont);
                        break;
                    
                
                mCursor.close();
                cursor.close();
        return contactList;
    
  

【问题讨论】:

使用 ListFragment 用于那个... 然后呢?有关刷新 Fragment 的 ListFragment 的任何具体内容。 在那个适配器上 .notifyDataSetChanged() 在 Activity Resume() 或任何地方...它会更新您的ListFragment... 你能告诉我你创建Adapter的代码吗?并查看我的答案以了解为什么 notifyDataSetChanged() 在您的情况下不起作用。总结:你需要改变Adapter的数据源,之后调用notifyDataSetChanged()会刷新ListView 尝试使用滑动刷新到您的应用程序。看到这个***.com/questions/41469040/fragment-refresh/… 【参考方案1】:

根据您实现ListViewAdapter 的具体方式,您有多种选择来解决此问题。

    致电notifyDataSetChanged() 通过重置Adapter

使用 notifyDataSetChanged() 进行更新

这是目前最好的解决方案,但您需要修改 List 使用的 Adapter 才能使其正常工作。例如,如果您像这样使用ArrayAdapter

String[] dataSource = new String[] 
    "A", "B", "C", ...
;

ArrayAdapter<String> adapter = new ArrayAdapter<String>(context, R.layout.example, dataSource);

如您所见,String[] 是我们的Adapter 的数据源。我们可以像这样修改数组,但是这些更改不会立即反映在ListView

dataSource[0] = "some new String value";

只有当我们调用notifyDataSetChanged() 时,ListView 才会更新:

adapter.notifyDataSetChanged();

来自documentation

public void notifyDataSetChanged ()

通知附加的观察者基础数据已被 发生变化,任何反映数据集的视图都应自行刷新。

但是不要notifyDataSetChanged()notifyDataSetInvalidated()混淆,因为notifyDataSetInvalidated()做的事情完全不同,只会弄乱你的ListView

来自documentation

public void notifyDataSetInvalidated ()

通知附加的观察者基础数据不再是 有效或可用。一旦调用此适配器不再有效,并且 不应报告进一步的数据集更改。


通过重置Adapter进行更新

这很简单。每次设置新的Adapter 时,ListView 都会自行更新。如果由于某种原因您不能使用notifyDataSetChanged(),那么您必须这样做。每次您想更新您的ListView 时,只需创建一个新的Adapter

ArrayAdapter<String> adapter = new ArrayAdapter<String>(context, R.layout.example, newData);

并使用setAdapter() 将其设置为ListView

listView.setAdapter(adapter);

这将始终更新ListView,但此解决方案存在一些问题。首先,每次更新ListView 时,它都会滚动回顶部,当频繁更新或ListView 中有很多内容时,这可能会很烦人。


编辑:

您的代码中有几处不是最优化的。首先,您的Adapter 不应包含下载联系人的代码。它只是不属于那里,Adapter 的唯一责任应该是他从给定的数据源创建Views。所以首先你应该将getAllContacts() 方法移到Adapter 之外。我建议你为此创建静态辅助方法,我冒昧地修改了你的代码:

public class ContactsHelper 

    public static List<Contact> getAllContacts(Context context) 

        List<Contact> contactList = new ArrayList<Contact>();

        String URL = "content://com.example.provider.Contacts/contacts";
        Uri baseUri1 = Uri.parse(URL);
        String[] select = ContactsContentProvider.PHONE_ID, ContactsContentProvider.STATUS;

        String where = "((" + ContactsContentProvider.NEEO_USER + " NOTNULL) AND (" +
                ContactsContentProvider.NEEO_USER + " = 1 )AND (" +
                ContactsContentProvider.STATUS + " = 1 ))";

        Cursor cursor = context.getContentResolver().query(baseUri1, select, where, null, "pid");

        for (cursor.moveToFirst(); cursor.moveToNext(); cursor.isAfterLast()) 
            Log.w("Filtered IDS", "" + cursor.getString(cursor.getColumnIndex(ContactsContentProvider.PHONE_ID)) +
                    "" + cursor.getString(cursor.getColumnIndex(ContactsContentProvider.STATUS)));
        

        Uri baseUri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;

        String[] projection = new String[]
                ContactsContract.CommonDataKinds.Phone._ID,
                ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
                ContactsContract.CommonDataKinds.Phone.NUMBER;

        String selection = "((" +
                ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " NOTNULL) AND (" +
                ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " != ' ' ))";

        String[] selectionArgs = null;
        String sortOrder = ContactsContract.CommonDataKinds.Phone._ID + " COLLATE LOCALIZED ASC";

        Cursor mCursor = context.getContentResolver().query(baseUri, projection, selection, selectionArgs, sortOrder);

        // Joinging Both Cursors
        CursorJoiner joiner = new CursorJoiner(cursor, new String[]ContactsContentProvider.PHONE_ID, mCursor, new String[]ContactsContract.CommonDataKinds.Phone._ID);
        for (CursorJoiner.Result joinerResult : joiner) 
            Contact cont = new Contact();
            Log.e("Result", joinerResult.toString());
            switch (joinerResult) 
                case LEFT:
                    // handle case where a row in cursorA is unique
                    break;
                case RIGHT:
                    // handle case where a row in cursorB is unique
                    cont.setID(mCursor.getString(mCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone._ID)));
                    cont.setName(mCursor.getString(mCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)));
                    cont.setPhoneNumber(mCursor.getString(mCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)));
                    cont.setStatus("0");
                    contactList.add(cont);
                    break;
                case BOTH:
                    // handle case where a row with the same key is in both cursors
                    cont.setID(mCursor.getString(mCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone._ID)));
                    cont.setName(mCursor.getString(mCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)));
                    cont.setPhoneNumber(mCursor.getString(mCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)));
                    cont.setStatus(cursor.getString(cursor.getColumnIndex(ContactsContentProvider.STATUS)));
                    contactList.add(cont);
                    break;
            
        
        mCursor.close();
        cursor.close();
        return contactList;
    

使用此代码,您可以像这样获取所有联系人:

List<Contact> contacts = ContactsHelper.getAllContacts(getActivity());

在此之后,我们需要修改您的 Adapter 以便 notifyDateSetChanged() 可以工作:

private class CustomAdapterForAllContacts extends BaseAdapter 

    private final List<Contact> contactsList;
    private final LayoutInflater inflater;

    public CustomAdapterForAllContacts(Context context, List<Contact> contacts) 
        this.inflater = LayoutInflater.from(context);
        this.contactsList = contacts;
    

    @Override
    public int getCount() 
        return contactsList.size();
    

    @Override
    public Contact getItem(int position) 
        return contactsList.get(position);
    

    @Override
    public long getItemId(int position) 
        return position;
    

    // We expose the List so we can modify it from outside
    public List<Contact> contacts() 
        return this.contactsList;    
    

    private class SimpleViewHolder 

        private final SparseArray<View> viewArray = new SparseArray<View>();
        private final View convertView;

        public SimpleViewHolder(View convertView) 
            this.convertView = convertView;
        

        public View get(int id) 
            View view = this.viewArray.get(id, null);
            if(view == null) 
                view = this.convertView.findViewById(id);
                this.viewArray.put(id, view);
            
            return view;
        
    

    @Override
    public View getView(int position, View convertView, ViewGroup viewGroup) 

        // By implementing the view holder pattern you only need to perform 
        // findViewById() once. This will improve the performance of `ListView`
        // and reduce lag.
        SimpleViewHolder viewHolder;
        if (convertView == null) 
            convertView = this.inflater.inflate(R.layout.list_item, viewGroup, false);
            viewHolder = new SimpleViewHolder(convertView);
            convertView.setTag(viewHolder);
        

        viewHolder = (SimpleViewHolder) convertView.getTag();

        TextView contName = (TextView) viewHolder.get(R.id.nameText);
        TextView contNumber = (TextView) viewHolder.get(R.id.numberText);
        ImageView image = (ImageView) viewHolder.get(R.id.contact_image);

        Contact contact = getItem(position);

        String status = contact.getStatus();

        if (contact.getStatus().equals("1")) 
            image.setBackgroundResource(com.example.mycontentprovider.R.drawable.person_empty_online);
         else 
            image.setBackgroundResource(com.example.mycontentprovider.R.drawable.person_empty_offline);
        

        contName.setText(contact.getName());
        contNumber.setText(contact.getPhoneNumber());
        return view;
    
  

我在这个Adapter 中更改了多项内容。首先,ContactsList 现在是最终的,我添加了一个方法contacts() 来公开List,这样我们就可以从外部修改Adapter 中的数据。我还实现了视图持有者模式,以便您的 ListView 滚动更快更流畅!

我希望我没有忘记任何东西,但这应该是您需要的所有更改。您可以像这样使用新的Adapter

List<Contact> contacts = ContactsHelper.getAllContacts(getActivity());
CustomAdapterForAllContacts adapter = new CustomAdapterForAllContacts(getActivity(), contacts);
listView.setAdapter(adapter);

如果你想稍后更新ListView,你需要像这样修改Adapter里面的List

List<Contact> newData = ContactsHelper.getAllContacts(getActivity());
adapter.contacts().clear();
adapter.contacts().addAll(newData);
adapter.notifyDataSetChanged();

希望能帮到你,如果还有什么问题欢迎追问!

【讨论】:

检查我编辑的问题。 好的,我明白了。您不应该在适配器内执行数据下载。那样的东西不属于那里。在Adapter 中用作数据源的List 通常应该是最终的,而不是像您那样处理。我将根据一些建议编辑我的答案。 我已经更新了我的答案!如果您还有其他问题,请随时提问。 我来看看,如果我建议使用不同的方法来加载数据,您会不会感到困扰?你必须使用LoaderManager吗? CursorJoiner 呢? 我已经使用了 CursorJoing 和它的工作方式,就像你说的那样。但是,如果我的实际通讯录中发生更改,我需要在运行时反映更改。这就是为什么我使用 LoaderManager。【参考方案2】:

如果你在 Fragment 中,那么你可以这样做

// code for fetching the data
// ...
// ...
((BaseAdapter) yourlistview.getAdapter()).notifyDataSetChanged();

【讨论】:

以上是关于刷新同一活动中剩余的当前片段(ListView 数据)的主要内容,如果未能解决你的问题,请参考以下文章

每 2 秒刷新一次从 JSON 响应中填充的 listView

Fragment的ListView项接口定义中的按钮?

listview 没有在带有 viewpager 选项卡的片段中刷新

片段中的Android ListView - 获取新数据后刷新表的问题

Android中Adapter刷新数据问题

片段活动错误中的ListView Adapter上下文,我该怎么办?