【问题标题】:AsyncTask onPostExecute not called未调用 AsyncTask onPostExecute
【发布时间】:2015-02-04 16:31:16
【问题描述】:

我有一个带有TextView 的简单小部件。一个TextView 应该显示从网页获得的信息,我正在使用它来实现它:

private class DownloadWebpageTask extends AsyncTask<String, Void, String> {
    @Override
    protected String doInBackground(String... urls) {

        // params comes from the execute() call: params[0] is the url.
        try {
            return downloadUrl(urls[0]);
        } catch (IOException e) {
            return getString(R.string.srv_dwn);
        }
    }
    // onPostExecute displays the results of the AsyncTask.
    @Override
    protected void onPostExecute(String result) {
        widgetText1 = result;
    }
}

DownloadWebpageTask 从活动中调用,如下所示:

    DownloadWebpageTask downloadWebpageTask = new DownloadWebpageTask();
    Context context = this;
    AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
    RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.example_appwidget);
    ComponentName thisWidget = new ComponentName(context, Widget.class);

    ConnectivityManager cm =
            (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo netInfo = cm.getActiveNetworkInfo();

    if (netInfo != null && netInfo.isConnected())
    {
        remoteViews.setViewVisibility(R.id.widgettext1, View.VISIBLE);
        netInfo = cm.getActiveNetworkInfo();
        widgetText2 = netInfo.getTypeName();

        downloadWebpageTask.execute("http://checkip.amazonaws.com/");

        remoteViews.setTextViewText(R.id.widgettext1, widgetText1);
        remoteViews.setTextViewText(R.id.widgettext2, widgetText2);
        appWidgetManager.updateAppWidget(thisWidget, remoteViews);
    }
    else
    {
        remoteViews.setTextViewText(R.id.widgettext1, widgetText1);
        remoteViews.setViewVisibility(R.id.widgettext1, View.GONE);
        remoteViews.setTextViewText(R.id.widgettext2, getString(R.string.tbl_no_connection));
        appWidgetManager.updateAppWidget(thisWidget, remoteViews);
    }

此变量在我的Activity 类中定义,应该显示AsyncTask 的结果,但不显示。

public String widgetText1 = "initialtext";

逐步调试表明从未调用过onPostExecute,并且TextView 中的文本仍然是“初始文本”。

第二个TextView 根据需要更新,因为它不涉及AsyncTask

不过,包含DownloadWebpageTask 的类似代码在我的主要活动中运行良好。

【问题讨论】:

  • 我敢打赌 doInBackGround 没有被调用。或者它有一个异常并返回initstring。
  • 如果出现异常,它会返回除 'initialtext' 之外的特定字符串,如您在代码中所见。

标签: android android-activity android-asynctask widget


【解决方案1】:

您所做的只是更新String 变量。您应该使用EditTextsetText 方法进行更新。所以在onPostExecute 中执行如下操作:

@Override
protected void onPostExecute(String result)
{
    yourEditText.setText(result);
}

【讨论】:

  • 更新字符串值并稍后在 RemoteViews 中使用它来更新实际的 TextView。所以你是说不能改变 onPostExecure() 中的变量?
  • 哦,好吧,我明白了。我误解了你想做什么。使用onPostExecute 的目的是更新您的UI,因为onPostExecute 本身在UI 线程上运行。那么为什么不直接更新EditText呢?
  • 我在更新小部件 TextViews 时遇到了问题(就像它们不“可见”一样),所以我最终使用了一个额外的变量(widgetText1),然后将它传递给 remoteViews。那我试试用EditText吧。
  • 我看不到,也没有其他人在这里看到过您的字符串文件。
  • 'Initial text' 只是我用来检查代码是否有效的存根。而像 string.srv_dwn 这样的字符串实际上是“服务器关闭”。这里没有什么复杂的。
【解决方案2】:

AsyncTask 中的execute() 方法在后台运行,因此当您调用它时,活动中的代码会继续执行,因为无法知道execute() 方法需要多长时间才能完成:

downloadWebpageTask.execute("http://checkip.amazonaws.com/");

remoteViews.setTextViewText(R.id.widgettext1, widgetText1);

所以,第二行是在调用 onPostExcute() 之前执行的,此时,wigetText1 仍然具有“initialtext”值。

您应该从 onPostExecute() 方法直接更新小部件(正如@Willis 所说),它保证在对页面的请求完成后将更新它。

如果您需要使 TextView 或任何内容可见,请在 onPostExecute() 方法中进行。

但实际上,为了更新主 Activity 中的小部件,它们必须对 AsyncTask 可见,将其声明为 Activity 类的内部类,如下所示:

public class myActivity extends Activity {

//Declare the TextView as a instance variable in your activity
public TextView widgetText1;

protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_splash_screen);
       //Find your widget in the layout to avoid NullPointerException    when the AsynTask try to update it.
       widgetText1 = findViewById(R.id.some_id);
    }

//Inner class myTask
private class myTask extends AsyncTask<String, Void, String>{

        @Override
        protected String doInBackground(String... urls) {
            //some code
            return result;
        }

        @Override
        protected void onPostExecute(String result) {
           widgetText1.setText(result);
        }
    }
}

请注意,这样一来,您必须为要发出网页请求的每个活动创建一个新的 AsynTask,但这里是有关如何创建可重用 AsyncTask 的参考。

Extracting out your AsyncTasks into separate classes makes your code cleaner

【讨论】:

  • java.lang.RuntimeException:无法实例化活动 ComponentInfo{<...>.WidgetUpdateAct}:java.lang.NullPointerException
  • 我将尝试使用服务而不是活动,它不想工作,出现 1 个错误或其他错误。
【解决方案3】:

我已经切换到Service 而不是Activity,但我认为解决方案可以在这两种情况下实现。

我在 Service 类中创建了一个方法:

public void setIPWidget(String result)
{
    Context context = this;
    RemoteViews remoteViews = new RemoteViews(context.getPackageName(), R.layout.example_appwidget);
    AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
    ComponentName thisWidget = new ComponentName(context, Widget.class);

    remoteViews.setTextViewText(R.id.widgettext1, result);
    appWidgetManager.updateAppWidget(thisWidget, remoteViews);
}

在 onPostExecute 中,我只需调用该方法并获得结果:

    @Override
    protected void onPostExecute(String result) {
        setIPWidget(result);
    }

比我想象的要简单。

【讨论】:

    猜你喜欢
    • 2013-04-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多