如何防止 AsyncTask 在 onScroll 事件中被多次执行?
How would I prevent AsyncTask from being executed multiple times in onScroll event?
我有一个 AsyncTask,它在 onPostExecute 事件中刷新我的 listView 并在 doInBackground 事件中检索一些数据。问题是我的 AsyncTask 在 onScroll 事件中被执行了多次。我怎样才能阻止它这样做?
顺便说一下,我正在尝试在我的应用程序中创建一个 Infinite Scroll。也许我做错了什么?
这是我的 onScroll 事件:
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
previousTotal = totalItemCount;
try {
itemNews = listAdapter.getData();
}catch (Exception e){
System.out.println("itemNews is empty");
}
if(totalItemCount > 2) {
artId = itemNews.get(firstVisibleItem).articleId;
}
if(firstVisibleItem > ((previousTotal)/2))
{
UpdateListAsyncTask updateListAsyncTask = new UpdateListAsyncTask(artId, mActivity, listAdapter);
updateListAsyncTask.execute();
}
这是我的 AsyncTask:
public class UpdateListAsyncTask extends AsyncTask<Void, Void, Void> {
public int currentArticleId;
public Activity mActivity;
RemoteData remoteData;
public ListAdapterRegular listAdapter;
UpdateListAsyncTask(int currentArticleId, Activity activity, ListAdapterRegular listAdapterRegular)
{
this.mActivity = activity;
this.currentArticleId = currentArticleId;
this.listAdapter = listAdapterRegular;
}
@Override
protected void onPreExecute()
{
remoteData = new RemoteData(mActivity, "News");
}
@Override
protected Void doInBackground(Void... params) {
try{
remoteData.writeServerData("&from=" + currentArticleId);
System.out.println("DoInBackground writeServerData");
}catch (Exception e)
{
e.printStackTrace();
System.out.println("UpdateListAsyncTask: doInBackground exception!");
}
return null;
}
@Override
protected void onPostExecute(Void result)
{
List<News> dataList = Select.from(News.class).orderBy("date DESC").list();
System.out.println("onPostExecuteInitiated");
listAdapter.clear();
listAdapter.addAll(dataList);
listAdapter.notifyDataSetChanged();
}
}
非常感谢任何帮助和想法!
更新:
我不得不重做我的代码,但这是值得的。我是按照link做的:https://github.com/codepath/android_guides/wiki/Endless-Scrolling-with-AdapterViews
我会用这样的东西
// The total number of items in the dataset after the last load
private int previousTotalItemCount = 0;
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
previousTotal = totalItemCount;
try {
itemNews = listAdapter.getData();
}catch (Exception e){
System.out.println("itemNews is empty");
}
// If the total item count is zero and the previous isn't, assume the
// list is invalidated and should be reset back to initial state
if (totalItemCount < previousTotalItemCount) {
this.previousTotalItemCount = totalItemCount;
if (totalItemCount == 0) { this.loading = true; }
}
if(totalItemCount > 2) {
artId = itemNews.get(firstVisibleItem).articleId;
}
// If it’s still loading, we check to see if the dataset count has
// changed, if so we conclude it has finished loading and update the current page
// number and total item count.
if(loading && totalItemCount > previousTotalItemCount) {
loading = false;
previousTotalItemCount = totalItemCount;
}
if(!loading && firstVisibleItem > ((previousTotal)/2))
{
loading = true;
UpdateListAsyncTask updateListAsyncTask = new UpdateListAsyncTask(artId, mActivity, listAdapter);
updateListAsyncTask.execute();
}
}
PS 当我实现无限滚动时,我用这个作为例子 https://github.com/codepath/android_guides/wiki/Endless-Scrolling-with-AdapterViews
您的方法可以有其他改进,但没有任何改进,如果您想要的只是多个异步任务而不是 运行,为什么不试试这个?
改变
if(firstVisibleItem > ((previousTotal)/2))
{
UpdateListAsyncTask updateListAsyncTask = new UpdateListAsyncTask(artId, mActivity, listAdapter);
updateListAsyncTask.execute();
}
到
if(firstVisibleItem > ((previousTotal)/2))
{
if(mUpdateListAsyncTask != null && (mUpdateListAsyncTask.getStatus == AsyncTask.Status.RUNNING|| mUpdateListAsyncTask.getStatus ==AsyncTask.Status.PENDING)) {
return;
} else {
mUpdateListAsyncTask = new UpdateListAsyncTask(artId, mActivity, listAdapter);
updateListAsyncTask.execute();
}
}
基本上,如果状态为 运行 或 PENDING,只需跳过创建新的异步任务并 运行 将其启动。应该可以。
您可能想执行最后一个任务,所以我将 UpdateListAsyncTask updateListAsyncTask
设为属性。
现在改变这个:
if(firstVisibleItem > ((previousTotal)/2))
{
UpdateListAsyncTask updateListAsyncTask = new UpdateListAsyncTask(artId, mActivity, listAdapter);
updateListAsyncTask.execute();
}
对此:
if(firstVisibleItem > ((previousTotal)/2))
{
try{
updateListAsyncTask.cancel(true);
}catch(Exception ex){}
updateListAsyncTask = new UpdateListAsyncTask(artId, mActivity, listAdapter);
updateListAsyncTask.execute();
}
private UpdateListAsyncTask updateListAsyncTask = null;
...
if(firstVisibleItem > ((previousTotal)/2))
{
//Create just if not exist or if it's finished
if (updateListAsyncTask == null || updateListAsyncTask.getStatus() == Status.FINISHED) {
updateListAsyncTask = new UpdateListAsyncTask(artId, mActivity, listAdapter);
}
//Start only if it's not already running
if (updateListAsyncTask.getStatus() == Status.PENDING) {
updateListAsyncTask.execute();
}
}
我有一个 AsyncTask,它在 onPostExecute 事件中刷新我的 listView 并在 doInBackground 事件中检索一些数据。问题是我的 AsyncTask 在 onScroll 事件中被执行了多次。我怎样才能阻止它这样做? 顺便说一下,我正在尝试在我的应用程序中创建一个 Infinite Scroll。也许我做错了什么? 这是我的 onScroll 事件:
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
previousTotal = totalItemCount;
try {
itemNews = listAdapter.getData();
}catch (Exception e){
System.out.println("itemNews is empty");
}
if(totalItemCount > 2) {
artId = itemNews.get(firstVisibleItem).articleId;
}
if(firstVisibleItem > ((previousTotal)/2))
{
UpdateListAsyncTask updateListAsyncTask = new UpdateListAsyncTask(artId, mActivity, listAdapter);
updateListAsyncTask.execute();
}
这是我的 AsyncTask:
public class UpdateListAsyncTask extends AsyncTask<Void, Void, Void> {
public int currentArticleId;
public Activity mActivity;
RemoteData remoteData;
public ListAdapterRegular listAdapter;
UpdateListAsyncTask(int currentArticleId, Activity activity, ListAdapterRegular listAdapterRegular)
{
this.mActivity = activity;
this.currentArticleId = currentArticleId;
this.listAdapter = listAdapterRegular;
}
@Override
protected void onPreExecute()
{
remoteData = new RemoteData(mActivity, "News");
}
@Override
protected Void doInBackground(Void... params) {
try{
remoteData.writeServerData("&from=" + currentArticleId);
System.out.println("DoInBackground writeServerData");
}catch (Exception e)
{
e.printStackTrace();
System.out.println("UpdateListAsyncTask: doInBackground exception!");
}
return null;
}
@Override
protected void onPostExecute(Void result)
{
List<News> dataList = Select.from(News.class).orderBy("date DESC").list();
System.out.println("onPostExecuteInitiated");
listAdapter.clear();
listAdapter.addAll(dataList);
listAdapter.notifyDataSetChanged();
}
}
非常感谢任何帮助和想法! 更新: 我不得不重做我的代码,但这是值得的。我是按照link做的:https://github.com/codepath/android_guides/wiki/Endless-Scrolling-with-AdapterViews
我会用这样的东西
// The total number of items in the dataset after the last load
private int previousTotalItemCount = 0;
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
previousTotal = totalItemCount;
try {
itemNews = listAdapter.getData();
}catch (Exception e){
System.out.println("itemNews is empty");
}
// If the total item count is zero and the previous isn't, assume the
// list is invalidated and should be reset back to initial state
if (totalItemCount < previousTotalItemCount) {
this.previousTotalItemCount = totalItemCount;
if (totalItemCount == 0) { this.loading = true; }
}
if(totalItemCount > 2) {
artId = itemNews.get(firstVisibleItem).articleId;
}
// If it’s still loading, we check to see if the dataset count has
// changed, if so we conclude it has finished loading and update the current page
// number and total item count.
if(loading && totalItemCount > previousTotalItemCount) {
loading = false;
previousTotalItemCount = totalItemCount;
}
if(!loading && firstVisibleItem > ((previousTotal)/2))
{
loading = true;
UpdateListAsyncTask updateListAsyncTask = new UpdateListAsyncTask(artId, mActivity, listAdapter);
updateListAsyncTask.execute();
}
}
PS 当我实现无限滚动时,我用这个作为例子 https://github.com/codepath/android_guides/wiki/Endless-Scrolling-with-AdapterViews
您的方法可以有其他改进,但没有任何改进,如果您想要的只是多个异步任务而不是 运行,为什么不试试这个?
改变
if(firstVisibleItem > ((previousTotal)/2))
{
UpdateListAsyncTask updateListAsyncTask = new UpdateListAsyncTask(artId, mActivity, listAdapter);
updateListAsyncTask.execute();
}
到
if(firstVisibleItem > ((previousTotal)/2))
{
if(mUpdateListAsyncTask != null && (mUpdateListAsyncTask.getStatus == AsyncTask.Status.RUNNING|| mUpdateListAsyncTask.getStatus ==AsyncTask.Status.PENDING)) {
return;
} else {
mUpdateListAsyncTask = new UpdateListAsyncTask(artId, mActivity, listAdapter);
updateListAsyncTask.execute();
}
}
基本上,如果状态为 运行 或 PENDING,只需跳过创建新的异步任务并 运行 将其启动。应该可以。
您可能想执行最后一个任务,所以我将 UpdateListAsyncTask updateListAsyncTask
设为属性。
现在改变这个:
if(firstVisibleItem > ((previousTotal)/2))
{
UpdateListAsyncTask updateListAsyncTask = new UpdateListAsyncTask(artId, mActivity, listAdapter);
updateListAsyncTask.execute();
}
对此:
if(firstVisibleItem > ((previousTotal)/2))
{
try{
updateListAsyncTask.cancel(true);
}catch(Exception ex){}
updateListAsyncTask = new UpdateListAsyncTask(artId, mActivity, listAdapter);
updateListAsyncTask.execute();
}
private UpdateListAsyncTask updateListAsyncTask = null;
...
if(firstVisibleItem > ((previousTotal)/2))
{
//Create just if not exist or if it's finished
if (updateListAsyncTask == null || updateListAsyncTask.getStatus() == Status.FINISHED) {
updateListAsyncTask = new UpdateListAsyncTask(artId, mActivity, listAdapter);
}
//Start only if it's not already running
if (updateListAsyncTask.getStatus() == Status.PENDING) {
updateListAsyncTask.execute();
}
}