方法概览

  1. 使用 HttpURLConnection (标准 Java API)

    • 优点: 不需要第三方库,是 Android SDK 自带的,轻量级。
    • 缺点: 代码相对繁琐,需要手动处理线程和流。
    • 适用场景: 简单的网络请求,不想引入第三方库时。
  2. 使用 OkHttp (强烈推荐)

    • 优点: 现代、高效、易用,内置了线程池、缓存、连接池等,是 Android 开发的事实标准。
    • 缺点: 需要添加第三方库依赖。
    • 适用场景: 几乎所有网络请求场景,特别是新项目。
  3. 使用 WebView

    • 优点: 可以完整地渲染一个网页,获取渲染后的最终源码(可能包含 JavaScript 动态生成的内容)。
    • 缺点: 相对重量级,主要用于展示网页,获取源码是其附加功能。
    • 适用场景: 需要获取经过 JavaScript 执行和修改后的最终 HTML 源码时。

核心前提:网络权限

无论使用哪种方法,你都必须在 AndroidManifest.xml 文件中声明网络权限。

<!-- 允许应用访问网络 -->
<uses-permission android:name="android.permission.INTERNET" />
<!-- 如果你的应用目标 API 级别是 28 或更高,还需要声明 cleartextTrafficAllowed -->
<!-- 因为从 Android 9 (API 28) 开始,默认禁止 HTTP 明文传输 -->
<application
    android:usesCleartextTraffic="true"
    ...>
    ...
</application>

使用 HttpURLConnection (原生方式)

这是最基础的方法,理解它有助于你了解网络请求的本质。

步骤:

  1. 在后台线程中发起请求(Android 4.0+ 不允许在主线程进行网络操作)。
  2. 创建 URL 对象。
  3. 打开 HttpURLConnection 连接。
  4. 设置请求方法(如 GET)。
  5. 获取输入流并读取数据。
  6. 将数据流转换为字符串(源码)。
  7. 关闭连接。

示例代码:

import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
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 MainActivity extends AppCompatActivity {
    private TextView textView;
    private Button button;
    // 切换到主线程的 Handler
    private Handler mainHandler = new Handler(Looper.getMainLooper());
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = findViewById(R.id.textView);
        button = findViewById(R.id.button);
        button.setOnClickListener(v -> {
            // 在新线程中执行网络请求
            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        String htmlSourceCode = getHtmlSourceCode("https://www.example.com");
                        // 将结果更新到 UI
                        updateUI(htmlSourceCode);
                    } catch (IOException e) {
                        e.printStackTrace();
                        updateUI("Error: " + e.getMessage());
                    }
                }
            }).start();
        });
    }
    private String getHtmlSourceCode(String urlString) throws IOException {
        URL url = new URL(urlString);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        connection.setRequestMethod("GET");
        connection.setConnectTimeout(15000); // 15秒连接超时
        connection.setReadTimeout(15000);   // 15秒读取超时
        // 获取响应码
        int responseCode = connection.getResponseCode();
        if (responseCode == HttpURLConnection.HTTP_OK) { // 200 OK
            // 获取输入流
            InputStream inputStream = connection.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
            StringBuilder response = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                response.append(line);
            }
            reader.close();
            inputStream.close();
            return response.toString();
        } else {
            throw new IOException("HTTP GET Request Failed with Response Code: " + responseCode);
        }
    }
    private void updateUI(final String result) {
        // 切换回主线程更新 UI
        mainHandler.post(() -> {
            textView.setText(result);
            Toast.makeText(MainActivity.this, "Source code loaded!", Toast.LENGTH_SHORT).show();
        });
    }
}

使用 OkHttp (推荐方式)

OkHttp 大大简化了网络请求的代码,并且性能更好,是目前 Android 开发的主流选择。

步骤:

  1. build.gradle (Module: app) 文件中添加 OkHttp 依赖。
  2. 创建 OkHttpClientRequest 对象。
  3. 使用 client.newCall(request).execute() (同步) 或 client.newCall(request).enqueue() (异步) 发起请求。
  4. 处理响应体 response.body().string() 获取源码。

添加依赖

打开你的 app/build.gradle 文件,在 dependencies 代码块中添加:

dependencies {
    // ... 其他依赖
    implementation("com.squareup.okhttp3:okhttp:4.12.0") // 使用最新版本
}

然后点击 "Sync Now"。

示例代码

OkHttp 的异步回调方式非常适合 Android。

import android.os.Bundle;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import java.io.IOException;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
public class MainActivityOkHttp extends AppCompatActivity {
    private TextView textView;
    private Button button;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main); // 假设布局文件和上面一样
        textView = findViewById(R.id.textView);
        button = findViewById(R.id.button);
        // 创建 OkHttpClient 实例
        OkHttpClient client = new OkHttpClient();
        button.setOnClickListener(v -> {
            // 1. 创建 Request 对象
            Request request = new Request.Builder()
                    .url("https://www.example.com")
                    .build();
            // 2. 创建 Call 对象并异步执行
            client.newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    // 请求失败
                    // 切换到主线程更新 UI
                    runOnUiThread(() -> {
                        textView.setText("Error: " + e.getMessage());
                        Toast.makeText(MainActivityOkHttp.this, "Request Failed", Toast.LENGTH_SHORT).show();
                    });
                }
                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    // 请求成功
                    if (response.isSuccessful()) {
                        // 获取响应体字符串 (网页源码)
                        final String htmlSourceCode = response.body().string();
                        // 切换到主线程更新 UI
                        runOnUiThread(() -> {
                            textView.setText(htmlSourceCode);
                            Toast.makeText(MainActivityOkHttp.this, "Source code loaded!", Toast.LENGTH_SHORT).show();
                        });
                    } else {
                        runOnUiThread(() -> {
                            textView.setText("Error: " + response.code());
                            Toast.makeText(MainActivityOkHttp.this, "Request Failed with Code: " + response.code(), Toast.LENGTH_SHORT).show();
                        });
                    }
                }
            });
        });
    }
}

使用 WebView

这种方法不直接请求网络,而是通过加载网页,然后获取其 DOM 内容,它能拿到 JavaScript 执行后的最终 HTML。

步骤:

  1. 在布局文件中添加 WebView 组件。
  2. 在代码中获取 WebView 实例。
  3. 设置 WebViewClient,并在 onPageFinished 回调中获取源码。
  4. 启用 JavaScript(如果网页需要)。

布局文件 (activity_main.xml)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="16dp">
    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Load via WebView" />
    <WebView
        android:id="@+id/webView"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1" />
</LinearLayout>

示例代码

import android.os.Bundle;
import android.webkit.WebChromeClient;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Button;
import androidx.appcompat.app.AppCompatActivity;
public class MainActivityWebView extends AppCompatActivity {
    private WebView webView;
    private Button button;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        webView = findViewById(R.id.webView);
        button = findViewById(R.id.button);
        // 启用 JavaScript (非常重要!)
        webView.getSettings().setJavaScriptEnabled(true);
        button.setOnClickListener(v -> {
            // 加载网页
            webView.loadUrl("https://www.example.com");
        });
        // 设置 WebViewClient
        webView.setWebViewClient(new WebViewClient() {
            @Override
            public void onPageFinished(WebView view, String url) {
                // 页面加载完成后调用
                // 可以在这里执行 JavaScript 来获取最终的 HTML
                view.evaluateJavascript("(function() { return document.documentElement.outerHTML; })();", value -> {
                    // value 是 JavaScript 返回的结果,带有前后的引号,需要处理
                    String htmlSourceCode = value.substring(1, value.length() - 1);
                    // 在这里你可以得到最终的 HTML 源码
                    // 注意:直接在 logcat 中打印很长的字符串可能会被截断
                    android.util.Log.d("WebViewSource", "HTML Source: " + htmlSourceCode.substring(0, Math.min(500, htmlSourceCode.length())) + "...");
                    // 你可以将它显示在另一个 TextView 中
                    // textView.setText(htmlSourceCode);
                });
            }
        });
    }
}

总结与对比

方法 优点 缺点 适用场景
HttpURLConnection 无需第三方库,轻量 代码繁琐,功能少 简单学习,无依赖需求
OkHttp 代码简洁,功能强大,性能好 需要添加依赖 绝大多数网络请求场景的首选
WebView 能获取 JS 渲染后的最终 HTML 资源消耗大,主要用于展示页面 需要与网页深度交互或抓取动态内容的场景

对于绝大多数获取网页源码的需求,强烈推荐使用 OkHttp,因为它在开发效率和性能之间取得了最佳平衡,只有当你明确需要获取经过 JavaScript 动态修改的 HTML 时,才考虑使用 WebView