【问题标题】:Android application and AsyncTask not behaving as expectedAndroid 应用程序和 AsyncTask 未按预期运行
【发布时间】:2014-06-30 06:09:05
【问题描述】:

我有一个 Android 应用程序,它使用一个单独的类与服务器通信。这工作正常,但是当我按下应用程序上的按钮(将消息发送到服务器)时,按钮变为灰色并且一切都挂起,直到收到响应。我宁愿让应用显示 ProgressDialog,以便用户可以看到肯定发生的事情(而不是仅仅认为它被冻结了)。

我曾尝试使用 AsyncTask 执行此操作,但由于某种原因它不起作用。

这是我用来与服务器通信的类:

public class ServerConnection extends AsyncTask<String, Void, String> {

    private Context context;
    private ProgressDialog dialog;

    public ServerConnection(Context ctx){
        context = ctx;
        dialog = new ProgressDialog(context);
        dialog.setTitle("Waiting...");
        dialog.setMessage("...on the world to change.");
    }

    @Override
    protected void onPreExecute() {
        dialog.show();
    }

    @Override
    protected void onPostExecute(String unused) {
        dialog.dismiss();
    }

    protected String doInBackground(String... msg) {
        String response = null;
        try{
            /**
             *
             * Connects to server, sends message to server, waits for and receives a reponse from server
             *
             **/
        } catch(Exception e) {
            e.printStackTrace();
        }
        return response;
    }
}

这就是我使用它的方式(请注意,这些行将从 Activity 中的某些方法中调用):

ServerConnection conn = new ServerConnection(this);
String response = null;
try {
    response = conn.execute("ThisIsAMessageToTheServer").get();
} catch (Exception e){e.printStackTrace();}

当我单击一个按钮时,会执行一小段代码,几秒钟后,会收到来自服务器的响应。因此,就与服务器的通信和正确的响应而言,代码绝对可以正常工作。唯一的问题是 ProgressDialog 永远不会显示。

我浏览了谷歌,遇到的每个示例似乎都与此完全一样,所以我不确定是什么导致了问题。

【问题讨论】:

  • execute() 后删除 .get()
  • @RiteshGune 这绝对使对话工作!有什么方法可以在不使用 get() 的情况下将“响应”返回给 Activity?
  • 在 doInBackground 中获得的响应将被传递给你的 asynctask 的 onPostExecute()。在后期执行中,您可以使用接口使用回调方法将结果发送回您的活动。

标签: java android android-asynctask progressdialog


【解决方案1】:

我同意Golu's answer。除此之外, 我建议您仅在您的activity 中创建AsyncTask。这样你就可以只根据onPostExecute()得到的响应做所有UI相关的操作了。

但是,如果您希望继续使用现在的结构,请创建一个提供回调方法的接口。将您的活动设置为侦听器并在活动中实现该方法。

由于在 doInBackground 中获得的响应将被传递给您的 asynctask 的 onPostExecute()。在后期执行中,您可以使用接口的回调方法将结果发送回您的活动。

//创建界面如下:

public interface OnResponseReceivedListener{
      public void onResponseReceived(String response);
}

// 修改你的activity代码如下

public yourActivity extends Activity implements OnResponseReceivedListener {


    ServerConnection conn = new ServerConnection(this);
    conn.setResponseListener(this);

    public void onResponseReceived(String response){

     // TODO: do your UI operations based on the response.
    }
}

// 如下修改你的AsyncTask。

public class ServerConnection extends AsyncTask<String, Void, String> {

    OnResponseReceivedListener mListener;

    public void setResponseListener(OnResponseReceivedListener listener){
       mListener = listener;
    }

    // Your rest of the code
    @Override
    protected void onPostExecute(String unused) {
        mListener.onResponseReceived(unused);
        dialog.dismiss();
    }      

}

【讨论】:

  • 嗯,问题是在我得到响应字符串后,我需要根据响应的内容来处理它的其他内容。看来我可能不得不按照大多数人的建议去做,并在 Activity 中创建 AsyncTask。我试图避免这种情况的原因是,多个活动需要以完全相同的方式与服务器通信,并且我想避免重复太多代码。
  • 我设法按照您的建议重写(更多,重新组织)代码以使用回调。非常感谢您的帮助!
  • 欢迎您,很高兴为您提供帮助。
【解决方案2】:

你的问题是你的.get().get 是一个阻塞调用。这意味着您不会返回到事件循环(Android 框架中调用onCreateonPause、事件处理程序、onPostExecuteonPreExecute 等的代码),直到它返回。如果您不返回事件循环,您将永远不会进入绘图代码,也不会显示进度对话框。如果要显示对话框,则需要重新架构应用程序以实际异步使用任务。旁注——如果你在你的 UI 线程上像这样调用.get(),你的整个应用程序将冻结并且看起来很糟糕。这就是为什么他们一开始就强迫人们不要在 UI 线程上进行网络 IO。

【讨论】:

  • 谢谢,这很有意义。如果我不使用 get,那么如何从 doInBackground() 方法中获取字符串响应?
  • @BSnapZ 然后你在 onPostExcute 方法中得到字符串值。
【解决方案3】:

您正在使用 get 方法,这就是您的 ProgressDialog 对话框没有出现的原因,请删除 get 并重试。

因为get() 方法会阻塞你的主线程。

因此您需要覆盖onPostExecute() 以进行结果处理。

by use use get() in AsycTask, it will become SyancTask again.

编辑试试这个代码:

public class ServerConnection extends AsyncTask<String, Void, String> {

    private Context context;
    private ProgressDialog dialog;

    public ServerConnection(Context ctx){
        context = ctx;

    }

    @Override
    protected void onPreExecute() {

        dialog = new ProgressDialog(context);
        dialog.setTitle("Waiting...");
        dialog.setMessage("...on the world to change.");
        dialog.show();
    }

    @Override
    protected void onPostExecute(String unused) {

    }

    protected String doInBackground(String... msg) {
        String response = null;
        try{
            /**
             *
             * Connects to server, sends message to server, waits for and receives a reponse from server
             *
             **/
        } catch(Exception e) {
            e.printStackTrace();
        }
        return response;
    }

    public onPostExecute(String response) {

    dialog.dismiss(); // dismiss dialgo here.
    // preocess your response here.

    }

}

【讨论】:

  • 有什么办法可以让 onPostExecute() 对调用这个类的活动“响应”?
  • 为什么你不在你的 Activity 中创建 Asyantask 作为 Private 类,并在 onPostExecute() 中做所有的响应,因为你的活动和 asyantask 和不同的线程,所以你怎么能停止你的活动代码运行直到响应将来自服务器。
  • 因为我有几个不同的活动使用 ServerConnection 类,我不喜欢在几个活动之间复制/粘贴私有类的想法,因为这是非常糟糕的做法。
  • 好的没问题,你可以公开它并传递相关Activity的上下文,也传递相关的UI对象,记住在多个Activity之间使用公共线程也是不好的习惯。 Asyctask 也是一种线程,因为它在底层实现了 java 线程。
【解决方案4】:

使用下面的代码

 @Override
        protected void onPreExecute() {
            dialog = ProgressDialog.show(this, "Waiting...","...on the world to change.",       
true);

        }

【讨论】:

    猜你喜欢
    • 2022-12-10
    • 1970-01-01
    • 2018-03-10
    • 2020-01-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多