【问题标题】:Background HTTP tasks后台 HTTP 任务
【发布时间】:2012-08-30 17:17:33
【问题描述】:

我的应用上有一个启动页面,我想做的是启动后台任务以开始下载内容,以便在用户需要时准备好。

例如一周的照片或其他东西。

启动画面启动(启动后台任务)
启动画面完成(后台任务仍在工作)
主屏幕启动(临时“加载”占位符)
用户导航到另一个活动
下载完成
用户返回主屏幕,主屏幕会更新本周图片

现在我知道异步任务,但我听说异步任务在 finish() 上被取消,而且我还听说它们没有被取消。

这种任务,后台加载是否最好在服务中处理? 谁能给我一个在后台加载这样的东西的教程?

编辑:
人们都在提到UI工作应该在UI中,非UI在非UI中。我考虑过处理程序,但是当当前活动不活动时,侦听器是否工作?

假设我在 main 中启动了一个处理程序,然后切换页面。当我回来时,我很确定主 UI 不会更新,因为在我查看另一个页面时侦听器没有触发。

我假设我必须创建一个类来存储变量或其他东西。服务完成后,它会将“pic_of_week_loaded”设置为 true,并且当主程序重新加载时,它会检查此 var。我该怎么办?

【问题讨论】:

  • 考虑使用DownloadManager?
  • DownloadManager 是 API 9,这可能是个问题
  • Dashboard 始终是检查优先支持哪些版本的好工具。

标签: java android service android-asynctask


【解决方案1】:

您可以从 Application 类扩展,在其中创建一个线程(或 AsyncTask),基本上可以从 Internet 下载内容。完成后,您可以通知主屏幕活动以将内容显示到占位符中。

【讨论】:

  • 不,但是一旦创建,Activity 可以获取 ApplicationObject 的句柄并简单地执行myApp.isDataDownloaded() 之类的操作来找出当前状态。
  • @Rawr 是的。您可以在应用程序类中声明一个标志,指示是否显示主屏幕活动。您可能需要在主屏幕活动的onStart() 将标志设置为真,并在onStop() 将其设置为假。后台下载完成后,检查标志,如果为真则通知主屏幕活动,否则您可能需要从主屏幕活动的onStart() 加载内容(您可以在应用程序类上设置一个标志,告知是否下载完成与否)。
  • @Eng.Fouad 好的,是的,所以这种方式可能有效。我听说很多人就 AsyncTask 是否在 finish() 上被取消相互矛盾,您能否提供一些可靠的文档来建议 Async 即使在 finish() 之后仍然存在。后台任务应该停止的唯一时间是如果有人进入设置并按字面意思强制停止程序。
  • 查看this tutorial 了解更多关于如何实现Application 类的信息。
  • @Eng.Fouad 谢谢我真的认为链接是破解 xD
【解决方案2】:

另一种选择是使用Android Asynchronous Http Client

我会在活动中执行此操作,但请确保在您显示活动时检查活动是否仍处于活动状态(确保尚未调用 onDestroy)..

然后我会缓存结果,这样您就不必从网络再次加载它(将日期存储在文件名中,以便您知道图片的日期,以便您知道缓存是否已经保存了最新的) .

【讨论】:

  • 非常好的主意。我在想主程序会检查 SD 卡以查看某个位置是否有图像,应用程序会检查最新的图像并删除存储在 SD 卡中的图像,如果有更新的图像。然后后台任务将下载并将其保存到该位置。主要只是检查这个“所述位置”中是否存在图像。我什至没有考虑缓存,文件名中的日期也很聪明。
【解决方案3】:

考虑使用IntentService 做你的后台工作,这样你就不会被活动生命周期束缚。

编辑:根据 cmets。

使用自己的应用程序对象非常简单。像这样创建它:

final public class MyApplication extends Application {
 ....
}

然后将您的清单更新为如下所示:

<application
    android:name=".MyApplication"
    ...

理论上就是这样。您现在可以在那里添加自己的方法,包括。异步任务操作。您可以使用MyApplication app = (MyApplication)getApplicationContext(); 处理您的应用程序对象,然后执行app.XXX();一些重要的注意事项:如果您想在 ApplicationObject 中使用 AsyncTask,请注意Android Bug #20915。根据讨论,解决方法是在onCreate() 中执行此操作:

public void onCreate() {
  // Workaround for android bug #20915
  // http://code.google.com/p/android/issues/detail?id=20915
  try {
    Class.forName("android.os.AsyncTask");
  } catch (Exception e) {
    e.printStackTrace();
  }

  super.onCreate();
  ...

【讨论】:

  • 是的,我认为这可能是最安全的方式。知道我将如何存储一个变量,主要检查图像是否完成下载?
  • 在我的应用程序中,我通常有自己的ApplicationObject,所以我可以将这样的“全局”变量和逻辑放在那里,但这并不是必需的(但是我看到了很多好处,但它会使你的代码一点)。我现在能想到的最简单的方法就是为此使用共享偏好。
  • 是的,我认为它可能必须是一个共享偏好,但我开始需要一个地方来存储任何活动都可以访问的变量。我可能会研究这个应用程序对象。有链接吗?
  • 我接受了另一个答案,因为这是我要采用的路径,而不是 IntentService,但我对你的很多 cmets 投了赞成票,因为你提供了很多关于 Application 类概念的信息。先生,你很有帮助。
  • 没问题。无论如何,请查看更新,因为您可能也遇到了所描述的问题。
【解决方案4】:

我将尝试解释为什么 (1) 将全局状态保持在 Application sublcass 和 (2) 使用 AsyncTask 在这种情况下都是不好的方法。

(1) 如果应用程序不在前台并且当前应用程序中没有正在运行的服务,操作系统可能会终止您的应用程序进程。这篇文章的更多细节:How to declare global variables in Android?

(2) AsyncTask 比它看起来更狡猾。 :) 例如,如果 ((OS = 3.0)) 默认情况下,所有任务都在同一个后台工作线程上运行。我的意思是当前 Java 进程的所有任务都在唯一的后台线程上执行。因此,其他活动中下一个可能开始的任务将不得不等到第一个/init 一个完成。我认为这不是您想要得到的(如果用户从 Home 活动导航到其他活动,并且另一个活动需要使用 AsyncTask 加载一些数据,那么请确保您的第一个/初始化任务快速完成,因为它会阻止任何后续任务)。当然,如果 first/init 任务的工作量不大,那么这点可以不用担心。有关AsyncTask 工作原理的更多详细信息,请参阅这篇文章:Running multiple AsyncTasks at the same time -- not possible?

所以我的建议是使用IntentService 下载您在启动时需要的图像/日期。一旦下载数据,它就会在SharedPreferences 中设置标志并发送广播。此时 Home 活动可能处于 3 种状态:

  • 活动(已通过onResume(),但尚未通过onPause()
  • 暂停(已通过onPause(),但尚未返回onResume
  • 销毁

当它处于活动状态时,它使用广播接收器来监听服务。当它暂停时,它会取消注册广播接收器,但当它处于活动状态时,它所做的第一件事就是检查来自SharedPreferences 的标志。如果 flag 仍未设置,则注册广播接收器。

【讨论】:

  • 知道缺点是件好事。问题是如果应用程序在前台,我只希望它在后台运行,巧合的是,我将在后台运行一个服务,所以它不应该是一个问题:) 我只是认为应用程序的方式将是总体上对我正在制作的应用类型更有用:O
【解决方案5】:

1. 好吧,AsyncTask 被引入到 android 中,以提供它对 Painless Threading 的了解,但我认为这里不是这种情况......

2. 现在让 UI 工作在 UI 线程上总是好的,非 UI 工作在非 UI 线程上,这成为了一个规则HoneyComb安卓版的到来。

3. 现在您想在后台下载一些内容,这些内容不包括在 UI 上反映输出。然后我想你看看 java.util.concurrent 中的CountDownLatch 类。

4. 否则,您始终可以在后台运行 Non-UI thread

【讨论】:

  • 所以下载不会直接影响 UI,但是当它完成时它可能会发送一个广播以及设置一个全局变量。如果 main 当前打开,它会接收广播并更新。如果稍后返回 main,onResume 将检查变量。任何想法如何存储通过活动持续存在的变量?而不是在活动之间传递,在后台设置一个变量?几乎就像一种偏好。
  • 当我想做你提到的事情时,我使用单例模式,我知道有些人不喜欢这个想法,但是当我在做 Android 时它真的很好用......创建一个类使用单例模式,具有您想要设置的那些变量,以及它的 getter 和 setter 方法......瞧!!!!你完成了............从应用程序的任何地方随时随地访问它......但它会在您的应用程序运行之前可用......(它不会在应用程序运行后持久化)应用程序已关闭),如果您打算以后使用它,请使用数据库来存储此类中的这些值
【解决方案6】:

我更喜欢将ThreadsHandlers 用于后台任务。线程会在后台执行一些操作,然后当任务完成时,更新处理程序以更新 UI。下面是一些示例代码:

Handler handler = new Handler() { //Declare this as a global variable to the class
      @Override
      public void handleMessage(Message msg) {
    //display each item in a single line
          if(msg.obj.equals("update subcat")){
              subcategoryAdapter.notifyDataSetChanged();
          }else if (msg.obj.equals("update products")){
              productsAdapter.notifyDataSetChanged();
          }else if (msg.obj.equals("update cat")){
              categoryAdapter.notifyDataSetChanged();
          }
     }
 };

这是你的后台任务:

Thread background = new Thread(new Runnable() {

    @Override
    public void run() {
        getSubCategories(((Categories)searchResults.get(pos)).ID);
        handler.sendMessage(handler.obtainMessage(pos, "update subcat"));
        }
    });
    background.start();

【讨论】:

  • 我很确定如果活动已经 finish()ed,notifyDataSetChanged() 不会触发
猜你喜欢
  • 2015-07-10
  • 2011-09-29
  • 2011-09-15
  • 2013-02-04
  • 2017-10-01
  • 1970-01-01
  • 2020-11-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多