【问题标题】:Killing threads杀死线程
【发布时间】:2010-11-04 14:17:24
【问题描述】:

我创建了一个类,它是 Thread 的扩展。此类访问 Web 服务并在屏幕上抛出一些数据。我不关心这些数据的持久化(屏幕显示搜索结果)。

目前,用户只需键入 EditText 并单击搜索按钮。我想去掉搜索按钮并实现类似于 Google 的即时搜索的功能,在您输入时,搜索结果会得到更新。

这意味着,随着用户键入,搜索参数会发生变化。 我希望能够终止当前正在运行的线程(如果当前正在运行)并使用新的搜索字符串生成一个新的线程。如何做到这一点?我可以用 Thread 来做,还是需要使用新对象?

【问题讨论】:

  • 这不应该在移动设备中发生。大概您使用的是 3g 而不是 wifi,即使是 1 个搜索结果也可能需要很长时间。您必须缓存用户可以键入的每个可能组合的搜索结果。疯了吧。根据数据,您可能只想在启动时立即获取所有数据,然后使用自动完成功能在本地搜索,如下所述。如果你的数据是网页,那就别想了。
  • 正在搜索的数据列表一个单词列表。它最多返回 25 个单词。当您键入“w”时,Web 服务会要求输入以“w”开头的单词。如果您随后键入“wi”,Web 服务会要求输入以“wi”开头的单词。我想要完成的是,如果当用户键入“i”时对“w”的 Web 服务调用仍然处于活动状态,它会取消它并尝试对“wi”的 Web 服务调用。此外,我在调用 Web 服务之前设置了 2 秒的睡眠时间;因此,如果用户在 2 秒内输入“w”然后输入“wi”,则不会使用带宽,因为第一个呼叫从未打出。
  • 网络服务调用发生在线程中;因此,通过停止 Web 服务调用,我实际上是指停止包含它的线程。

标签: android multithreading android-asynctask


【解决方案1】:

这比简单地杀死一个线程更困难。您可以在线程上调用interrupt(),但线程必须定期检查其中断状态并自行终止。

其次,您不希望在用户输入时立即启动线程。您将很快通过线程生成使系统不堪重负。在进行搜索之前实现 100-200 毫秒的等待时间,以便您可以合理地确定用户已完成输入。谷歌的服务器可以处理负载,但手机不能。

编辑:扩展我的第一点,线程可能很难取消。在这种情况下,事件调度线程需要以某种方式告诉正在运行的线程它需要停止。您可以使用线程中内置的interrupt 工具,但正如this article 所指出的那样,它往往很棘手。相反,我只需要一个boolean 变量,可以通过一些外部线程将其设置为cancelled。诀窍(如该链接所示)是您需要定期检查线程是否已被取消,如果是,则需要手动中止。

您将遇到的下一个问题是是否已经对某个外部服务器进行了网络调用。它将阻塞在该线程中,直到它返回并且该线程将无法杀死自己。这可能需要几秒钟。

所以让我们来玩一下 - 如果用户键入一个字符,并且您的超时期限由于某种原因而到期并进行了网络调用,那么用户在超时期限到期的情况下键入另一个字符以便进行另一个网络调用怎么办?如果您的网络调用需要 5 秒,那么第一个线程将继续运行,即使事件调度线程取消它,至少 5 秒。您现在有两个线程进行网络调用。

现在展开。如果用户这样做并创建 4 或 5 个线程怎么办?这是您压倒手机资源的地方。我不是告诉你不要追求这个,只是想指出这个领域可能存在的问题。

【讨论】:

  • 嗯,我打算做的是,当用户键入一个字符时,任何正在执行的线程都被取消,搜索结果被擦除,并启动一个具有新搜索参数的新线程。当一个线程启动时,它会等待 2-3 秒,然后才能真正访问 Web 服务。这使用户有时间在使用收音机之前键入另一个字符并取消先前的搜索。问题是我不知道如何以编程方式执行此操作(取消部分)。
【解决方案2】:

使用AutoCompleteTextView 小部件。从您的网络服务中预取您的搜索提示,以将它们加载到自动完成数组中并设置其适配器。根据提示的复杂程度,可选择使用自定义光标适配器。

类似:

AutoCompleteTextView inputSearch;
String[] autocompleteArray = new String[size of prefetched items];
//fill autocompleteArray with webservice data

inputSearch = (AutoCompleteTextView)findViewById(R.id.inputSearch);
searchAdapter = new ArrayAdapter<String>(context, R.layout.autcomplete_dropdown, autocompleteArray);
inputSearch.setAdapter(searchAdapter);

R.layout.autocomplete_dropdown 可能类似于:

<?xml version="1.0" encoding="utf-8"?>
<TextView 
  xmlns:android="http://schemas.android.com/apk/res/android" 
  android:id="@+id/name"
  android:singleLine="false"
  android:textSize="15sp"
  android:paddingLeft="3dip"
  android:paddingRight="3dip"
  android:paddingTop="15dip"
  android:paddingBottom="15dip"
  android:textColor="#000000"
  android:layout_width="fill_parent"
  android:layout_height="wrap_content" /> 

在应用中进行搜索,您要搜索的内容有多大?预加载 sqlite 中的所有数据并经常检查来自网络的更新数据?

否则我会说您应该限制应用尝试启动线程的次数。设置某种计时器,它将: 看看是不是……

  1. 一个线程已经在工作了
  2. 自上次以来输入已更改 时间或具有非空搜索值
  3. 用户甚至在搜索 屏幕

如果一切正常,启动线程获取结果

只是一个想法,没试过这个

【讨论】:

  • 对不起,我可能没有表达清楚我的意图。我不打算重新创建 Google 的自动完成功能。我正在寻找重新创建 Google 的即时搜索。当用户在 EditText 中键入搜索词时,列表中的结果会更新。
【解决方案3】:

线程创建是非常耗时的操作。因此,我建议使用一个线程,该线程随后将使用新的搜索字符串调用 Web 服务。

【讨论】:

    【解决方案4】:

    您的意思是自动完成。我认为您不需要启动几个线程来处理它。使用 android Auto Complete 并使用 AutoCompleteTextView

    此外,不建议通过子类化 java 线程或实现接口来使用线程。您可以使用AsyncTask在后台执行耗时操作。

    【讨论】:

    • 不,我不是说自动完成。我的意思是即时搜索。当用户在 EditText 中键入时,列表中显示的搜索结果会更新。我会考虑使用 AsyncTask 而不是 Thread,尽管任何类型的异步操作都可以让我做我想做的事。
    猜你喜欢
    • 2011-04-19
    • 1970-01-01
    • 2021-11-13
    • 1970-01-01
    • 1970-01-01
    • 2023-04-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多