`
XiangdongLee
  • 浏览: 94306 次
  • 性别: Icon_minigender_1
  • 来自: 长沙
社区版块
存档分类
最新评论

【攻克Android(26)】Async Task 异步任务

阅读更多
本文围绕以下两个部分展开:

一、Async Task 异步任务
案例一:通过Async Task进行线程间通信(非 UI进程更新 UI、处理耗时任务)





一、Async Task 异步任务

        1. Async Task 异步任务

        AsyncTask是在Android SDK 1.5之后推出的一个方便编写后台线程与UI线程交互的辅助类。AsyncTask的内部实现是一个线程池,每个后台任务会提交到线程池中的线程执行,然后使用Thread+Handler的方式调用回调函数。

        2. 使用方法

    /**
     * 自定义异步任务类 - 继承自 AsyncTask 类
     */

    /*
        三个模板参数:
        (传入参数类型, 进度类型, 返回值类型)
        Params:传递给后台任务的参数类型。
        Progress:后台计算执行过程中,进步单位(progress units)的类型。
                (就是后台程序已经执行了百分之几了。)
        Result:后台执行返回的结果的类型。

        AsyncTask并不总是需要使用上面的全部3种类型。
        标识不使用的类型,只需要使用Void类型即可。
     */
    private class XxxTask extends AsyncTask<Params, Progress, Result> {

        /**
         * 1. 准备运行(可选)
         * <p/>
         * 该回调函数在任务被执行之后立即由UI线程调用。
         *
         * 这个步骤通常用来建立任务,在用户接口(UI)上显示进度条。
         */
        @Override
        protected void onPreExecute() {
            super.onPreExecute();
        }

        /**
         * 2. 正在后台运行(必须重写)
         *
         * 该回调函数由后台线程在onPreExecute()方法执行结束后立即调用。
         * <p/>
         * 通常在这里执行耗时的后台计算。
         * 计算的结果必须由该函数返回,并被传递到 onPostExecute()中。
         * <p/>
         * 在该函数内也可以使用 publishProgress(Progress...)来发布一个或多个进度单位。
         * 这些值将会在 onProgressUpdate(Progress...)中被发布到 UI线程
         *
         * @param params
         * @return
         */
        @Override
        protected String doInBackground(String... params) {

            return params[0];
        }

        /**
         * 3. 完成后台任务(可选)
         *
         * 当后台计算结束后调用。
         *
         * 后台计算的结果会被作为参数传递给这一函数。
         *
         * @param s 后台计算的结果
         */
        @Override
        protected void onPostExecute(String s) {
            super.onPostExecute(s);
        }

        /**
         * 4. 进度更新 (可选)
         * <p/>
         * 该函数由 UI线程在 publishProgress(Progress...)方法调用完后被调用。
         *
         * 一般用于动态地显示一个进度条。
         *
         * @param values
         */
        @Override
        protected void onProgressUpdate(Integer... values) {
            super.onProgressUpdate(values);
        }

        /**
         * 5. 取消任务(可选)
         * <p/>
         * 在调用AsyncTask的cancel()方法时调用
         */
        @Override
        protected void onCancelled() {
            super.onCancelled();
        }
    }



案例一:通过Async Task进行线程间通信(非 UI进程更新 UI、处理耗时任务)

        效果如下:

        进入主界面后,显示一个按钮:



        当点击该按钮的时候,跳到另一个界面:异步任务界面。



        要实现左上角“异步任务”左侧的回退按钮,只需要在功能清单文件中添加如下一句话:

android:parentActivityName=".MainActivity"


        添加到该Activity中:

<activity
            android:name=".AsyncTaskActivity"
            android:label="@string/title_activity_async_task"
            android:parentActivityName=".MainActivity" />


        当点击START按钮的时候,条形进度条和文本进度,都会以0.2秒增加1的速度增长,一直到100。





        当进度达到100的时候,会弹出Toast提示:“结果:Google”。




        (1)strings.xml

<resources>
    <string name="app_name">Async Task</string>

    <string name="hello_world">Hello world!</string>
    <string name="action_settings">Settings</string>

    <string name="btn_start">Start</string>
    <string name="btn_async_task">Async Task 异步任务</string>
    <string name="title_activity_async_task">异步任务</string>

</resources>


        (2)activity_main.xml。主活动布局。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity">

    <Button
        android:id="@+id/btnAsyncTask"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="onClick"
        android:text="@string/btn_async_task" />

</RelativeLayout>


        (3)新建一个Activity: AsyncTaskActivity。并在功能清单中设置回退按钮。

        (4)MainActivity。主活动。按钮的点击事件。

public void onClick(View view) {
        startActivity(new Intent(this, AsyncTaskActivity.class));
    }


        (5)activity_async_task.xml。异步任务活动布局。包括一个START按钮,一个条形进度条和一个文本(文本进度)。

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context="com.android.handlerthread.AsyncTaskActivity">

    <Button
        android:id="@+id/btnStart"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="onClick"
        android:text="@string/btn_start" />

    <ProgressBar
        android:id="@+id/progressBar"
        style="?android:progressBarStyleHorizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@id/btnStart"
        android:visibility="gone" />

    <TextView
        android:id="@+id/tvScale"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/progressBar"
        android:visibility="gone" />

</RelativeLayout>

    <!-- 设置 ProgressBar 和 TextView 不可见,
 当点击 START 按钮的时候,才可见。-->


        (6)AsyncTaskActivity。通过Async Task进行线程间通信(非 UI进程更新 UI、处理耗时任务)

package com.android.handlerthread;

import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;


public class AsyncTaskActivity extends Activity {
    // 1.1 要用到主界面中的 ProgressBar 和 TextView,因此要先声明并初始化。
    // 声明两个控件(RatingBar 和 TextView)
    private ProgressBar progressBar;
    private TextView tvScale;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_async_task);

        // 1.2 初始化两个控件(ProgressBar 和 TextView)
        progressBar = (ProgressBar) findViewById(R.id.progressBar);
        tvScale = (TextView) findViewById(R.id.tvScale);
    }

    public void onClick(View view) {
        // 2. 设置控件可见,并启动任务
        progressBar.setVisibility(View.VISIBLE);
        tvScale.setVisibility(View.VISIBLE);
        UpdateTask task = new UpdateTask();
        // 这里输入的参数会传输给 doInBackground()方法
        task.execute("Google");
    }

    /**
     * 3. 自定义异步任务类
     */
    private class UpdateTask extends AsyncTask<String, Integer, String> {

        /**
         * 3.1 准备运行(可选)
         */
        @Override
        protected void onPreExecute() {
            // 设置最大进度值:100
            progressBar.setMax(100);
        }

        /**
         * 3.2 正在后台运行(必须重写)
         *
         * @param params
         * @return
         */
        @Override
        protected String doInBackground(String... params) {
            for (int i = 0; i < 100; i++) {
                // 5.2.1 设置进度值
                // 发布一个或多个进度单位(units of progress)。
                // 这些值将会在 onProgressUpdate(Progress...)中被发布到 UI线程
                this.publishProgress(i + 1);
                try {
                    // 5.2.2 模拟具体完成的耗时任务 --- 比如:访问网络。
                    // 200毫秒,进度增 1
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if (isCancelled()) {
                    return "Cancelled";
                }
            }
            return params[0];
        }

        /**
         * 3.4 完成后台任务(可选)
         *
         * @param result 后台计算的结果
         */
        @Override
        protected void onPostExecute(String result) {
            // 完成后台任务后,给一个 Toast 提示
            Toast.makeText(getApplicationContext(), "结果:" + result,
                    Toast.LENGTH_SHORT).show();
        }

        /**
         * 3.3 进度更新 (可选)
         *
         * @param values
         */
        @Override
        protected void onProgressUpdate(Integer... values) {
            // 因为只传入一个值:"Google",因此对应的进度更新的时候,也是 values[0]
            progressBar.setProgress(values[0]);
            tvScale.setText(String.format("%d / %d", values[0], 100));
        }

        /**
         * 取消任务(可选)
         */
        @Override
        protected void onCancelled() {
            super.onCancelled();
        }
    }

    // -----------------------------------------------------------
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.menu_async_task, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {
            return true;
        }

        return super.onOptionsItemSelected(item);
    }
}
  • 大小: 20.8 KB
  • 大小: 13.9 KB
  • 大小: 16.2 KB
  • 大小: 12.4 KB
  • 大小: 18.4 KB
分享到:
评论

相关推荐

    C# Exercise Answers C# Exercise Answers

    9. **异步编程**:学习async和await关键字,理解Task类,以及如何编写异步方法来提高应用程序的性能。 10. **文件和流操作**:了解如何读写文件,使用FileStream、StreamReader和StreamWriter类,以及XML和JSON序列...

    C#入门经典例题代码

    异步编程是C# 5.0引入的重要特性,基于async/await关键字,可以使程序在等待IO操作完成时释放CPU资源。 数据库交互是许多应用程序的核心。C#可以通过ADO.NET库连接和操作各种数据库,如SQL Server、MySQL等。Entity...

    学习C#入门必看的实例程序.rar

    9. **异步编程**:C#的async/await关键字使得异步编程变得更为简单。通过实例,你可以了解如何处理耗时操作,避免阻塞UI线程。 10. **多线程与并发**:C#提供了对多线程和并发的支持,如Thread类、Task类、Mutex、...

    spring-ai-bedrock-converse-1.0.0-M7.jar中文文档.zip

    # 【spring-ai-bedrock-converse-1.0.0-M7.jar中文文档.zip】 中包含: 中文文档:【spring-ai-bedrock-converse-1.0.0-M7-javadoc-API文档-中文(简体)版.zip】 jar包下载地址:【spring-ai-bedrock-converse-1.0.0-M7.jar下载地址(官方地址+国内镜像地址).txt】 Maven依赖:【spring-ai-bedrock-converse-1.0.0-M7.jar Maven依赖信息(可用于项目pom.xml).txt】 Gradle依赖:【spring-ai-bedrock-converse-1.0.0-M7.jar Gradle依赖信息(可用于项目build.gradle).txt】 源代码下载地址:【spring-ai-bedrock-converse-1.0.0-M7-sources.jar下载地址(官方地址+国内镜像地址).txt】 # 本文件关键字: spring-ai-bedrock-converse-1.0.0-M7.jar中文文档.zip,java,spring-ai-bedrock-converse-1.0.0-M7.jar,org.springframework.ai,spring-ai-bedrock-converse,1.0.0-M7,org.springframework.ai.bedrock.converse,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,springframework,spring,ai,bedrock,converse,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压 【spring-ai-bedrock-converse-1

    房地产 -可视化管理课件.ppt

    房地产 -可视化管理课件.ppt

    tokenizers-0.18.0.jar中文-英文对照文档.zip

    # 【tokenizers-***.jar***文档.zip】 中包含: ***文档:【tokenizers-***-javadoc-API文档-中文(简体)版.zip】 jar包下载地址:【tokenizers-***.jar下载地址(官方地址+国内镜像地址).txt】 Maven依赖:【tokenizers-***.jar Maven依赖信息(可用于项目pom.xml).txt】 Gradle依赖:【tokenizers-***.jar Gradle依赖信息(可用于项目build.gradle).txt】 源代码下载地址:【tokenizers-***-sources.jar下载地址(官方地址+国内镜像地址).txt】 # 本文件关键字: tokenizers-***.jar***文档.zip,java,tokenizers-***.jar,ai.djl.huggingface,tokenizers,***,ai.djl.engine.rust,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,djl,huggingface,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压 【tokenizers-***.jar***文档.zip】,再解压其中的 【tokenizers-***-javadoc-API文档-中文(简体)版.zip】,双击 【index.html】 文件,即可用浏览器打开、进行查看。 # 特殊说明: ·本文档为人性化翻译,精心制作,请放心使用。 ·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; ·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 # 温馨提示: (1)为了防止解压后路径太长导致浏览器无法打开,推荐在解压时选择“解压到当前文件夹”(放心,自带文件夹,文件不会散落一地); (2)有时,一套Java组件会有多个jar,所以在下载前,请仔细阅读本篇描述,以确保这就是你需要的文件; # Maven依赖: ``` <dependency> <groupId>ai.djl.huggingface</groupId> <artifactId>tokenizers</artifactId> <version>***</version> </dependency> ``` # Gradle依赖: ``` Gradle: implementation group: 'ai.djl.huggingface', name: 'tokenizers', version: '***' Gradle (Short): implementation 'ai.djl.huggingface:tokenizers:***' Gradle (Kotlin): implementation("ai.djl.huggingface:tokenizers:***") ``` # 含有的 Java package(包): ``` ai.djl.engine.rust ai.djl.engine.rust.zoo ai.djl.huggingface.tokenizers ai.djl.huggingface.tokenizers.jni ai.djl.huggingface.translator ai.djl.huggingface.zoo ``` # 含有的 Java class(类): ``` ai.djl.engine.rust.RsEngine ai.djl.engine.rust.RsEngineProvider ai.djl.engine.rust.RsModel ai.djl.engine.rust.RsNDArray ai.djl.engine.rust.RsNDArrayEx ai.djl.engine.rust.RsNDArrayIndexer ai.djl.engine.rust.RsNDManager ai.djl.engine.rust.RsSymbolBlock ai.djl.engine.rust.RustLibrary ai.djl.engine.rust.zoo.RsModelZoo ai.djl.engine.rust.zoo.RsZooProvider ai.djl.huggingface.tokenizers.Encoding ai.djl.huggingface.tokenizers.HuggingFaceTokenizer ai.djl.huggingface.tokenizers.HuggingFaceTokenizer.Builder ai.djl.hu

    基于MATLAB的BP神经网络预测模型构建与应用

    内容概要:本文详细介绍了如何使用MATLAB构建和应用BP神经网络预测模型。首先,通过读取Excel数据并进行预处理,如归一化处理,确保数据的一致性和有效性。接着,配置网络结构,选择合适的训练算法(如SCG),设置训练参数(如最大迭代次数、目标误差等)。然后,进行模型训练,并通过可视化窗口实时监控训练过程。训练完成后,利用测试集评估模型性能,计算均方误差(MSE)和相关系数(R²),并通过图表展示预测效果。最后,将训练好的模型保存以便后续调用,并提供了一个简单的预测函数,确保新数据能够正确地进行归一化和预测。 适合人群:具有一定MATLAB基础,从事数据分析、机器学习领域的研究人员和技术人员。 使用场景及目标:适用于需要对多维数据进行预测的任务,如电力负荷预测、金融数据分析等。主要目标是帮助用户快速搭建一个可用的BP神经网络预测系统,提高预测准确性。 其他说明:文中提供了完整的代码框架和详细的注释,便于理解和修改。同时,强调了数据预处理的重要性以及一些常见的注意事项,如数据量的要求、归一化的必要性等。

    tokenizers-0.22.1.jar中文-英文对照文档.zip

    # 【tokenizers-***.jar***文档.zip】 中包含: ***文档:【tokenizers-***-javadoc-API文档-中文(简体)版.zip】 jar包下载地址:【tokenizers-***.jar下载地址(官方地址+国内镜像地址).txt】 Maven依赖:【tokenizers-***.jar Maven依赖信息(可用于项目pom.xml).txt】 Gradle依赖:【tokenizers-***.jar Gradle依赖信息(可用于项目build.gradle).txt】 源代码下载地址:【tokenizers-***-sources.jar下载地址(官方地址+国内镜像地址).txt】 # 本文件关键字: tokenizers-***.jar***文档.zip,java,tokenizers-***.jar,ai.djl.huggingface,tokenizers,***,ai.djl.engine.rust,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,djl,huggingface,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压 【tokenizers-***.jar***文档.zip】,再解压其中的 【tokenizers-***-javadoc-API文档-中文(简体)版.zip】,双击 【index.html】 文件,即可用浏览器打开、进行查看。 # 特殊说明: ·本文档为人性化翻译,精心制作,请放心使用。 ·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; ·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 # 温馨提示: (1)为了防止解压后路径太长导致浏览器无法打开,推荐在解压时选择“解压到当前文件夹”(放心,自带文件夹,文件不会散落一地); (2)有时,一套Java组件会有多个jar,所以在下载前,请仔细阅读本篇描述,以确保这就是你需要的文件; # Maven依赖: ``` <dependency> <groupId>ai.djl.huggingface</groupId> <artifactId>tokenizers</artifactId> <version>***</version> </dependency> ``` # Gradle依赖: ``` Gradle: implementation group: 'ai.djl.huggingface', name: 'tokenizers', version: '***' Gradle (Short): implementation 'ai.djl.huggingface:tokenizers:***' Gradle (Kotlin): implementation("ai.djl.huggingface:tokenizers:***") ``` # 含有的 Java package(包): ``` ai.djl.engine.rust ai.djl.engine.rust.zoo ai.djl.huggingface.tokenizers ai.djl.huggingface.tokenizers.jni ai.djl.huggingface.translator ai.djl.huggingface.zoo ``` # 含有的 Java class(类): ``` ai.djl.engine.rust.RsEngine ai.djl.engine.rust.RsEngineProvider ai.djl.engine.rust.RsModel ai.djl.engine.rust.RsNDArray ai.djl.engine.rust.RsNDArrayEx ai.djl.engine.rust.RsNDArrayIndexer ai.djl.engine.rust.RsNDManager ai.djl.engine.rust.RsSymbolBlock ai.djl.engine.rust.RustLibrary ai.djl.engine.rust.zoo.RsModelZoo ai.djl.engine.rust.zoo.RsZooProvider ai.djl.huggingface.tokenizers.Encoding ai.djl.huggingface.tokenizers.HuggingFaceTokenizer ai.djl.huggingface.tokenizers.HuggingFaceTokenizer.Builder ai.djl.hu

    基于蒙特卡洛算法的电动汽车对IEEE 33节点电网影响的研究及应用场景分析

    内容概要:本文探讨了电动汽车(EV)对IEEE 33节点电网的影响,特别是汽车负荷预测与节点潮流网损、压损计算。通过蒙特卡洛算法模拟电动汽车负荷的时空特性,研究了四种不同场景下电动汽车接入电网的影响。具体包括:负荷接入前后的网损与电压计算、不同节点接入时的变化、不同时段充电的影响以及不同负荷大小对电网的影响。通过这些分析,揭示了电动汽车充电行为对电网的具体影响机制,为未来的电网规划和优化提供了重要参考。 适合人群:从事电力系统研究的专业人士、电网规划工程师、电动汽车行业从业者、能源政策制定者。 使用场景及目标:①评估电动汽车大规模接入对现有电网基础设施的压力;②优化电动汽车充电设施的布局和运营策略;③为相关政策和技术标准的制定提供科学依据。 其他说明:文中提供的Python代码片段用于辅助理解和验证理论分析,实际应用中需要更复杂的模型和详细的电网参数。

    房地产 -【万科经典-第五园】第五园产品推介会.ppt

    房地产 -【万科经典-第五园】第五园产品推介会.ppt

    稳压器件.SchLib

    稳压器件.SchLib

    1.jpg

    1

    模拟符号.SCHLIB

    模拟符号.SCHLIB

    基于Simulink的三相电压型逆变器SPWM与电压单闭环控制仿真

    内容概要:本文详细介绍了如何在Simulink中构建并仿真三相电压型逆变器的SPWM调制和电压单闭环控制系统。首先,搭建了由六个IGBT组成的三相全桥逆变电路,并设置了LC滤波器和1000V直流电源。接着,利用PWM Generator模块生成SPWM波形,设置载波频率为2kHz,调制波为50Hz工频正弦波。为了实现精确的电压控制,采用了abc/dq变换将三相电压信号转换到旋转坐标系,并通过锁相环(PLL)进行同步角度跟踪。电压闭环控制使用了带有抗饱和处理的PI调节器,确保输出电压稳定。此外,文中还讨论了标幺值处理方法及其优势,以及如何通过FFT分析验证输出波形的质量。 适用人群:电力电子工程师、自动化控制专业学生、从事逆变器研究的技术人员。 使用场景及目标:适用于希望深入了解三相电压型逆变器控制原理和技术实现的研究人员和工程师。主要目标是掌握SPWM调制技术和电压单闭环控制的设计与调试方法,提高系统的稳定性和效率。 其他说明:文中提供了详细的建模步骤和参数设置指南,帮助读者快速上手并在实践中不断优化模型性能。同时,强调了一些常见的调试技巧和注意事项,如载波频率的选择、积分器防饱和处理等。

    【蓝桥杯EDA】客观题解析:第十三届立创EDA出品省赛模拟题一.pdf

    【蓝桥杯EDA】客观题解析

    房地产 -物业 苏州设备房管理标准.ppt

    房地产 -物业 苏州设备房管理标准.ppt

    3.png

    3

    房地产 -2024H1房地产市场总结与展望(新房篇).docx

    房地产 -2024H1房地产市场总结与展望(新房篇).docx

    LabVIEW与PLC基于TCP协议的自动化数据交互解决方案

    内容概要:本文详细介绍了利用LabVIEW与PLC进行自动化数据交互的技术方案,涵盖参数管理、TCP通信、串口扫描、数据转移等方面。首先,通过配置文件(INI)实现参数的自动加载与保存,确保参数修改不影响程序运行。其次,在TCP通信方面采用异步模式和心跳包设计,增强通信稳定性,并加入CRC16校验避免数据丢失。对于串口扫描,则通过VISA配置实现状态触发,确保进出站检测的准确性。最后,针对不同类型的数据转移提出具体方法,如TDMS文件存储策略,确保高效可靠的数据处理。 适合人群:从事工业自动化领域的工程师和技术人员,尤其是熟悉LabVIEW和PLC编程的从业者。 使用场景及目标:适用于需要将LabVIEW作为上位机与PLC进行数据交互的工业生产线环境,旨在提高系统的自动化程度、稳定性和易维护性。 其他说明:文中提供了多个实用代码片段和注意事项,帮助读者更好地理解和应用相关技术。

    d65689da7ed20e21882a634f8f5ce6c9_faad2735d293907fb32f7c5837f7302a.png

    d65689da7ed20e21882a634f8f5ce6c9_faad2735d293907fb32f7c5837f7302a

Global site tag (gtag.js) - Google Analytics