简体   繁体   English

尽管我使用了Adapter.notifyDataSetChanged(),但在更改数据集后,Android ListView不会刷新

[英]Android ListView not refreshing after dataset changed, though I have used the Adapter.notifyDataSetChanged()

I know similar questions had been asked here a couple of times, but none of them could help me with my problem, so I will just have to ask again. 我知道这里曾问过类似的问题几次,但是没有一个问题可以帮助我解决我的问题,所以我只需要再问一次。

What I have is an app that has a fragment that holds a ListView in the main activity and I used a PullableListView so that when I drag the ListView up, it will trigger the onLoadMore() callback method to load more data from the server. 我所拥有的应用程序具有一个片段,该片段在主活动中拥有一个ListView,并且我使用了PullableListView,因此当我向上拖动ListView时,它将触发onLoadMore()回调方法从服务器加载更多数据。 Once data loaded, the data will be saved to a SQLiteDB and then used by the ListView to show the updated data. 加载数据后,数据将保存到SQLiteDB,然后由ListView用来显示更新的数据。

The is my PullableListViewFragment.java: 这是我的PullableListViewFragment.java:

public class PullableListViewFragment extends Fragment implements
    OnItemClickListener {

private ListView listView;
private PullToRefreshLayout ptrl;

private MissionDB mMissionDB;
private List<MissionEntity> mData;

private MissionListAdapter mAdapter;

/**
 * Specify the exact mission that will be displayed in MissionDetailActivity
 */
private int mIndexOfMission;

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
        Bundle savedInstanceState) {
    View pullableLayout = inflater.inflate(R.layout.pullable_layout, container, false);
    listView = (ListView) pullableLayout.findViewById(R.id.content_view);
    listView.setDivider(null);
    ptrl = (PullToRefreshLayout) pullableLayout.findViewById(R.id.refresh_view);
    ptrl.setOnRefreshListener(new RefreshListener());
    loadData();

    Log.d(Constants.LOG_TAG, "onCreateView Called from PullableListViewFragment");

    return pullableLayout;
}

/**
 * Initialise ListView
 */
@Override
public void onActivityCreated(Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    mAdapter = new MissionListAdapter(getActivity(), mData);
    listView.setAdapter(mAdapter);
    listView.setOnItemClickListener(this);
    mAdapter.notifyDataSetChanged();
    Log.d(Constants.LOG_TAG, "onActivityCreated Called from PullableListViewFragment");
}

/**
 * Load data from db
 */
private void loadData() {
    mData = new ArrayList<>();
    mMissionDB = MissionDB.getInstance(MyApplication.getContext());
    mData = mMissionDB.loadMission();
}

/**
 * OnItemClick event
 */
@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
        long id) {
    Intent intent = new Intent(getActivity(), MissionDetailActivity.class);
    mIndexOfMission = mData.get((int) id).getId();
    intent.putExtra("Position", mIndexOfMission);
    startActivity(intent);
}

}

And this is the RefreshListener.java: 这是RefreshListener.java:

public class RefreshListener implements PullToRefreshLayout.OnRefreshListener {

private MissionDB mMissionDB = MissionDB.getInstance(MyApplication.getContext());

@Override
public void onLoadMore(final PullToRefreshLayout pullToRefreshLayout) {
    // LoadMore
    new Handler() {

        @Override
        public void handleMessage(Message msg) {

            /** When drag up, load more mission that is older and not out of date */
            mMissionDB.open();
            int id = mMissionDB.getMaxOrMinId("MIN");
            final JSONObject oldMission = new JSONObject();
            try {
                oldMission.put("platform", "1");
                oldMission.put("more", 0);
                oldMission.put("id", id);
                oldMission.put("size", 1);
            } catch (JSONException e) {
                e.printStackTrace();
            }

            Thread t = new Thread(new Runnable() {

                @Override
                public void run() {
                    HttpRequest.sendHttpRequest(Constants.PULLORDRAG_TO_LOAD_MISSION_URL, oldMission, new HttpCallbackListener() {

                        @Override
                        public void onFinish(String response) {
                            MissionEntity mMission = new MissionEntity();

                            /** Save new mission to mission database */
                            try {
                                JSONObject jsonObject = new JSONObject(response);
                                JSONArray missionList = jsonObject.getJSONArray("taskList");
                                for (int i = 0; i < missionList.length(); i++) {
                                    JSONObject mission = missionList.getJSONObject(i);
                                    mMission.setId(mission.getInt("id"));
                                    mMission.setDownloadUrl(mission.getString("appPath"));
                                    mMission.setCreateTime(mission.getString("taskId"));
                                    mMission.setImageUrl(mission.getString("appImg"));
                                    mMission.setTitleName(mission.getString("appName"));
                                    mMission.setRemainTime("Remain: 1d 11h 23m 36s");
                                    mMission.setParticipant("135");
                                    mMission.setCreator("Google");
                                    mMission.setRequirement(mission.getString("description"));
                                    mMission.setRewards("TODO");
                                    mMission.setAttention("TODO");
                                    mMission.setValidDate(mission.getString("deadline"));
                                    mMission.setAccepted("0");
                                    mMission.setCollected("0");
                                    mMission.setAccomplished("0");
                                    mMissionDB.saveMission(mMission);
                                }
                            } catch (JSONException e) {
                                e.printStackTrace();
                            }
                        }

                        @Override
                        public void onError(Exception e) {
                            e.printStackTrace();
                            Log.e(Constants.LOG_TAG, "Error while loading more");
                        }
                    });
                }
            });

            try {
                t.start();
                t.join();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            pullToRefreshLayout.loadmoreFinish(PullToRefreshLayout.SUCCEED);

            //==================Update 1==================
            ListView list = (ListView) pullToRefreshLayout.findViewById(R.id.content_view);
            List<MissionEntity> missionList = mMissionDB.loadMission();
            Log.d(Constants.LOG_TAG, "mission size" + missionList.size());
            MissionListAdapter adapter = (MissionListAdapter) list.getAdapter();
            adapter.setData(missionList);
            adapter.notifyDataSetChanged();
            list.setAdapter(adapter);
            //==================Update 1==================
        }
    }.sendEmptyMessageDelayed(0, 1000);
}

}

The PullToRefreshLayout is a custom RelativeLayout that defined a inner interface OnRefreshListener that will be called once the onLoadMore() callback method is called. PullToRefreshLayout是一个自定义的RelativeLayout,它定义了一个内部接口OnRefreshListener ,一旦调用onLoadMore()回调方法,该内部接口就会被调用。

The ListView I use in the Fragment is a PullableListView that implemented a Pullable interface that can drag up. 我在该片段中使用ListView是实现了一个可拉接口,可以拖动一个PullableListView。

My Pullable.java: 我的Pullable.java:

public interface Pullable
{
    /**
     * If pull up is not needed, set canPullUp to false
     * 
     * @return true if the View can pull up
     */
    boolean canPullUp();
}

This is the fragment's layout.xml: 这是片段的layout.xml:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
          android:layout_width="match_parent"
          android:layout_height="match_parent"
          android:background="#f2f2f2"
          android:orientation="vertical">

<View
    android:layout_width="match_parent"
    android:layout_height="5dp" />

<pulltorefresh.PullToRefreshLayout
    android:id="@+id/refresh_view"
    android:layout_marginLeft="8dp"
    android:layout_marginRight="8dp"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <include layout="@layout/refresh_head"/>

    <!-- Supports all view that implemented the Pullable interface -->
    <pulltorefresh.PullableListView
        android:id="@+id/content_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    <include layout="@layout/load_more"/>

</pulltorefresh.PullToRefreshLayout>

</LinearLayout>

The problem is when the data in the SQLiteDB is changed after the onLoadMore() method, the ListView in the fragment doesn't refresh itself unless I navigate to another fragment within the same main activity and then navigate back. 问题是当在onLoadMore()方法之后更改SQLiteDB中的数据时,片段中的ListView不会刷新自身,除非我导航到同一主要活动中的另一个片段,然后再返回。

I tired all the ways I can find here and none of them help. 我在这里能找到的所有方法都很累,但没有一个可以帮助。

Could anyone tell me how can I make the ListView refresh itself when the data in the SQLiteDB changed. 任何人都可以告诉我,当SQLiteDB中的数据更改时,如何使ListView刷新。

[Update 1] I've added some code in the onLoadMore() callback, the size of the data remains the same after I get some data from the server, i think this is the problem why the ListVie is not refreshing, what's interesting is if I put a Thread.sleep(500) before mMission.loadMission() the size of the data is correct and everything is fine. [更新1]我在onLoadMore()回调中添加了一些代码,从服务器获取一些数据后数据的大小保持不变,我认为这就是为什么ListVie不刷新的问题,有趣的是如果我将Thread.sleep(500) mMission.loadMission() Thread.sleep(500)之前,则数据大小正确且一切都很好。 Any idea why? 知道为什么吗?

In onLoadMore method, you just only load data and save into database. 在onLoadMore方法中,您仅加载数据并保存到数据库中。 After load data, you should update the data source of the adapter and call adapter.notifyDataSetChanged() to refresh the listview. 加载数据后,您应该更新适配器的数据源并调用adapter.notifyDataSetChanged()以刷新列表视图。 or you can notify the fragment to reload data from database. 或者,您可以通知片段从数据库中重新加载数据。

Make sure it get data when load more first. 确保先加载更多数据,然后获取数据。 And I think your mMissionDB is changed indeed, but what about mData? 而且我认为您的mMissionDB确实发生了变化,但是mData呢? Your adapter is use mData as datasource actually, so you should update mData, and call adapter.notifyDataSetChanged() to refresh the listview. 您的适配器实际上是使用mData作为数据源,因此您应该更新mData,并调用adapter.notifyDataSetChanged()刷新列表视图。 Hope it can help you. 希望它能对您有所帮助。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM