Android-将数据从AsyncTask传递到Activity

如何解决Android-将数据从AsyncTask传递到Activity

我正在尝试将字符串从AsyncTask传递回我的Activity。浏览其他类似问题(例如here)后,我决定使用接口侦听器。

接口:

package com.example.myapplication;

public interface GetListener {
    void passJSONGet(String s);
}

AsyncTask类:

package com.example.myapplication;

import android.content.Context;
import android.os.AsyncTask;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;


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

    Context context;
    private GetListener GetListener;
    public String jsonString;

    DataGetter(Context ctx,GetListener listener) {
        this.context = ctx;
        this.GetListener = listener;
    }

    @Override
    protected String doInBackground(String... params) {
        String ip = params[0];
        String scriptname = params[1];
        String db = params[2];
        String urladress = "http://" + ip + "/"+ scriptname +".php";

        try {
            URL url = new URL(urladress);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setDoInput(true);
            connection.setDoOutput(true);

            OutputStream os = connection.getOutputStream();
            OutputStreamWriter writer = new OutputStreamWriter(os,"UTF-8");

            String data = URLEncoder.encode("database","UTF-8") + "=" + URLEncoder.encode(db,"UTF-8");

            writer.write(data);
            writer.flush();
            writer.close();

            BufferedReader reader = new BufferedReader(new
                    InputStreamReader(connection.getInputStream()));
            StringBuilder sb = new StringBuilder();

            String line = null;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
                break;
            }
            return sb.toString();
        } catch (Exception e) {
            return e.getMessage();
        }
    }

    @Override
    protected void onPostExecute(String result) {
        GetListener.passJSONGet(result);
    }
}

我的活动:

import android.os.Bundle;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import org.json.JSONArray;
import org.json.JSONException;


public class WeatherDisplay extends AppCompatActivity implements GetListener {

    private JSONArray jsonArray;
    private String jsonString;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        
       // other code
      
        DataGetter dataGetter = new DataGetter(this,WeatherDisplay.this);
        dataGetter.execute(ip,"readLatestOutside","weather");
        Toast.makeText(this,this.jsonString,Toast.LENGTH_LONG).show();
        this.jsonArray = new JSONArray(this.jsonString);

       // furter code
}

    @Override
    public void passJSONGet(String jsonstring) {
        this.jsonString = jsonstring;
    }

JSON可以从服务器正确获取,并且可以在onPostExecute中正常看到,但是以后在WeatherDisplay中不可见(Toast显示为空,变量仍然是nullpointer)。

如何解决此问题?我没有经验,可能错过了一些琐碎的东西。

解决方法

我认为有关Android如何运行代码的一些解释可能会有所帮助。

因此,在后台,Android不断循环运行一些代码。该循环的一部分是检查消息队列,该队列基本上是任务交付的地方-它需要执行的代码。理想情况下,它将足够快地完成每个循环中所需的所有工作,使其每秒可以管理60个循环。如果有太多事情要做,那它就会开始放慢速度,并变得有些僵硬。

一些可能要执行的任务类似于正在创建的Activity,因此它可能希望系统运行其onCreate代码-每个Activity都执行一次。您可能已经注意到,它只会发生一次,而那正是您不断循环的地方,对吗?要在其中捕获执行,直到AsyncTask传递其结果?

问题在于您正在停止主循环的工作-在完成该任务之前,它无法继续执行任何操作,并且您故意阻止了它。通常这很糟糕,这就是为什么我们鼓励您不要在该主线程(运行主循环程序的线程)上进行慢速操作-它创建的工作时间太长,并使整个UI的响应速度变慢(UI处理)也是需要运行的任务)

因此,这通常是不好的,但是AsyncTask的实际工作方式是它们在另一个线程上运行(因此,它们不会阻塞主要线程,就像让另一个独立的人在处理东西一样)-但是它们在主线程上传递结果。他们将消息发布到主线程的消息队列中,告诉它运行onPostExecute代码。

但是,在处理队列中较早的任务之前,系统无法获取该消息。而且,如果它正在忙于运行一个无休止的循环,等待AsyncTask的结果,它将永远不会到达该消息,该变量将永远不会被更新,并且循环将永远不会看到它正在等待的更改。就像有人高举一条线,拒绝移动直到他们看到线下的某人试图传递的东西


这是一堆背景,但是重点是,您永远都不应阻塞这样的线程,除非它是您创建的特殊线程,这样您就可以了,并且不会干扰任何其他线程。将Android视为事件驱动的系统-您编写的代码应在发生某些事情时执行,例如创建活动(ònCreate)或按下按钮(onClick)或AsyncTask完成(onPostExecute)。所有这些方法都以“ on”开头是有原因的! “当事情发生时,执行此操作……”

因此,当您的任务完成时,它将运行onPostExecute,这是您处理接收结果的所有代码的位置。实际上,它不需要放在onPostExecute方法内-就像您已经将自己放在passJSONGet方法内以保持事物井然有序,但这是从onPostExecute调用的,这是事件触发代码运行。

因此,无论您需要如何处理结果,都可以从onPostExecute调用它。发生这种情况时,它将执行您已告诉它要做的事情。更新变量,举杯,用一些新数据填充布局中的视图!

,

将代码更改为:

  @Override
protected void onCreate(Bundle savedInstanceState) {
    
   // other code
  
    DataGetter dataGetter = new DataGetter(this,WeatherDisplay.this);
    dataGetter.execute(ip,"readLatestOutside","weather");
    

   // furter code
}
@Override
public void passJSONGet(String jsonstring) {
    this.jsonString = jsonstring;
    this.jsonArray = new JSONArray(this.jsonString);
    Toast.makeText(this,this.jsonString,Toast.LENGTH_LONG).show();
    
}

您的流程有误。所有UI工作都应在onPostExecute之后完成

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-