Android onScroll以加载更多来自MySQL/PHP/JSON的结果


Android onScroll to load more results from MySQL/PHP/JSON

我正在寻找一种方法来将onScroll侦听器嵌入我的列表视图。我已经阅读了很多关于使用:

notifyDataSetChanged();

但是,老实说,我不知道如何将它实现到我的工作代码中。

目前,我使用 PHP(JSON 响应)从 MySQL 数据库将一堆记录拉入列表视图。一切正常,但我想限制首次启动活动时返回的记录数(我知道这是使用 PHP 脚本中的 SQL 语句完成的),然后当用户滚动以使其加载较旧的帖子并将它们附加到当前列表视图时。我看过很多例子,但我找不到任何与我当前结构有关的例子。

这是我当前的代码:(LiveFeed.java)

public class LiveFeed extends SherlockListActivity {
@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Used To Put Dark Icons On Light Action Bar
    boolean isLight = ThemeList.THEME == R.style.Theme_Sherlock;
    // Build Action Bar
    menu.add("Refresh")
        .setIcon(isLight ? R.drawable.ic_refresh : R.drawable.ic_refresh_inverse).setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
    menu.add("+ Add Post")
        .setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM | MenuItem.SHOW_AS_ACTION_WITH_TEXT);
    return true;
}
// Define Menu Item Actions
@Override
public boolean onOptionsItemSelected(MenuItem item) {
    String menuItemTitle = item.getTitle().toString();
    if(menuItemTitle.equals("Refresh")){
        // Clear ArrayList
        posts.clear();
        // Re-Run AsyncTask
        new FeedTask().execute();
    }
    if(menuItemTitle.equals("+ Add Post")){
        Intent intent = new Intent(this, AddPost.class);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        startActivity(intent);
    }
    return true;
}
private ArrayList<Feed> posts = new ArrayList<Feed>();
// Define JSON Nodes
private static final String TAG_ID = "id";
private static final String TAG_POST = "post";
private static final String TAG_TIME = "post_time";
@Override
public void onCreate(Bundle savedInstanceState) {
    setTheme(ThemeList.THEME);
    super.onCreate(savedInstanceState);
    // Load All Posts
    new FeedTask().execute();
    // Get ListView
    ListView lv = getListView();
    // Selecting Single List Item Starts EditPost Activity
    lv.setOnItemClickListener(new OnItemClickListener() {
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
            // getting values from selected ListItem
            String pid = ((TextView) view.findViewById(R.id.postid)).getText().toString();
            // Starting new intent
            Intent in = new Intent(getApplicationContext(), EditPost.class);
            // sending Post Id To EditPost Activity
            in.putExtra(TAG_ID, pid);
            // starting new activity and expecting some response back
            startActivityForResult(in, 100);
        }
    });
}
// Response from Edit Product Activity
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
    super.onActivityResult(requestCode, resultCode, data);
    // If Result Code 100 (edited/deleted post) - Reload Screen
    if (resultCode == 100) {
        Intent intent = getIntent();
        finish();
        startActivity(intent);
    }
}
// AsyncTask To Pull In All Posts And Build ListView
private class FeedTask extends AsyncTask<Void, Void, Void> {
    private ProgressDialog progressDialog;
    protected void onPreExecute() {
        progressDialog = ProgressDialog.show(LiveFeed.this,"", "Loading. Please wait...", true);
    }
    @Override
    protected Void doInBackground(Void... arg0) {
        try {
            HttpClient httpClient = new DefaultHttpClient();
            HttpPost httpPost = new HttpPost("http://www.mysite.com/android/login/get_posts.php");
            HttpResponse httpResponse = httpClient.execute(httpPost);
            String result = EntityUtils.toString(httpResponse.getEntity());
            JSONArray jArray = new JSONArray(result);
            JSONObject json_data = null;
            for (int i = 0; i < jArray.length(); i++) {
                json_data = jArray.getJSONObject(i);
                Feed feed = new Feed();
                feed.id = json_data.getString(TAG_ID);
                feed.post = json_data.getString(TAG_POST);
                feed.post_time = json_data.getString(TAG_TIME);
                posts.add(feed);
            }
        } 
        catch (Exception e){
            Log.e("ERROR", "Error loading JSON", e);
        }
        return null;
    }
    @Override
    protected void onPostExecute(Void result) {
        progressDialog.dismiss();
        setListAdapter(new FeedListAdaptor(LiveFeed.this, R.layout.feed, posts));
    }
}
private class FeedListAdaptor extends ArrayAdapter<Feed> {
    private ArrayList<Feed> posts;
    public FeedListAdaptor(Context context, int textViewResourceId, ArrayList<Feed> items) {
        super(context, textViewResourceId, items);
        this.posts = items;
    }
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View v = convertView;
        if (v == null) {
            LayoutInflater vi = (LayoutInflater)
            getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            v = vi.inflate(R.layout.feed, null);
        }
        Feed o = posts.get(position);
        TextView ht = (TextView) v.findViewById(R.id.postid);
        TextView tt = (TextView) v.findViewById(R.id.toptext);
        TextView bt = (TextView) v.findViewById(R.id.bottomtext);
        ht.setText(o.id);
        tt.setText(o.post);
        bt.setText(o.post_time);
        return v;
    }
}
// Define Variables Used To Build Feed
public class Feed {
    String id;
    String post;
    String post_time;
}

}

以及提取结果的 PHP 脚本:(get_posts.php)

include('config.php');
$q=mysql_query("SELECT f.id, f.post, DATE_FORMAT(f.post_time, '%b %D, %Y %r') AS post_time, f.updated, u.firstname, u.lastname FROM feed f
INNER JOIN users u ON u.id=f.user__id WHERE archived='0' ORDER BY f.id DESC");
while($row=mysql_fetch_assoc($q))
$output[]=$row;
print json_encode($output);
mysql_close();

我正在考虑在初始帖子中传递一个起始数字,以告诉 PHP 脚本要拉回多少结果。然后,每次在滚动过程中获取结果时,返回下一个数字,以用作从 onScroll() 调用的下一个 SQL 查询中的 LIMIT。(现在我没有在我的SQL查询上设置任何限制。

希望有人能帮帮我!

我目前正在做类似的事情。您可以将 setOnScrollListener 用于您的列表视图并像这样实现它:

@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
    boolean isLastItemVisible = firstVisibleItem + visibleItemCount == totalItemCount;
    if (isLastItemVisible) {
        listOverscrolled();
    }
}

比在列表Overscrolled方法中做这样的事情:

    if (!isLoadingData()) {
      setLoadingData(true);
      loadData(); 
}
并在加载数据

方法中启动加载数据的新异步任务。我所做的是将上次下载的记录的 id 附加到 url 查询中,并在 SQL 查询中添加条件 WHERE id> last_id。每次请求更多记录时,以相同的顺序返回它们非常重要。

所以在你的情况下,它会是这样的:

 lastId = feedListAdapter.get(feedListAdapter.count());
    ... and in AsyncTask ...
   HttpPost httpPost = new HttpPost("http://www.mysite.com/android/login/get_posts.php?lastid=" + lastId);

比在OnPostExecute中,你可以做这样的事情:

 setLoading(false);
    feedListAdapter.addAll(feeds);
    feedListAdapter.notifyDataSetChanged();

当然,您的适配器必须更早创建。