【问题标题】:How to load data from background thread, updating the UI asynchornously如何从后台线程加载数据,异步更新 UI
【发布时间】:2014-07-09 02:40:43
【问题描述】:

我在 FragmentActivity 类中创建了一个类 asyncTask

    class aysncTask extends AsyncTask<Void, Void, Void>
    {
            @Override
            protected Void doInBackground(Void... params) {
                    assert(filterfiles != null);
                    while( !searchDone.getValue() )
                    {
                            filterfiles.searchTargetFile(android.os.Environment.getExternalStorageDirectory()+ "/");
                            publishProgress();      //Doesn't work here.
                    }
                    return null;
            }

            @Override
            protected void onProgressUpdate(Void... params)
            {
                    UpdateUI();                     //Only executes as the search is done.
            }

            @Override
            protected void onPostExecute(Void result)
            {
            }
    }

filterfiles.searchTargetFile(~) 函数搜索本地数据,将它们添加到ArrayList: cachedData。但我等不及搜索完成,然后更新 UI。用户将等待太久。 但我不知道在哪里放置更新的 UI 代码。 不能在方法onPostExecute(Void result)里面,因为我还要等待搜索完成。

也不能在onProgressUpdate(Void params)方法内,因为一旦我调用filterfiles.searchTargetFile(~),它就会在本地系统中搜索匹配的文件。只有搜索完成后,才会调用publishProgress()

我想到的是创建另一个线程观察cachedData,一旦找到文件,我将添加文件并更新UI。

可是我不知道怎么办?这是一个好习惯吗? 请提供一些建议的解决方案!我在这个问题上花了两天时间。

更新 我设计了一种机制来实现异步加载数据和更新 UI。当前的 搜索目标文件代码:

 public void searchTargetFile(String path)
    {   
            File dirRoot= new File( path );  
            File[] dirOrFile= dirRoot.listFiles();

            if( dirOrFile == null) return;
            for( File f : dirOrFile )
            {   
                    if( f.isDirectory() )
                    {   
                            searchTargetFile( f.getAbsolutePath() );
                    }   
                    else                        
                    {   
                            for(String extName: filterFileExt)
                            {   
                                    if( f.getName().endsWith(extName) )
                                    {   
                                            newDisplayFile= new DisplayFile(new String( f.getAbsolutePath() ), f.length());
                                            this.searchedDisplayFile.add(newDisplayFile);
                                    }   
                            }   
                    }   
            }   
            this.searchDone.setValue(true); 
    }   

其中 newDisplayFile 是项目将被插入到 searchedDisplayFile

*问题:

  1. 如何通过线程重写搜索代码,以便我可以pauseresume它。 wait()notify() 会起作用吗?

  2. 应该将wait()notify() 代码放在aysncTask 类的什么位置?

感谢任何其他更好的方法!!!

【问题讨论】:

  • 正确的方法是在 onProgressUpdate 和 onPostExecute 中。两者都将在 UI 线程上调用,因此它们可以触摸 UI,并且不会出现同步问题。
  • 所以你应该定义重写你的 filterfiles.searchTargetFile 方法,使用一些分页技术
  • 不,我想要的场景是找到一些文件,立即更新 UI。一个线程负责搜索数据,另一个线程观察搜索到的数据,然后更新UI
  • @NguyễnHoàiNam paging technique 是什么?有什么例子吗?如何实现searchTargetFile 真的让我筋疲力尽。
  • 你看过这个关于Watching a Directory for Changes的教程吗?

标签: java android multithreading android-asynctask lazy-loading


【解决方案1】:

所以我会在这里为你的评论添加我的答案,因为评论无法显示代码 sn-p。

因为我不知道你的数据是什么样子的,所以假设你有一个索引数据库,并且你想对整个数据库进行搜索,获取它们的列表。分页的想法是搜索有限的项目,保存偏移量以备将来使用,同时用这些搜索的项目更新您的列表。例如(伪代码):

int max_items = 10;
int offset = 0;
while(searchable) {
    List<Items> items_ = searchFromOffset(offset); // this will return up to 10 items each time
    update(items_); // call the progressUpdate here
    offset += items_.size(); // next time you will search from next "page"
    searchable = checkForFinish(); // return a boolean value showing if the searching is finish or not
}

真正的问题可能更复杂,但大体思路如上图。这也将帮助您为每个查询节省内存。

希望这会有所帮助。

【讨论】:

  • 我不知道如何实现searchFromOffset() 方法?我应该将搜索方法放在Runnable Class 中吗?任何例子都值得赞赏!
  • 好吧,它的行为与“searchTargetFile”的行为相同,但它只会返回一些项目/文件,而不是全部。我们重复调用以节省内存,您可以在搜索更多项目时更新结果。我猜你使用光标在整个文件列表中移动,所以尝试在某处“暂停”光标,保存位置,更新文件列表,然后从该位置开始下一次搜索。
  • 是的,看来可以。但是,我不知道如何pause 我的搜索方法。我想知道将搜索方法放在线程中是否可行?
  • 您能否在问题中添加您的 searchTargetFile() 方法的代码?它可能会帮助其他人知道您尝试过什么。
  • 好的,但是你能等一会儿吗?简单地说,实现只是一个recursive approach。它将搜索所有项目,如果是目录,则会更深入地查找,否则将文件添加到ArrayList。它不能被暂停或停止。一旦开始搜索,它必须遍历整个本地文件系统。我认为这是主要问题。我将尝试通过在线程上实现搜索方法来解决它。所以请稍候. 谢谢。
【解决方案2】:

我使用 onProgressUpdate(progressValue); 而不是 发布进度。这对我来说效果很好。

【讨论】:

  • onProgressUpdate() 和 publishProgress() 成对工作。您从后台发布某些内容,然后 onProgressUpdate() 将使用它来更新进度。
猜你喜欢
  • 2012-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多