java - 使用 EndlessRecyclerOnScrollListener 的 Asynctask 的无尽 RecyclerView

标签 java android listview android-asynctask android-recyclerview

我有一个搜索查询的 Activity (使用 async 任务和服务器端 PHP)并在 recycler view 中给出一个列表,现在我想在用户到达底部时实现无尽/无限滚动。我尝试使用 EndlessScrollListener 来做到这一点.我需要帮助解决两个问题。

首先,新列表会自行重新创建,而不是附加到旧列表。

其次,current_page int 变量保留了之前搜索和滚动时的值,这意味着当第二次运行 AsyncTask 时,current_page int 变量仍然保留第一次的值,不会重置。

   public class MainActivity extends AppCompatActivity {

// CONNECTION_TIMEOUT and READ_TIMEOUT are in milliseconds
public static final int CONNECTION_TIMEOUT = 10000;
public static final int READ_TIMEOUT = 15000;
private RecyclerView mRVFish;
private AdapterFish mAdapter;
private  LinearLayoutManager mLayoutManager;
private String searchQuery;


SearchView searchView = null;


private String query;


private EndlessRecyclerOnScrollListener mScrollListener = null;
private SwipeRefreshLayout mSwipeRefreshLayout = null;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);


    mRVFish = (RecyclerView) findViewById(R.id.fishPriceList);
    mLayoutManager = new LinearLayoutManager(MainActivity.this);
    mRVFish.setLayoutManager(mLayoutManager);

}


@Override
public boolean onCreateOptionsMenu(Menu menu) {

    // adds item to action bar
    getMenuInflater().inflate(R.menu.search_main, menu);

    // Get Search item from action bar and Get Search service
    MenuItem searchItem = menu.findItem(R.id.action_search);
    SearchManager searchManager = (SearchManager) MainActivity.this.getSystemService(Context.SEARCH_SERVICE);
    if (searchItem != null) {
        searchView = (SearchView) searchItem.getActionView();
    }
    if (searchView != null) {
        searchView.setSearchableInfo(searchManager.getSearchableInfo(MainActivity.this.getComponentName()));
        searchView.setIconified(false);
    }

    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {

    return super.onOptionsItemSelected(item);
}



// Every time when you press search button on keypad an Activity is recreated which in turn calls this function
@Override
protected void onNewIntent(Intent intent) {
    // Get search query and create object of class AsyncFetch
    if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
          query = intent.getStringExtra(SearchManager.QUERY);
        if (searchView != null) {
            searchView.clearFocus();
        }
       int startrow =0;
        String type="";
        String filetype="";

        AsyncFetch myTask = new AsyncFetch(query, startrow,  type,  filetype);


        myTask.execute();



        mScrollListener = new EndlessRecyclerOnScrollListener(mLayoutManager) {
            @Override
            public void onLoadMore(int current_page) {

                int startrow=current_page;
                String type="";
                String filetype="";
                AsyncFetch myTask = new AsyncFetch(query, startrow,  type,  filetype);

                myTask.execute();


            }
        };

        mRVFish.addOnScrollListener(mScrollListener);

        // enable pull down to refresh
        mSwipeRefreshLayout = (SwipeRefreshLayout) findViewById(R.id.swipeRefreshLayout);
        mSwipeRefreshLayout.setOnRefreshListener(new SwipeRefreshLayout.OnRefreshListener() {
            @Override
            public void onRefresh() {

                int startrow =0;
                String type="";
                String filetype="";

                AsyncFetch myTask = new AsyncFetch(query, startrow,  type,  filetype);

                myTask.execute();

                // after refresh is done, remember to call the following code
                if (mSwipeRefreshLayout != null && mSwipeRefreshLayout.isRefreshing()) {
                    mSwipeRefreshLayout.setRefreshing(false);  // This hides the spinner
                }
            }
        });



    }

}


// Create class AsyncFetch
private class AsyncFetch extends AsyncTask<String, String, String> {

    ProgressDialog pdLoading = new ProgressDialog(MainActivity.this);
    HttpURLConnection conn;
    URL url = null;
    String searchQuery;
    int startrow;
    String type;
    String filetype;


    public AsyncFetch(String searchQuery,  int startrow, String type, String filetype){
        this.searchQuery=searchQuery;
        this.startrow = startrow;
        this.type = type;
        this.filetype=filetype;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();

        //this method will be running on UI thread
        pdLoading.setMessage("\tLoading...");
        pdLoading.setCancelable(false);
        pdLoading.show();

    }

    @Override
    protected String doInBackground(String... params) {
        try {

            // Enter URL address where your php file resides
            url = new URL("http://someurl/json/search.php");

        } catch (MalformedURLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return e.toString();
        }
        try {

            // Setup HttpURLConnection class to send and receive data from php and mysql
            conn = (HttpURLConnection) url.openConnection();
            conn.setReadTimeout(READ_TIMEOUT);
            conn.setConnectTimeout(CONNECTION_TIMEOUT);
            conn.setRequestMethod("POST");

            // setDoInput and setDoOutput to true as we send and recieve data
            conn.setDoInput(true);
            conn.setDoOutput(true);

            // add parameter to our above url
            Uri.Builder builder = new Uri.Builder().appendQueryParameter("searchQuery", searchQuery).appendQueryParameter("startrow", String.valueOf(startrow));
            String query = builder.build().getEncodedQuery();

            OutputStream os = conn.getOutputStream();
            BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(os, "UTF-8"));
            writer.write(query);
            writer.flush();
            writer.close();
            os.close();
            conn.connect();

        } catch (IOException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
            return e1.toString();
        }

        try {

            int response_code = conn.getResponseCode();

            // Check if successful connection made
            if (response_code == HttpURLConnection.HTTP_OK) {

                // Read data sent from server
                InputStream input = conn.getInputStream();
                BufferedReader reader = new BufferedReader(new InputStreamReader(input));
                StringBuilder result = new StringBuilder();
                String line;

                while ((line = reader.readLine()) != null) {
                    result.append(line);
                }

                // Pass data to onPostExecute method
                return (result.toString());

            } else {
                return("Connection error");
            }

        } catch (IOException e) {
            e.printStackTrace();
            return e.toString();
        } finally {
            conn.disconnect();
        }


    }

    @Override
    protected void onPostExecute(String result) {


        //this method will be running on UI thread
        pdLoading.dismiss();

        List<DataFish> data=new ArrayList<>();

        pdLoading.dismiss();
        if(result.equals("no rows")) {
            Toast.makeText(MainActivity.this, "No Results found for entered query", Toast.LENGTH_LONG).show();
        }else{

            try {

                JSONArray jArray = new JSONArray(result);

                // Extract data from json and store into ArrayList as class objects
                for (int i = 0; i < jArray.length(); i++) {
                    JSONObject json_data = jArray.getJSONObject(i);
                    DataFish fishData = new DataFish();
                    try {
                        fishData.fileName = URLDecoder.decode(json_data.getString("file"), "UTF-8");
                    } catch (Exception e) {

                        Toast.makeText(MainActivity.this, e.toString(), Toast.LENGTH_LONG).show();
                        fishData.fileName=json_data.getString("file");


                    }

                    fishData.linkName = json_data.getString("link");
                    fishData.reg_date = json_data.getString("reg_date");
                    fishData.fileSize = json_data.getString("filesize");
                    data.add(fishData);
                }

                mAdapter = new AdapterFish(MainActivity.this, data);

                   mRVFish.setAdapter(mAdapter);


                if(jArray.length()>19)
                mScrollListener.setLoading(false);
                else
                    mScrollListener.setLoading(true);

            } catch (JSONException e) {
                // You to understand what actually error is and handle it appropriately
                Toast.makeText(MainActivity.this, e.toString(), Toast.LENGTH_LONG).show();
                Toast.makeText(MainActivity.this, result.toString(), Toast.LENGTH_LONG).show();
            }





        }


    }




 }



}

EndlessRecyclerOnScrollListener.java

public abstract class EndlessRecyclerOnScrollListener extends 
RecyclerView.OnScrollListener {
public static String TAG = EndlessRecyclerOnScrollListener.class.getSimpleName();

private int previousTotal = 0; // The total number of items in the dataset after the last load
private boolean loading = false; // True if we are still waiting for the last set of data to load.
private int visibleThreshold = 0; // The minimum amount of items to have below your current scroll position before loading more.
int firstVisibleItem, visibleItemCount, totalItemCount;

private int current_page = 20;

private LinearLayoutManager mLayoutManager;

public EndlessRecyclerOnScrollListener(LinearLayoutManager linearLayoutManager) {
    this.mLayoutManager = linearLayoutManager;
}

@Override
public void onScrolled(RecyclerView mRVFish, int dx, int dy) {
    super.onScrolled(mRVFish, dx, dy);

    if(dy < 0) {
        return;
    }
    // check for scroll down only
    visibleItemCount = mRVFish.getChildCount();
    totalItemCount = mLayoutManager.getItemCount();
    firstVisibleItem = mLayoutManager.findFirstVisibleItemPosition();

    // to make sure only one onLoadMore is triggered
    synchronized (this) {
        if (!loading && (totalItemCount - visibleItemCount) <= (firstVisibleItem + visibleThreshold)) {
            // End has been reached, Do something


            current_page=current_page+20;
            onLoadMore(current_page);
            loading = true;
        }
    }
}


public void setLoading(boolean loading) {
    this.loading = loading;
}

public abstract void onLoadMore(int current_page);

}

最佳答案

first, the new list recreates itself instead of appending to the old list.

如果你设置一个新的适配器,你会交换回收站 View 的内容。我想你可以在下面的代码中做到这一点

mAdapter = new AdapterFish(MainActivity.this, data);
mRVFish.setAdapter(mAdapter); 

要附加数据,您需要将新元素添加到适配器的数据集(您获取数据以在适配器中绑定(bind) View 的数据集),然后调用 adapter.notifyDataSetChanged() 或更好的 adapter.notifyItemRangeInserted(int positionStart,int itemCount) 还有一些工具可以优化添加元素,比如 DiffUtil

second, the current_page int variable keeps its value from the previous search and scroll, means when running AsyncTask for second time

不确定库开发人员的想法是什么,但最简单的方法是在 EndlessRecyclerOnScrollListener 中创建一个方法,类似于:

public void resetPage() {
    current_page = 20;
}

并在调用新搜索之前调用它。

关于java - 使用 EndlessRecyclerOnScrollListener 的 Asynctask 的无尽 RecyclerView,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44605378/

相关文章:

java - 使用 jUnit、Selenium Webdriver 打印有关测试失败的有意义的消息并继续执行脚本

java - 来自 JSON 的多维数组

c# - Linphone SDK 集成在 Xamarin Android 中返回未知程序集

android - 如何仅在 Listview 中的特定列上设置 OnLongClickListener 但对于所有行

java - 如何在 ListView 行中显示较长的 TextView 高度?

java - 使异常默认执行某些操作

java - 多对多关系中 @JoinTable 和共享 key 的异常

java - 查找给定范围内的史密斯数

java - 在 android 中有阴影的目标上拖放后拖放回到原来的位置?

android - 在 ListView 中滚动时切换按钮更改状态