Android学习笔记 87.AsyncTask 和 AsyncTaskLoader

本文详细介绍了如何在Android中使用AsyncTask和AsyncTaskLoader处理后台任务,包括探索Google Books API、创建'谁写的?'应用示例,以及优化UI和迁移到AsyncTaskLoader。通过实例学习网络请求、JSON解析和最佳实践,提升开发效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Android学习笔记

Android 开发者基础知识 (Java) —— Google Developers 培训团队

第3单元 在后台运行

第7课 后台任务

87.AsyncTask 和 AsyncTaskLoader
你会做什么
  • 使用 Google APIs Explorer 了解 Books API。
  • 创建“谁写的?” 应用程序,它使用工作线程查询 Books API 并在 UI 中显示结果。
  • 修改“谁写的?” 应用程序使用 anAsyncTaskLoader而不是AsyncTask.
87.1 探索Google Books API
  1. 发送Books API请求

    地址:https://developers.google.com/apis-explorer/

    在这里插入图片描述

    在这里插入图片描述

  2. 分析Books API的响应

    JSON格式

    在这里插入图片描述

87.2 创建“谁写的?”应用程序
  1. 创建项目和用户界面UI

    在这里插入图片描述

    布局activity_main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="16dp"
        tools:context=".MainActivity">
    
        <TextView
            android:id="@+id/instructions"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:text="@string/instructions"
            android:textAppearance="@style/TextAppearance.AppCompat.Title"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    
    
        <EditText
            android:id="@+id/bookInput"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp"
            android:hint="@string/input_hint"
            android:inputType="text"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/instructions" />
    
    
        <Button
            android:id="@+id/searchButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp"
            android:onClick="searchBooks"
            android:text="@string/button_text"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/bookInput" />
    
        <TextView
            android:id="@+id/titleText"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="16dp"
            android:textAppearance="@style/TextAppearance.AppCompat.Headline"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/searchButton" />
    
        <TextView
            android:id="@+id/authorText"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginTop="8dp"
            android:textAppearance="@style/TextAppearance.AppCompat.Headline"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/titleText" />
    
    </androidx.constraintlayout.widget.ConstraintLayout>
    
  2. 获取用户输入

    package com.dingjiaxiong.whowroteit;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    import android.os.Bundle;
    import android.view.View;
    import android.widget.EditText;
    import android.widget.TextView;
    
    public class MainActivity extends AppCompatActivity {
    
        private EditText mBookInput;
        private TextView mTitleText;
        private TextView mAuthorText;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            mBookInput = (EditText) findViewById(R.id.bookInput);
            mTitleText = (TextView) findViewById(R.id.titleText);
            mAuthorText = (TextView) findViewById(R.id.authorText);
    
        }
    
        public void searchBooks(View view) {
    
            String queryString = mBookInput.getText().toString();
    
        }
    }
    
  3. 创建AsyncTask类

    FetchBook.java

    package com.dingjiaxiong.whowroteit;
    
    import android.os.AsyncTask;
    import android.widget.TextView;
    
    import java.lang.ref.WeakReference;
    
    public class FetchBook extends AsyncTask<String,Void,String> {
        private WeakReference<TextView> mTitleText;
        private WeakReference<TextView> mAuthorText;
    
        public FetchBook(TextView mTitleText, TextView mAuthorText) {
            this.mTitleText = new WeakReference<>(mTitleText);
            this.mAuthorText = new WeakReference<>(mAuthorText);
        }
    
        @Override
        protected String doInBackground(String... strings) {
            return null;
        }
    
        @Override
        protected void onPostExecute(String s) {
            super.onPostExecute(s);
        }
    }
    
  4. 创建Networkutils类并构建URL

  5. 发起请求

    package com.dingjiaxiong.whowroteit;
    
    import android.net.Uri;
    import android.util.Log;
    
    import java.io.BufferedReader;
    import java.io.IOException;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.net.HttpURLConnection;
    import java.net.URL;
    
    public class NetworkUtils {
    
        private static final String LOG_TAG = NetworkUtils.class.getSimpleName();
    
        // Constants for the various components of the Books API request.
        //
        // Base endpoint URL for the Books API.
        private static final String BOOK_BASE_URL =
                "https://www.googleapis.com/books/v1/volumes?";
        // Parameter for the search string.
        private static final String QUERY_PARAM = "q";
        // Parameter that limits search results.
        private static final String MAX_RESULTS = "maxResults";
        // Parameter to filter by print type.
        private static final String PRINT_TYPE = "printType";
    
    
        /**
         * Static method to make the actual query to the Books API.
         *
         * @param queryString the query string.
         * @return the JSON response string from the query.
         */
        static String getBookInfo(String queryString) {
    
            // Set up variables for the try block that need to be closed in the
            // finally block.
            HttpURLConnection urlConnection = null;
            BufferedReader reader = null;
            String bookJSONString = null;
    
            try {
                // Build the full query URI, limiting results to 10 items and
                // printed books.
                Uri builtURI = Uri.parse(BOOK_BASE_URL).buildUpon()
                        .appendQueryParameter(QUERY_PARAM, queryString)
                        .appendQueryParameter(MAX_RESULTS, "10")
                        .appendQueryParameter(PRINT_TYPE, "books")
                        .build();
    
                // Convert the URI to a URL,
                URL requestURL = new URL(builtURI.toString());
    
                // Open the network connection.
                urlConnection = (HttpURLConnection) requestURL.openConnection();
                urlConnection.setRequestMethod("GET");
                urlConnection.connect();
    
                // Get the InputStream.
                InputStream inputStream = urlConnection.getInputStream();
    
                // Create a buffered reader from that input stream.
                reader = new BufferedReader(new InputStreamReader(inputStream));
    
                // Use a StringBuilder to hold the incoming response.
                StringBuilder builder = new StringBuilder();
    
                String line;
                while ((line = reader.readLine()) != null) {
                    // Add the current line to the string.
                    builder.append(line);
    
                    // Since this is JSON, adding a newline isn't necessary (it won't
                    // affect parsing) but it does make debugging a *lot* easier
                    // if you print out the completed buffer for debugging.
                    builder.append("\n");
                }
    
                if (builder.length() == 0) {
                    // Stream was empty.  Exit without parsing.
                    return null;
                }
    
                bookJSONString = builder.toString();
    
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                // Close the connection and the buffered reader.
                if (urlConnection != null) {
                    urlConnection.disconnect();
                }
                if (reader != null) {
                    try {
                        reader.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
    
            // Write the final JSON response to the log
            Log.d(LOG_TAG, bookJSONString);
    
            return bookJSONString;
        }
    }
    
  6. 添加网络权限

    在这里插入图片描述

  7. 解析JSON字符串

    MainActivity.java

    package com.dingjiaxiong.whowroteit;
    
    import androidx.appcompat.app.AppCompatActivity;
    
    import android.content.Context;
    import android.net.ConnectivityManager;
    import android.net.NetworkInfo;
    import android.os.Bundle;
    import android.view.View;
    import android.view.inputmethod.InputMethodManager;
    import android.widget.EditText;
    import android.widget.TextView;
    
    public class MainActivity extends AppCompatActivity {
    
        private EditText mBookInput;
        private TextView mTitleText;
        private TextView mAuthorText;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            mBookInput = (EditText) findViewById(R.id.bookInput);
            mTitleText = (TextView) findViewById(R.id.titleText);
            mAuthorText = (TextView) findViewById(R.id.authorText);
    
        }
    
        public void searchBooks(View view) {
            // Get the search string from the input field.
            String queryString = mBookInput.getText().toString();
    
            // Hide the keyboard when the button is pushed.
            InputMethodManager inputManager = (InputMethodManager)
                    getSystemService(Context.INPUT_METHOD_SERVICE);
            if (inputManager != null) {
                inputManager.hideSoftInputFromWindow(view.getWindowToken(),
                        InputMethodManager.HIDE_NOT_ALWAYS);
            }
    
            // Check the status of the network connection.
            ConnectivityManager connMgr = (ConnectivityManager)
                    getSystemService(Context.CONNECTIVITY_SERVICE);
            NetworkInfo networkInfo = null;
            if (connMgr != null) {
                networkInfo = connMgr.getActiveNetworkInfo();
            }
    
            // If the network is available, connected, and the search field
            // is not empty, start a FetchBook AsyncTask.
            if (networkInfo != null && networkInfo.isConnected()
                    && queryString.length() != 0) {
                new FetchBook(mTitleText, mAuthorText).execute(queryString);
                mAuthorText.setText("");
                mTitleText.setText(R.string.loading);
            }
            // Otherwise update the TextView to tell the user there is no
            // connection, or no search term.
            else {
                if (queryString.length() == 0) {
                    mAuthorText.setText("");
                    mTitleText.setText(R.string.no_search_term);
                } else {
                    mAuthorText.setText("");
                    mTitleText.setText(R.string.no_network);
                }
            }
        }
    }
    

    运行程序

    在这里插入图片描述

    【当然手机用的另一个网,肯定是获取不到数据的…】

87.3 实施UI最佳实践
  1. 隐藏键盘并更新TextView

    InputMethodManager inputManager = (InputMethodManager)
       getSystemService(Context.INPUT_METHOD_SERVICE);
    
    if (inputManager != null ) {
       inputManager.hideSoftInputFromWindow(view.getWindowToken(),
               InputMethodManager.HIDE_NOT_ALWAYS);
    }
    
    new FetchBook(mTitleText, mAuthorText).execute(queryString);
    mAuthorText.setText("");
    mTitleText.setText(R.string.loading)
    
  2. 管理网络状态和空搜索字段的示例

    ConnectivityManager connMgr = (ConnectivityManager)
               getSystemService(Context.CONNECTIVITY_SERVICE);
    NetworkInfo networkInfo = null;
    if (connMgr != null) {
       networkInfo = connMgr.getActiveNetworkInfo();
    }
    
87.4 迁移到AsyncTaskLoader

项目地址:https://github.com/google-developer-training/android-fundamentals-apps-v2/tree/master/WhoWroteItLoader

  1. 创建一个 AsyncTaskLoader类
  2. 实现方法
  3. 修改MainActivity
  4. 实现加载器回调
87.5 小结
  • 连接到网络的任务不应在 UI 线程上执行。如果您尝试在 UI 线程上进行网络连接或文件访问,Android 运行时通常会引发异常。
  • 使用图书搜索 API 以编程方式访问 Google 图书。对 Google 图书的 API 请求采用 URL 的形式,响应是 JSON 字符串。
  • 使用 Google APIs Explorer 以交互方式探索 Google APIs。
  • 用于getText()EditText视图中检索文本。要将文本转换为简单字符串,请使用toString().
  • Uri.buildUpon()方法返回URI.Builder可用于构造 URI 字符串的 a。
  • 要连接到互联网,您必须在 Android 清单文件中配置网络权限:
<uses-permission android:name="android.permission.INTERNET" />

该类 AsyncTask允许您在后台而不是在 UI 线程上运行任务:

  • 要使用AsyncTask,您必须对其进行子类化。子类覆盖该doInBackground(Params...)方法。通常子类也会覆盖该onPostExecute(Result)方法。
  • 要启动AsyncTask,请使用execute()
  • 如果正在控制的活动停止(例如由于设备配置更改),AsyncTask则无法更新 UI 。AsyncTask

执行时AsyncTask,它经过四个步骤:

  1. onPreExecute()在执行任务之前在 UI 线程上运行。此步骤通常用于设置任务,例如通过在 UI 中显示进度条。
  2. doInBackground(Params...)完成后立即在后台线程上运行onPreExecute()。此步骤执行可能需要很长时间的后台计算。
  3. onProgressUpdate(Progress...)调用后在 UI 线程上运行publishProgress(Progress...)
  4. onPostExecute(Result)后台计算完成后在 UI 线程上运行。计算结果传递给onPostExecute().

AsyncTaskLoader是 loader 的等价物AsyncTask

  • AsyncTaskLoader提供该loadInBackground()方法,该方法在单独的线程上运行。
  • 的结果通过回调loadInBackground()的方式传递给 UI 线程。onLoadFinished() LoaderManager
  • 要创建和解析 JSON 字符串,请使用内置 Java JSON 类JSONObjectJSONArray.
  • AnAsyncTaskLoader使用AsyncTask辅助类在后台完成工作,脱离主线程。
  • AsyncTaskLoader实例由LoaderManager.
  • 允许LoaderManager您使用.Activity``getSupportLoaderManager().initLoader()

【这种实现方式有点太那个了,现在应该还是OKhttp吧】

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

祝我天天开心,平安健康

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值