草庐IT

android - 我的 AsyncTask 类中有其他线程。在执行以下方法之前,我如何等待它及其所有线程完成?

coder 2023-12-15 原文

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/

有关android - 我的 AsyncTask 类中有其他线程。在执行以下方法之前,我如何等待它及其所有线程完成?的更多相关文章

  1. ruby - 其他文件中的 Rake 任务 - 2

    我试图在一个项目中使用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时

  2. ruby - 如何将脚本文件的末尾读取为数据文件(Perl 或任何其他语言) - 2

    我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚

  3. ruby-on-rails - 如何在 ruby​​ 交互式 shell 中有多行? - 2

    这可能是个愚蠢的问题。但是,我是一个新手......你怎么能在交互式ruby​​shell中有多行代码?好像你只能有一条长线。按回车键运行代码。无论如何我可以在不运行代码的情况下跳到下一行吗?再次抱歉,如果这是一个愚蠢的问题。谢谢。 最佳答案 这是一个例子: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

  4. ruby-on-rails - 如何在我的 Rails 应用程序 View 中打印 ruby​​ 变量的内容? - 2

    我是一个Rails初学者,但我想从我的RailsView(html.haml文件)中查看Ruby变量的内容。我试图在ruby​​中打印出变量(认为它会在终端中出现),但没有得到任何结果。有什么建议吗?我知道Rails调试器,但更喜欢使用inspect来打印我的变量。 最佳答案 您可以在View中使用puts方法将信息输出到服务器控制台。您应该能够在View中的任何位置使用Haml执行以下操作:-puts@my_variable.inspect 关于ruby-on-rails-如何在我的R

  5. ruby - RuntimeError(自动加载常量 Apps 多线程时检测到循环依赖 - 2

    我收到这个错误:RuntimeError(自动加载常量Apps时检测到循环依赖当我使用多线程时。下面是我的代码。为什么会这样?我尝试多线程的原因是因为我正在编写一个HTML抓取应用程序。对Nokogiri::HTML(open())的调用是一个同步阻塞调用,需要1秒才能返回,我有100,000多个页面要访问,所以我试图运行多个线程来解决这个问题。有更好的方法吗?classToolsController0)app.website=array.join(',')putsapp.websiteelseapp.website="NONE"endapp.saveapps=Apps.order("

  6. ruby - 如何在 Rails 4 中使用表单对象之前的验证回调? - 2

    我有一个服务模型/表及其注册表。在表单中,我几乎拥有服务的所有字段,但我想在验证服务对象之前自动设置其中一些值。示例:--服务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

  7. ruby - 在 Ruby 中有条件地定义函数 - 2

    我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin

  8. ruby - 我可以将我的 README.textile 以正确的格式放入我的 RDoc 中吗? - 2

    我喜欢使用Textile或Markdown为我的项目编写自述文件,但是当我生成RDoc时,自述文件被解释为RDoc并且看起来非常糟糕。有没有办法让RDoc通过RedCloth或BlueCloth而不是它自己的格式化程序运行文件?它可以配置为自动检测文件后缀的格式吗?(例如README.textile通过RedCloth运行,但README.mdown通过BlueCloth运行) 最佳答案 使用YARD直接代替RDoc将允许您包含Textile或Markdown文件,只要它们的文件后缀是合理的。我经常使用类似于以下Rake任务的东西:

  9. jquery - 我的 jquery AJAX POST 请求无需发送 Authenticity Token (Rails) - 2

    rails中是否有任何规定允许站点的所有AJAXPOST请求在没有authenticity_token的情况下通过?我有一个调用Controller方法的JqueryPOSTajax调用,但我没有在其中放置任何真实性代码,但调用成功。我的ApplicationController确实有'request_forgery_protection'并且我已经改变了config.action_controller.consider_all_requests_local在我的environments/development.rb中为false我还搜索了我的代码以确保我没有重载ajaxSend来发送

  10. ruby - ruby 中有 each_if 吗? - 2

    假设我在Ruby中有这个each循环。@list.each{|i|putsiifi>10breakend}我想循环遍历列表直到满足条件。这让我感到“不像Ruby”,因为我是Ruby的新手,是否有Ruby方法可以做到这一点? 最佳答案 您可以使用Enumerable#detect或Enumerable#take_while,取决于您想要的结果。@list.detect{|i|putsii>10}#Returnsthefirstelementgreaterthan10,ornil.正如其他人所指出的,更好的风格是先进行子选择,然后再对其

随机推荐