【发布时间】:2016-04-10 00:58:54
【问题描述】:
我知道类似的问题已经在这里问过几次了,但没有一个可以帮助我解决我的问题,所以我只好再问一次了。
我有一个应用程序,它有一个在主活动中保存 ListView 的片段,我使用了 PullableListView,这样当我向上拖动 ListView 时,它会触发 onLoadMore () 回调方法从服务器加载更多数据。加载数据后,数据将保存到 SQLiteDB,然后由 ListView 使用以显示更新的数据。
这是我的 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);
}
}
这是 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);
}
}
PullToRefreshLayout 是一个自定义的 RelativeLayout,它定义了一个内部接口 OnRefreshListener,一旦调用 onLoadMore() 回调方法就会调用该内部接口。
我在Fragment中使用的ListView是一个PullableListView,实现了一个可以向上拖动的Pullable界面。
我的 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();
}
这是片段的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>
问题是当 SQLiteDB 中的数据在 onLoadMore() 方法之后发生更改时,片段中的 ListView 不会自行刷新,除非我导航到同一主活动中的另一个片段,然后再导航回来。
我已经厌倦了在这里可以找到的所有方法,但它们都无济于事。
谁能告诉我当 SQLiteDB 中的数据发生变化时如何让 ListView 自行刷新。
[更新 1] 我在 onLoadMore() 回调中添加了一些代码,从服务器获取一些数据后数据的大小保持不变,我认为这是问题所在为什么 ListVie 不刷新,有趣的是,如果我在 mMission.loadMission() 之前放一个 Thread.sleep(500),数据的大小是正确的,一切都很好。知道为什么吗?
【问题讨论】:
-
hmm,也许不是最聪明的解决方案,但我以前做的是刷新我的 ArrayList,用新的 ArrayList 重新加载 ArrayAdapter,然后将 ArrayAdapter 重新分配给 ListView 变量——就是这样.
-
@Razgriz 我已经尝试过您使用的方式,但效果不佳。我所做的是在 onLoadMore() 回调方法中,在 pullToRefreshLayout.loadmoreFinish(PullToRefreshLayout.SUCCEED); 之后,我确实从数据库中手动创建了一个新的 ArrayList 并通过 findViewById 获取 ListView 的实例,并将 ArrayList 分配给适配器,然后将其设置为 ListView,但它不起作用。这件事真的让我发疯了。
-
嗯,这很奇怪。在创建“重新加载”ArrayAdapter 之前尝试记录 ArrayList 的大小。也许,只是也许,您无法完全加载记录...?
-
@Razgriz
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); list.setAdapter(adapter);这是我在 loadMoreFinish() 回调后添加的,重新加载后大小仍然相同,知道为什么吗?对不起格式
标签: java android sqlite android-listview