Android通过HTTP请求获取和解析网页内容

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:本文介绍了在Android开发中如何使用HTTP请求来获取网页内容,并详细解释了利用Jsoup库解析HTML的过程。通过网络权限申请、HTTP GET请求的创建、HTML文档的解析以及在ListView中展示解析结果的步骤,本教程引导读者实现一个完整的网络内容获取和显示流程。教程还涵盖了自定义适配器的创建和事件处理,为开发功能丰富的Android网络应用提供指导。 Android获取网页内容(HTTP)

1. Android网络访问基础

随着移动互联网的发展,Android 应用对于网络功能的需求日益增长。本章将对 Android 平台的网络访问进行基础性的介绍,包括网络访问的概念、适用场景以及开发前的准备工作。

1.1 网络访问的基本概念

在 Android 中进行网络访问,通常涉及到客户端与服务器端的数据交互。开发者需要了解常见的网络协议(如HTTP、HTTPS)、数据传输格式(如JSON、XML),以及网络访问过程中可能遇到的安全性问题。

1.2 开发前的准备工作

在开发 Android 应用时,为了能够访问网络,需要在 AndroidManifest.xml 文件中声明网络权限:

<uses-permission android:name="android.permission.INTERNET" />

此外,还需要根据实际开发需求选择合适的网络访问API,并配置相关的网络环境和依赖库。

1.3 选择合适的网络访问方式

Android 提供了多种网络访问方式,包括 HttpClient、HttpURLConnection、Volley、Retrofit 等。开发者应根据应用的需求以及复杂度来选择最适合的网络访问方式。例如,对于简单的网络请求,HttpURLConnection 是一个不错的选择,而如果需要处理更复杂的网络请求,可能需要使用功能更丰富的第三方库如Retrofit。

在下一章,我们将深入了解 HttpURLConnection 的使用与实践,并探讨如何在 Android 中进行基本和高级的网络请求操作。

2. HttpURLConnection的使用与实践

2.1 HttpURLConnection基础

2.1.1 HttpURLConnection简介

在Android应用开发中,网络通信是常见的需求之一。HttpURLConnection是Android原生提供的一个用于处理HTTP协议网络通信的类,它能够完成发送HTTP请求和接收HTTP响应的功能。虽然现代Android应用开发中更多的是使用OkHttp等第三方库来处理网络请求,但在一些轻量级的应用或学习过程中,HttpURLConnection以其简单和轻量级,仍然是一个不错的选择。

2.1.2 HttpURLConnection的基本使用方法

HttpURLConnection的基本使用方法包括创建连接、设置请求方法、发送请求和读取响应等步骤。以下是一个简单的示例,展示了如何使用HttpURLConnection发送GET请求:

URL url = new URL("http://www.example.com");
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
try {
    // 设置请求方法为GET
    urlConnection.setRequestMethod("GET");
    // 发送请求并获取响应码
    int responseCode = urlConnection.getResponseCode();
    // 读取响应数据
    BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
    String inputLine;
    StringBuilder response = new StringBuilder();

    while ((inputLine = in.readLine()) != null) {
        response.append(inputLine);
    }
    in.close();

    // 输出响应内容
    System.out.println(response.toString());
} finally {
    urlConnection.disconnect();
}

上述代码中,首先创建了一个URL对象,并通过它来获取HttpURLConnection实例。然后,设置请求的方法为GET,并发送请求。通过连接的getInputStream()方法读取服务器的响应数据。最后,在finally块中确保连接被关闭,这是一个良好的编程习惯,以避免潜在的资源泄露。

2.2 HttpURLConnection高级用法

2.2.1 与服务器的交互方式

HttpURLConnection支持多种与服务器交互的方式,包括常见的GET、POST、PUT、DELETE等HTTP方法。每种方法都有不同的用途,例如GET通常用于获取资源,而POST用于提交数据。

在使用POST方法时,可以通过设置请求属性来传递数据,如设置请求头的"Content-Type"来指定数据格式,然后通过OutputStream来发送实际数据。下面是一个使用POST方法发送JSON数据的示例:

// 设置请求方法为POST
urlConnection.setRequestMethod("POST");
// 设置内容类型为JSON
urlConnection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
// 发送POST请求必须设置如下两行
urlConnection.setDoOutput(true);
DataOutputStream wr = new DataOutputStream(urlConnection.getOutputStream());
wr.writeBytes("这里是你要发送的JSON数据");
wr.flush();
wr.close();
2.2.2 网络请求的同步与异步处理

网络请求的同步与异步处理在Android应用开发中尤为关键。同步请求会阻塞主线程,直到请求完成,这通常会导致应用界面无响应(ANR),因此在实际应用中应尽量避免使用同步请求。异步请求则不会阻塞主线程,可以提升用户体验。

Android的AsyncTask是一个方便的类,用于在后台线程执行任务并处理结果。但自Android 11起,AsyncTask已被弃用,开发者应考虑使用其他并发解决方案,如Kotlin的协程等。不过,为了说明,以下是一个使用AsyncTask进行异步网络请求的示例:

private class DownloadWebpageTask extends AsyncTask<String, Void, String> {

    @Override
    protected String doInBackground(String... urls) {
        String result = "";
        URL url;
        HttpURLConnection urlConnection = null;
        try {
            url = new URL(urls[0]);
            urlConnection = (HttpURLConnection) url.openConnection();
            InputStream in = new BufferedInputStream(urlConnection.getInputStream());
            BufferedReader reader = new BufferedReader(new InputStreamReader(in));
            StringBuilder stringBuilder = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                stringBuilder.append(line).append("\n");
            }
            if (stringBuilder.length() == 0) {
                stringBuilder.append("No data");
            }
            result = stringBuilder.toString();
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (urlConnection != null) {
                urlConnection.disconnect();
            }
        }
        return result;
    }

    @Override
    protected void onPostExecute(String result) {
        TextView textView = findViewById(R.id.webpage);
        textView.setText(result);
    }
}

// 使用AsyncTask
new DownloadWebpageTask().execute("http://www.example.com");
2.2.3 网络请求的异常处理和重试机制

在进行网络请求时,异常处理是不可或缺的一部分。有效的异常处理可以避免应用崩溃,并提供更友好的用户体验。常见的网络请求异常包括网络连接问题、服务器错误响应等。处理网络异常的关键在于捕获并识别不同的异常类型,然后给出合适的处理措施。

重试机制是在网络请求失败时重新尝试请求的一种策略。实现重试机制通常需要结合定时器(如Handler)和异常处理机制。以下是一个简单的重试机制实现示例:

// 使用递归实现简单的重试逻辑
private static final int MAX_RETRIES = 3;

private void sendRequestWithRetry(final String url) {
    sendRequest(url, 0);
}

private void sendRequest(final String url, final int retryCount) {
    try {
        // 发起网络请求的代码
    } catch (Exception e) {
        if (retryCount < MAX_RETRIES) {
            // 延迟重试逻辑,可以使用Handler或Timer进行延迟
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    sendRequest(url, retryCount + 1);
                }
            }, RETRY_DELAY); // RETRY_DELAY为延迟时间,单位毫秒
        } else {
            // 最大重试次数已到,进行相应处理
        }
    }
}

在上述示例中,我们定义了一个递归方法sendRequestWithRetry来发起请求,并包含一个重试次数参数retryCount。当发生异常时,如果重试次数未达到最大次数,则通过Handler延迟一定时间后再次尝试请求。需要注意的是,重试次数和延迟时间应根据实际场景合理设置。

3. Jsoup库HTML解析详解

3.1 Jsoup库的介绍和使用环境设置

3.1.1 Jsoup库的基本概念

Jsoup 是一个 Java 库,用于解析 HTML 文档,它提供了一套易于使用的 API,可以提取和操作数据,如同在DOM中操作一样。它特别擅长于从HTML文档中抽取和操作特定元素,并且可以处理页面中的各种属性和文本内容。Jsoup 支持 HTTP 协议,因此可以很方便地从网上抓取 HTML 页面,并进行解析。此外,它也支持基于 CSS 选择器的方法来查找元素,这使得它在数据抓取和网页爬虫方面非常有用。

3.1.2 Jsoup库的集成和环境配置

要在项目中使用 Jsoup,首先需要将其添加到项目的依赖管理文件中。如果你使用的是 Maven,可以在 pom.xml 文件中添加以下依赖:

<dependency>
    <groupId>org.jsoup</groupId>
    <artifactId>jsoup</artifactId>
    <version>1.13.1</version>
</dependency>

对于 Gradle 项目,添加以下依赖到 build.gradle 文件:

implementation 'org.jsoup:jsoup:1.13.1'

在 Android 开发中,需要注意的是,从 Jsoup 1.12.2 版本开始,引入了一个用于解析 HTML 文档的解析器,基于 Java HTML 解析器,而之前的版本中,Jsoup 使用的是基于 Android 内置的 HTML 解析器。所以在 Android 项目中,建议使用最新版本的 Jsoup。

3.2 Jsoup解析HTML内容

3.2.1 解析HTML文档结构

要解析 HTML 文档结构,首先需要从一个 URL 或者 String 中加载 HTML 内容。使用 Jsoup,可以通过以下方式加载和解析 HTML:

Document doc = Jsoup.parse(htmlString);

这里的 htmlString 可以是本地的 HTML 字符串,也可以是从网络获取的 HTML 内容。一旦文档被解析,就可以使用 Jsoup 的 API 来访问 HTML 的各个部分。

3.2.2 提取和操作HTML元素

Jsoup 提供了简洁的方法来提取 HTML 中的特定元素。可以通过元素名称、ID、类名或 CSS 选择器来定位元素。例如,获取所有的标题元素:

Elements titles = doc.select("h1,h2,h3,h4,h5,h6");

一旦获取了元素,Jsoup 允许你进行诸如改变文本、添加类或属性、移除元素等操作。操作元素的示例:

Elements links = doc.select("a[href]"); // 选择所有带有href属性的<a>标签
for (Element link : links) {
    System.out.println(link.attr("href"));
}
3.2.3 处理HTML元素的属性和文本内容

Jsoup 提供了对 HTML 元素属性的直接访问和操作方式。要获取或设置属性,可以使用 attr 方法:

Element link = doc.select("a").first(); // 获取第一个<a>标签
String href = link.attr("href"); // 获取href属性值
link.attr("href", "http://example.com"); // 修改href属性值

处理元素的文本内容也非常方便,可以使用 text 方法来获取或设置元素及其子元素的纯文本内容:

String text = link.text(); // 获取<a>标签的文本内容
link.text("New text for link"); // 设置<a>标签的文本内容

3.3 实践中的应用场景

Jsoup 在很多场景下都非常有用,比如:

  • 网络爬虫
  • 数据抓取
  • 清理用户提交的不安全内容
  • 网页数据解析等

在编写网络爬虫或者数据抓取应用时,Jsoup 是一个非常强大的库,因为它可以非常方便地解析 HTML 内容,从而提取出有用信息。

3.4 代码块使用示例

以下是一个使用 Jsoup 库从网页中提取标题的简单示例:

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;

public class JsoupExample {
    public static void main(String[] args) {
        try {
            String url = "http://example.com";
            // 从URL加载HTML
            Document doc = Jsoup.connect(url).get();
            // 选择并打印所有的标题元素
            Elements titles = doc.select("h1, h2, h3, h4, h5, h6");
            for (Element title : titles) {
                System.out.println(title.text());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

在此示例中, Jsoup.connect(url).get() 用于连接到指定的 URL 并获取其 HTML 内容。之后, doc.select("h1, h2, h3, h4, h5, h6") 被用来选择所有标题标签,并通过循环遍历打印出它们的文本内容。

通过这个简单的示例,我们可以看到如何利用 Jsoup 来解析 HTML,并提取我们需要的信息。这对于处理网页数据以及开发类似爬虫的应用程序尤其有用。

3.5 结语

本章节详细介绍了 Jsoup 库的使用方法,包括环境配置、HTML 解析、元素提取和操作、属性和文本内容的处理等。Jsoup 作为一种功能强大的 HTML 解析工具,为开发者提供了便利,使得对网页数据的处理变得简单明了。从基本的文档解析到高级的元素操作,Jsoup 都提供了非常清晰的 API,使其成为 Java 和 Android 开发中处理 HTML 数据的首选库。

4. ListView展示数据实践

4.1 ListView的基本用法

4.1.1 ListView的布局和适配器配置

ListView 是 Android 开发中常用的组件之一,主要用于展示一个垂直滚动的列表项集合。为了更好地展示数据,我们需要理解如何在布局文件中正确配置 ListView ,以及如何通过适配器为它提供数据。

首先,要在布局文件中添加 ListView 组件。这通常是在 XML 布局文件中完成的:

<ListView
    android:id="@+id/list_view"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:divider="@android:color/darker_gray"
    android:dividerHeight="1dp"
    android:listSelector="@android:color/holo_blue_light" />

在上述代码中, android:id 属性为这个 ListView 提供一个唯一的 ID,以便在 Java 或 Kotlin 代码中引用。 android:layout_width android:layout_height 分别定义了组件的宽度和高度。 android:divider android:dividerHeight 设置了列表项之间的分隔线的颜色和高度,而 android:listSelector 则为列表项提供了选中时的视觉效果。

接下来,我们需要为 ListView 配置一个适配器。适配器 Adapter 是桥梁,将数据源与 ListView 组件连接起来。以下是使用 ArrayAdapter 来初始化 ListView 的基本示例代码:

ListView listView = findViewById(R.id.list_view);
ArrayAdapter<String> adapter = new ArrayAdapter<>(this,
                android.R.layout.simple_list_item_1, android.R.id.text1, new String[]{"Item 1", "Item 2", "Item 3"});
listView.setAdapter(adapter);

在这段代码中,我们首先通过 findViewById 方法获取到布局文件中定义的 ListView 。然后,我们创建了一个 ArrayAdapter 对象,其构造函数的参数分别代表当前上下文、布局文件、用于展示数据的视图组件以及数据集合。

ArrayAdapter 用于简化 ListView 的数据绑定过程,特别是当展示的数据项结构比较简单时。 android.R.layout.simple_list_item_1 是 Android 系统提供的一个标准布局文件,用于显示列表中的文本项。

4.1.2 动态添加和删除ListView项

在实际开发中,经常需要根据用户的操作动态地添加或删除 ListView 中的项。这一过程需要我们在适配器中添加或移除数据集合里的元素,并通知适配器数据已经更改,从而刷新 ListView 的显示内容。

添加项

假设我们有一个按钮,用户点击后可以在 ListView 中添加一个新的项:

Button addButton = findViewById(R.id.add_button);
addButton.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // 假设有一个数据列表
        List<String> dataList = adapter.getCount() > 0 ? adapter.getCount() : new ArrayList<>();
        dataList.add("New Item " + dataList.size());
        adapter.clear();
        adapter.addAll(dataList);
        adapter.notifyDataSetChanged();
    }
});

当按钮被点击时,我们首先从适配器获取当前的数据列表,然后向列表中添加一个新的字符串元素。接着,我们清空适配器中的数据,使用 addAll 方法添加新的数据集合,并通过 notifyDataSetChanged 方法通知 ListView ,数据已经发生了变化,需要重新加载视图。

删除项

删除 ListView 中的项通常需要根据用户的选择来进行。假设我们有一个方法 onItemDelete 来处理点击事件:

ListView listView = findViewById(R.id.list_view);
listView.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
    @Override
    public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) {
        onItemDelete(position);
        return true;
    }
});

public void onItemDelete(int position) {
    // 获取当前数据集合
    List<String> dataList = adapter.getCount() > 0 ? adapter.getCount() : new ArrayList<>();
    if (dataList.size() > 0 && position >= 0 && position < dataList.size()) {
        // 删除指定位置的项
        dataList.remove(position);
        adapter.clear();
        adapter.addAll(dataList);
        adapter.notifyDataSetChanged();
    }
}

在这段代码中,我们为 ListView 设置了一个长按监听器,当用户长按某个项时触发 onItemLongClick 方法。我们通过 onItemDelete 方法从数据集中移除被选中的项,并同样通过 notifyDataSetChanged 来刷新 ListView

4.2 数据与ListView的结合展示

4.2.1 数据模型的设计与实现

在展示数据之前,设计一个合适的数据模型是至关重要的。数据模型通常包含数据的属性以及对应的获取和设置方法。在 Android 开发中,数据模型通常是一个 Java 类,它的属性对应于界面上显示的数据字段。

假设我们有一个应用,需要展示一个书籍列表,每本书有书名和作者两个字段:

public class Book {
    private String title;
    private String author;

    // 构造函数
    public Book(String title, String author) {
        this.title = title;
        this.author = author;
    }

    // getter 和 setter 方法
    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }
}

上述代码定义了一个简单的 Book 类,包含了两个属性: title author ,以及它们对应的构造函数和 getter / setter 方法。这样的设计使得 Book 类的实例可以方便地用于数据绑定。

4.2.2 将解析的数据绑定到ListView

将数据绑定到 ListView 通常需要使用自定义的适配器,特别是在需要展示复杂数据结构时。 ArrayAdapter 可能无法满足所有需求,因为它的视图模型较为单一。这时,我们可以使用 BaseAdapter 来实现更复杂的绑定逻辑。

自定义适配器需要重写 getView 方法,以便为 ListView 中的每一项生成一个视图。以下是使用 BaseAdapter Book 列表数据绑定到 ListView 的示例代码:

public class BookAdapter extends BaseAdapter {
    private Context context;
    private List<Book> bookList;

    public BookAdapter(Context context, List<Book> bookList) {
        this.context = context;
        this.bookList = bookList;
    }

    @Override
    public int getCount() {
        return bookList.size();
    }

    @Override
    public Object getItem(int position) {
        return bookList.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // 重用旧视图或创建新视图
        if (convertView == null) {
            convertView = LayoutInflater.from(context).inflate(R.layout.item_book, parent, false);
        }

        // 获取当前书籍实例
        Book book = bookList.get(position);
        // 查找视图组件
        TextView titleView = convertView.findViewById(R.id.book_title);
        TextView authorView = convertView.findViewById(R.id.book_author);

        // 设置文本内容
        titleView.setText(book.getTitle());
        authorView.setText(book.getAuthor());

        return convertView;
    }
}

在这段代码中, BookAdapter 继承自 BaseAdapter ,并实现了它的所有抽象方法。我们首先定义了 getCount getItem getItemId 方法,这些都是 BaseAdapter 所需的。 getView 方法负责为 ListView 中的每一项创建或重用视图。如果 convertView 参数为 null ,则使用 LayoutInflater 来加载布局文件,并找到需要设置文本的 TextView 组件。

最后,我们将 BookAdapter 应用到 ListView

ListView listView = findViewById(R.id.list_view);
List<Book> bookList = fetchBooks(); // 假设此方法从数据源获取书籍列表
BookAdapter adapter = new BookAdapter(this, bookList);
listView.setAdapter(adapter);

通过上述方法,我们就能在 ListView 中展示每个书籍的名称和作者等信息。这种模式可以灵活地扩展到更复杂的数据展示,只要在 getView 方法中适当调整视图和数据的绑定逻辑即可。

5. 权限申请与异步任务处理

5.1 Android权限管理机制

5.1.1 Android权限的基本概念

在Android系统中,权限是一种限制应用程序可以执行的特定操作的机制。随着Android系统的不断更新迭代,权限管理机制也在不断完善。权限可以分为两类:系统权限和应用权限。系统权限是由系统层面定义的,如打电话、发送短信等,而应用权限则是应用自定义的,用于限制其他应用对其数据的访问。

为了保障用户隐私和系统安全,Android 6.0 引入了运行时权限(Runtime Permissions),这意味着应用需要在运行时向用户请求相应的权限。权限可以分为普通权限(Normal Permissions)、危险权限(Dangerous Permissions)和特殊权限(Special Permissions)。

5.1.2 网络访问权限的申请与管理

网络访问权限是一个典型的危险权限,因为它允许应用访问设备的网络,可能导致数据的传输和隐私信息的泄露。为了申请网络访问权限,开发者需要在应用的manifest文件中声明 ACCESS_NETWORK_STATE 权限。对于Android 6.0及以上版本,还需要在应用运行时请求用户授权。

下面是示例代码,展示如何在代码中请求网络权限:

if (ContextCompat.checkSelfPermission(thisActivity, Manifest.permission.ACCESS_NETWORK_STATE)
        != PackageManager.PERMISSION_GRANTED) {
    // Permission is not granted
    ActivityCompat.requestPermissions(thisActivity,
            new String[]{Manifest.permission.ACCESS_NETWORK_STATE},
            MY_PERMISSIONS_REQUEST_ACCESS_NETWORK_STATE);
}

如果用户授权了权限,我们就可以使用网络访问相关的API,如HttpURLConnection进行网络请求。如果未授权,我们需要妥善处理,并引导用户到设置页面开启权限。

5.2 异步任务处理机制

5.2.1 Android异步任务的分类与选择

为了在不影响UI线程的情况下执行耗时操作,Android提供了多种异步任务处理机制。其中最常见的有:

  • Thread : 最基础的方式,适合处理简单的后台任务,但需要手动管理线程的生命周期,并确保UI操作在UI线程中执行。
  • Handler/Looper : 通过消息队列机制来处理后台任务,适合与UI交互。
  • AsyncTask : 遗留机制,它封装了Thread和Handler,用于执行后台操作并在操作完成后更新UI。不过,由于AsyncTask的某些限制和已不推荐使用,对于新项目建议使用其他方式。
  • ExecutorService : Java并发框架的一部分,提供了更加灵活的线程池管理,适合进行复杂的后台任务。

5.2.2 使用AsyncTask处理网络请求

尽管AsyncTask已不推荐使用,但为了向后兼容性和示例说明,下面是如何使用AsyncTask来处理网络请求的示例:

private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
    protected Long doInBackground(URL... urls) {
        int count = urls.length;
        long totalSize = 0;
        for (int i = 0; i < count; i++) {
            try {
                URL url = urls[i];
                // Perform the network operation and calculate total size.
            } catch (Exception e) {
                // Handle the exception.
            }
        }
        return totalSize;
    }

    protected void onProgressUpdate(Integer... progress) {
        setProgressPercent(progress[0]);
    }

    protected void onPostExecute(Long result) {
        // Update UI with result.
    }
}

5.2.3 处理线程同步和数据更新问题

异步任务执行完成后,通常需要在UI线程上更新界面。这就涉及到线程同步和线程安全的问题。在Android中,Handler可以帮助我们在UI线程上更新数据。

// Update UI elements from within a background thread using the Handler
new Thread(new Runnable() {
    @Override
    public void run() {
        final String result = "Result from background thread";
        handler.post(new Runnable() {
            @Override
            public void run() {
                textView.setText(result);
            }
        });
    }
}).start();

通过使用Handler,我们可以在任何线程中发布和处理Runnable对象,将任务排队到UI线程的事件队列中,这样就能够在UI线程上安全地更新界面元素。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:本文介绍了在Android开发中如何使用HTTP请求来获取网页内容,并详细解释了利用Jsoup库解析HTML的过程。通过网络权限申请、HTTP GET请求的创建、HTML文档的解析以及在ListView中展示解析结果的步骤,本教程引导读者实现一个完整的网络内容获取和显示流程。教程还涵盖了自定义适配器的创建和事件处理,为开发功能丰富的Android网络应用提供指导。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值