AsyncTask 类启动了许多其他线程,因为我使用的是第三方库。我不确定库打开了多少个线程,但我想等待它们全部完成,然后再用它们获取的数据填充我的 ListView 。
目前我正在休眠 10000 毫秒,但这不切实际,因为我不知道它有多大。
这个问题的正确解决方案是什么?
task = new mTask();
task.execute(appsList);
new Thread(new Runnable() {
public void run() {
populateList();
}
}).start();
}
private class mTask extends AsyncTask<List<ApplicationInfo>, Void, Void> {
ProgressDialog progress;
@Override
protected void onPreExecute() {
progress = new ProgressDialog(MainActivity.this);
progress.setIndeterminate(true);
progress.show();
super.onPreExecute();
}
@SuppressWarnings("deprecation")
@Override
protected Void doInBackground(List<ApplicationInfo>... params) {
appDataManager = new AppDataManager(MainActivity.this,
mySQLiteAdapter, MainActivity.this);
appDataManager.work(params[0]);
return null;
}
@Override
protected void onPostExecute(Void result) {
mySQLiteAdapter.close();
progress.dismiss();
super.onPostExecute(result);
}
}
@SuppressWarnings("deprecation")
public void populateList() {
try {
Thread.sleep(10000)
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
runOnUiThread(new Runnable() {
public void run() {
Cursor cursor;
mySQLiteAdapter.openToRead();
cursor = mySQLiteAdapter.queueAll();
ArrayList<String> appsList = new ArrayList<String>();
if (cursor.moveToFirst()) {
do {
appsList.add(cursor.getString(1));
} while (cursor.moveToNext());
}
cursor.moveToFirst();
ArrayAdapter<String> adp = new ArrayAdapter<String>(
MainActivity.this, android.R.layout.simple_list_item_1,
appsList);
listContent.setAdapter(adp);
cursor.close();
mySQLiteAdapter.close();
Log.i("finished", "finished");
}
});
}
AppDataManager
public void work(List<ApplicationInfo> appsList) {
List<ApplicationInfo> appList = appsList;
mySQLiteAdapter.openToWrite();
mySQLiteAdapter.deleteAll();
mySQLiteAdapter.close();
for (int i = 0; i < 5; i++) {
String name = appList.get(i).name;
String pack = appList.get(i).packageName;
// TODO AsyncTask
getHtml(pack, name);
}
}
public void getHtml(final String pack, final String name) {
String url = MARKET_URL + pack;
//AndroidQuery library. fetch html
aq.ajax(url, String.class, 1000, new AjaxCallback<String>() {
@Override
public void callback(String url, String htm, AjaxStatus status) {
Log.i("status", status.getMessage());
parseHtml(htm, pack, name);
}
});
}
最佳答案
首先,我会将电话转到 populateList进入onPostExecute你的方法AsyncTask .我也会重写 populateList删除 sleep 并假设它在 UI 线程上运行(消除 runOnUiThread 调用并将 run 方法的主体直接移动到 populateList 中)。
现在要防止 AsyncTask从完成 doInBackground直到 AppDataManager完成它的工作。首先定义一个完成标志和一个可以同步的锁对象:
private class mTask extends AsyncTask<List<ApplicationInfo>, Void, Void> {
boolean complete;
static Object LOCK = new Object();
. . .
}
然后修改AppDataManager类以在工作完成时提供对另一个对象的回调。定义一个字段 callback并更新您的 API 和方法:
public void work(List<ApplicationInfo> appsList, Runnable callback) {
this.callback = callback; // define a field named "callback"
List<ApplicationInfo> appList = appsList;
mySQLiteAdapter.openToWrite();
mySQLiteAdapter.deleteAll();
mySQLiteAdapter.close();
for (int i = 0; i < 5; i++) {
String name = appList.get(i).name;
String pack = appList.get(i).packageName;
// TODO AsyncTask
getHtml(pack, name);
}
}
public void getHtml(final String pack, final String name) {
String url = MARKET_URL + pack;
//AndroidQuery library. fetch html
aq.ajax(url, String.class, 1000, new AjaxCallback<String>() {
@Override
public void callback(String url, String htm, AjaxStatus status) {
Log.i("status", status.getMessage());
parseHtml(htm, pack, name);
if (callback != null) {
callback.run();
}
}
});
}
现在修改你的doInBackground等待设置标志的方法:
protected Void doInBackground(List<ApplicationInfo>... params) {
appDataManager = new AppDataManager(MainActivity.this,
mySQLiteAdapter, MainActivity.this);
appDataManager.work(params[0], new Runnable() {
public void run() {
synchronized (LOCK) {
complete = true;
LOCK.notifyAll();
}
}
});
// wait for appDataManager.work() to finish...
synchronized (LOCK) {
while (!complete) {
LOCK.wait();
}
}
return null;
}
这应该可以完成工作。但是,您可能应该对此进行详细说明以处理各种错误(例如,为 AppDataManager 提供错误通知机制)。
更新 我终于注意到您在 AppDataManager 中进行了五次网络交易。 .因此,不是立即在 ajax() 的回调方法中运行回调。 ,递减一个计数器,并且只在计数器达到 0 时回调。在 work() 中将计数器初始化为 5在进入调用 getHtml() 的循环之前.由于计数器将被单独的线程修改,因此对它的访问需要同步。 (或者,您可以使用 AtomicInteger 作为计数器。
关于android - 我的 AsyncTask 类中有其他线程。在执行以下方法之前,我如何等待它及其所有线程完成?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13362510/
我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时
我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚
这可能是个愚蠢的问题。但是,我是一个新手......你怎么能在交互式rubyshell中有多行代码?好像你只能有一条长线。按回车键运行代码。无论如何我可以在不运行代码的情况下跳到下一行吗?再次抱歉,如果这是一个愚蠢的问题。谢谢。 最佳答案 这是一个例子:2.1.2:053>a=1=>12.1.2:054>b=2=>22.1.2:055>a+b=>32.1.2:056>ifa>b#Thecode‘if..."startsthedefinitionoftheconditionalstatement.2.1.2:057?>puts"f
我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R
我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("
我有一个服务模型/表及其注册表。在表单中,我几乎拥有服务的所有字段,但我想在验证服务对象之前自动设置其中一些值。示例:--服务Controller#创建Action:defcreate@service=Service.new@service_form=ServiceFormObject.new(@service)@service_form.validate(params[:service_form_object])and@service_form.saverespond_with(@service_form,location:admin_services_path)end在验证@ser
我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin
我喜欢使用Textile或Markdown为我的项目编写自述文件,但是当我生成RDoc时,自述文件被解释为RDoc并且看起来非常糟糕。有没有办法让RDoc通过RedCloth或BlueCloth而不是它自己的格式化程序运行文件?它可以配置为自动检测文件后缀的格式吗?(例如README.textile通过RedCloth运行,但README.mdown通过BlueCloth运行) 最佳答案 使用YARD直接代替RDoc将允许您包含Textile或Markdown文件,只要它们的文件后缀是合理的。我经常使用类似于以下Rake任务的东西:
rails中是否有任何规定允许站点的所有AJAXPOST请求在没有authenticity_token的情况下通过?我有一个调用Controller方法的JqueryPOSTajax调用,但我没有在其中放置任何真实性代码,但调用成功。我的ApplicationController确实有'request_forgery_protection'并且我已经改变了config.action_controller.consider_all_requests_local在我的environments/development.rb中为false我还搜索了我的代码以确保我没有重载ajaxSend来发送
假设我在Ruby中有这个each循环。@list.each{|i|putsiifi>10breakend}我想循环遍历列表直到满足条件。这让我感到“不像Ruby”,因为我是Ruby的新手,是否有Ruby方法可以做到这一点? 最佳答案 您可以使用Enumerable#detect或Enumerable#take_while,取决于您想要的结果。@list.detect{|i|putsii>10}#Returnsthefirstelementgreaterthan10,ornil.正如其他人所指出的,更好的风格是先进行子选择,然后再对其