全部笔记All notes

Android网络编程完全指南

阅读 7m 34s7m 34s read

系列导航

概述

网络编程是现代Android应用的核心功能之一。本指南全面介绍Android平台的网络编程技术,包括原生API、流行框架、WebView使用、数据解析等内容,帮助开发者构建高效、安全的网络应用。

学习目标

  • 掌握Android网络权限和安全配置
  • 学习使用HttpURLConnection和OkHttp
  • 精通Retrofit框架的使用
  • 理解WebView的高级用法
  • 实现文件的上传和下载
  • 掌握JSON和XML数据解析
  • 优化网络请求性能

网络权限配置

添加网络权限

<!-- AndroidManifest.xml -->
<manifest ...>
    <!-- 基本网络权限 -->
    <uses-permission android:name="android.permission.INTERNET" />
    <!-- 网络状态权限 -->
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <!-- WiFi状态权限 -->
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    
    <application
        android:usesCleartextTraffic="true"
        android:networkSecurityConfig="@xml/network_security_config"
        ...>
    </application>
</manifest>

网络安全配置

<!-- res/xml/network_security_config.xml -->
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <!-- 默认配置 -->
    <base-config cleartextTrafficPermitted="false">
        <trust-anchors>
            <certificates src="system" />
        </trust-anchors>
    </base-config>
    
    <!-- 开发环境配置 -->
    <debug-overrides>
        <trust-anchors>
            <certificates src="user" />
        </trust-anchors>
    </debug-overrides>
    
    <!-- 特定域名配置 -->
    <domain-config cleartextTrafficPermitted="true">
        <domain includeSubdomains="true">api.example.com</domain>
        <domain includeSubdomains="true">10.0.2.2</domain> <!-- 模拟器本地主机 -->
    </domain-config>
</network-security-config>

HttpURLConnection

基本GET请求

public class HttpHelper {
    
    public static String doGet(String urlString) throws IOException {
        URL url = new URL(urlString);
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();
        
        try {
            // 设置请求方法
            connection.setRequestMethod("GET");
            connection.setConnectTimeout(10000);
            connection.setReadTimeout(10000);
            
            // 设置请求头
            connection.setRequestProperty("Accept", "application/json");
            connection.setRequestProperty("User-Agent", "Android App");
            
            // 获取响应码
            int responseCode = connection.getResponseCode();
            if (responseCode == HttpURLConnection.HTTP_OK) {
                // 读取响应
                InputStream inputStream = connection.getInputStream();
                return readStream(inputStream);
            } else {
                throw new IOException("HTTP error code: " + responseCode);
            }
        } finally {
            connection.disconnect();
        }
    }
    
    private static String readStream(InputStream is) throws IOException {
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        StringBuilder response = new StringBuilder();
        String line;
        
        while ((line = reader.readLine()) != null) {
            response.append(line).append('\n');
        }
        
        reader.close();
        return response.toString();
    }
}

POST请求

public static String doPost(String urlString, String jsonBody) throws IOException {
    URL url = new URL(urlString);
    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
    
    try {
        // 设置POST请求
        connection.setRequestMethod("POST");
        connection.setDoOutput(true);
        connection.setDoInput(true);
        connection.setConnectTimeout(10000);
        connection.setReadTimeout(10000);
        
        // 设置请求头
        connection.setRequestProperty("Content-Type", "application/json; charset=UTF-8");
        connection.setRequestProperty("Accept", "application/json");
        
        // 写入请求体
        OutputStream os = connection.getOutputStream();
        os.write(jsonBody.getBytes("UTF-8"));
        os.flush();
        os.close();
        
        // 获取响应
        int responseCode = connection.getResponseCode();
        if (responseCode == HttpURLConnection.HTTP_OK) {
            InputStream inputStream = connection.getInputStream();
            return readStream(inputStream);
        } else {
            InputStream errorStream = connection.getErrorStream();
            String error = readStream(errorStream);
            throw new IOException("HTTP error code: " + responseCode + ", " + error);
        }
    } finally {
        connection.disconnect();
    }
}

异步请求封装

public class NetworkManager {
    private final ExecutorService executorService = Executors.newFixedThreadPool(4);
    
    public interface NetworkCallback {
        void onSuccess(String response);
        void onError(Exception e);
    }
    
    public void getAsync(final String url, final NetworkCallback callback) {
        executorService.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    String response = HttpHelper.doGet(url);
                    runOnUiThread(() -> callback.onSuccess(response));
                } catch (Exception e) {
                    runOnUiThread(() -> callback.onError(e));
                }
            }
        });
    }
    
    public void postAsync(final String url, final String body, final NetworkCallback callback) {
        executorService.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    String response = HttpHelper.doPost(url, body);
                    runOnUiThread(() -> callback.onSuccess(response));
                } catch (Exception e) {
                    runOnUiThread(() -> callback.onError(e));
                }
            }
        });
    }
    
    private void runOnUiThread(Runnable runnable) {
        new Handler(Looper.getMainLooper()).post(runnable);
    }
    
    public void shutdown() {
        executorService.shutdown();
    }
}

OkHttp使用

添加依赖

dependencies {
    implementation 'com.squareup.okhttp3:okhttp:4.11.0'
    implementation 'com.squareup.okhttp3:logging-interceptor:4.11.0'
}

基本使用

public class OkHttpManager {
    private static OkHttpManager instance;
    private final OkHttpClient client;
    
    private OkHttpManager() {
        // 创建日志拦截器
        HttpLoggingInterceptor loggingInterceptor = new HttpLoggingInterceptor();
        loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY);
        
        // 创建OkHttpClient
        client = new OkHttpClient.Builder()
            .connectTimeout(10, TimeUnit.SECONDS)
            .readTimeout(10, TimeUnit.SECONDS)
            .writeTimeout(10, TimeUnit.SECONDS)
            .addInterceptor(loggingInterceptor)
            .addInterceptor(new HeaderInterceptor())
            .cache(new Cache(getCacheDir(), 10 * 1024 * 1024)) // 10MB缓存
            .build();
    }
    
    public static OkHttpManager getInstance() {
        if (instance == null) {
            synchronized (OkHttpManager.class) {
                if (instance == null) {
                    instance = new OkHttpManager();
                }
            }
        }
        return instance;
    }
    
    // GET请求
    public void get(String url, Callback callback) {
        Request request = new Request.Builder()
            .url(url)
            .get()
            .build();
        
        client.newCall(request).enqueue(callback);
    }
    
    // POST请求 - JSON
    public void postJson(String url, String json, Callback callback) {
        MediaType JSON = MediaType.parse("application/json; charset=utf-8");
        RequestBody body = RequestBody.create(json, JSON);
        
        Request request = new Request.Builder()
            .url(url)
            .post(body)
            .build();
        
        client.newCall(request).enqueue(callback);
    }
    
    // POST请求 - 表单
    public void postForm(String url, Map<String, String> params, Callback callback) {
        FormBody.Builder builder = new FormBody.Builder();
        for (Map.Entry<String, String> entry : params.entrySet()) {
            builder.add(entry.getKey(), entry.getValue());
        }
        
        Request request = new Request.Builder()
            .url(url)
            .post(builder.build())
            .build();
        
        client.newCall(request).enqueue(callback);
    }
    
    // 文件上传
    public void uploadFile(String url, File file, Callback callback) {
        MediaType mediaType = MediaType.parse("application/octet-stream");
        
        MultipartBody body = new MultipartBody.Builder()
            .setType(MultipartBody.FORM)
            .addFormDataPart("file", file.getName(),
                RequestBody.create(file, mediaType))
            .build();
        
        Request request = new Request.Builder()
            .url(url)
            .post(body)
            .build();
        
        client.newCall(request).enqueue(callback);
    }
    
    // 自定义拦截器
    private static class HeaderInterceptor implements Interceptor {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request original = chain.request();
            
            Request request = original.newBuilder()
                .header("Authorization", "Bearer " + getToken())
                .header("Platform", "Android")
                .header("Version", BuildConfig.VERSION_NAME)
                .method(original.method(), original.body())
                .build();
            
            return chain.proceed(request);
        }
        
        private String getToken() {
            // 获取token逻辑
            return "your_auth_token";
        }
    }
}

使用示例

public class NetworkActivity extends AppCompatActivity {
    
    private void fetchData() {
        OkHttpManager.getInstance().get("https://api.example.com/data", 
            new Callback() {
                @Override
                public void onFailure(@NonNull Call call, @NonNull IOException e) {
                    runOnUiThread(() -> {
                        Toast.makeText(NetworkActivity.this, 
                            "网络请求失败: " + e.getMessage(), 
                            Toast.LENGTH_SHORT).show();
                    });
                }
                
                @Override
                public void onResponse(@NonNull Call call, @NonNull Response response) 
                        throws IOException {
                    if (response.isSuccessful()) {
                        String json = response.body().string();
                        runOnUiThread(() -> {
                            // 更新UI
                            updateUI(json);
                        });
                    } else {
                        runOnUiThread(() -> {
                            Toast.makeText(NetworkActivity.this, 
                                "请求失败: " + response.code(), 
                                Toast.LENGTH_SHORT).show();
                        });
                    }
                }
            });
    }
}

Retrofit框架

添加依赖

dependencies {
    implementation 'com.squareup.retrofit2:retrofit:2.9.0'
    implementation 'com.squareup.retrofit2:converter-gson:2.9.0'
    implementation 'com.squareup.retrofit2:adapter-rxjava3:2.9.0'
    implementation 'com.google.code.gson:gson:2.10.1'
}

定义API接口

public interface ApiService {
    
    // GET请求
    @GET("users/{id}")
    Call<User> getUser(@Path("id") int userId);
    
    // GET请求带查询参数
    @GET("users")
    Call<List<User>> getUsers(@Query("page") int page, 
                             @Query("size") int size);
    
    // POST请求
    @POST("users")
    Call<User> createUser(@Body User user);
    
    // PUT请求
    @PUT("users/{id}")
    Call<User> updateUser(@Path("id") int userId, @Body User user);
    
    // DELETE请求
    @DELETE("users/{id}")
    Call<Void> deleteUser(@Path("id") int userId);
    
    // 文件上传
    @Multipart
    @POST("upload")
    Call<UploadResponse> uploadFile(@Part MultipartBody.Part file,
                                   @Part("description") RequestBody description);
    
    // 文件下载
    @Streaming
    @GET
    Call<ResponseBody> downloadFile(@Url String fileUrl);
    
    // 使用RxJava
    @GET("users")
    Observable<List<User>> getUsersRx(@Query("page") int page);
}

创建Retrofit实例

public class RetrofitClient {
    private static RetrofitClient instance;
    private final Retrofit retrofit;
    private final ApiService apiService;
    
    private RetrofitClient() {
        // 创建OkHttpClient
        OkHttpClient client = new OkHttpClient.Builder()
            .connectTimeout(30, TimeUnit.SECONDS)
            .readTimeout(30, TimeUnit.SECONDS)
            .addInterceptor(new HttpLoggingInterceptor()
                .setLevel(HttpLoggingInterceptor.Level.BODY))
            .addInterceptor(new AuthInterceptor())
            .build();
        
        // 创建Retrofit
        retrofit = new Retrofit.Builder()
            .baseUrl("https://api.example.com/")
            .client(client)
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(RxJava3CallAdapterFactory.create())
            .build();
        
        apiService = retrofit.create(ApiService.class);
    }
    
    public static RetrofitClient getInstance() {
        if (instance == null) {
            synchronized (RetrofitClient.class) {
                if (instance == null) {
                    instance = new RetrofitClient();
                }
            }
        }
        return instance;
    }
    
    public ApiService getApiService() {
        return apiService;
    }
    
    // 认证拦截器
    private static class AuthInterceptor implements Interceptor {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request original = chain.request();
            
            Request.Builder builder = original.newBuilder()
                .header("Authorization", "Bearer " + getToken());
            
            Request request = builder.build();
            return chain.proceed(request);
        }
        
        private String getToken() {
            // 从SharedPreferences或其他地方获取token
            return "your_auth_token";
        }
    }
}

数据模型

public class User {
    @SerializedName("id")
    private int id;
    
    @SerializedName("name")
    private String name;
    
    @SerializedName("email")
    private String email;
    
    @SerializedName("avatar_url")
    private String avatarUrl;
    
    @SerializedName("created_at")
    private Date createdAt;
    
    // Getters and setters
    public int getId() { return id; }
    public void setId(int id) { this.id = id; }
    
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
    
    public String getEmail() { return email; }
    public void setEmail(String email) { this.email = email; }
    
    public String getAvatarUrl() { return avatarUrl; }
    public void setAvatarUrl(String avatarUrl) { this.avatarUrl = avatarUrl; }
    
    public Date getCreatedAt() { return createdAt; }
    public void setCreatedAt(Date createdAt) { this.createdAt = createdAt; }
}

使用Retrofit

public class UserViewModel extends AndroidViewModel {
    private final MutableLiveData<List<User>> usersLiveData = new MutableLiveData<>();
    private final MutableLiveData<String> errorLiveData = new MutableLiveData<>();
    private final ApiService apiService;
    
    public UserViewModel(@NonNull Application application) {
        super(application);
        apiService = RetrofitClient.getInstance().getApiService();
    }
    
    public LiveData<List<User>> getUsers() {
        return usersLiveData;
    }
    
    public LiveData<String> getError() {
        return errorLiveData;
    }
    
    public void loadUsers(int page) {
        apiService.getUsers(page, 20).enqueue(new Callback<List<User>>() {
            @Override
            public void onResponse(Call<List<User>> call, Response<List<User>> response) {
                if (response.isSuccessful() && response.body() != null) {
                    usersLiveData.postValue(response.body());
                } else {
                    errorLiveData.postValue("加载失败: " + response.code());
                }
            }
            
            @Override
            public void onFailure(Call<List<User>> call, Throwable t) {
                errorLiveData.postValue("网络错误: " + t.getMessage());
            }
        });
    }
    
    public void createUser(User user) {
        apiService.createUser(user).enqueue(new Callback<User>() {
            @Override
            public void onResponse(Call<User> call, Response<User> response) {
                if (response.isSuccessful()) {
                    // 用户创建成功
                    loadUsers(1); // 重新加载列表
                } else {
                    errorLiveData.postValue("创建失败: " + response.code());
                }
            }
            
            @Override
            public void onFailure(Call<User> call, Throwable t) {
                errorLiveData.postValue("网络错误: " + t.getMessage());
            }
        });
    }
}

WebView详解

基本配置

public class WebViewActivity extends AppCompatActivity {
    private WebView webView;
    private ProgressBar progressBar;
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_webview);
        
        webView = findViewById(R.id.webView);
        progressBar = findViewById(R.id.progressBar);
        
        initWebView();
        webView.loadUrl("https://www.example.com");
    }
    
    @SuppressLint("SetJavaScriptEnabled")
    private void initWebView() {
        WebSettings settings = webView.getSettings();
        
        // 基本设置
        settings.setJavaScriptEnabled(true);
        settings.setDomStorageEnabled(true);
        settings.setDatabaseEnabled(true);
        settings.setAppCacheEnabled(true);
        settings.setCacheMode(WebSettings.LOAD_DEFAULT);
        
        // 支持缩放
        settings.setSupportZoom(true);
        settings.setBuiltInZoomControls(true);
        settings.setDisplayZoomControls(false);
        
        // 自适应屏幕
        settings.setUseWideViewPort(true);
        settings.setLoadWithOverviewMode(true);
        
        // 文件访问
        settings.setAllowFileAccess(true);
        settings.setAllowContentAccess(true);
        
        // 混合内容
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            settings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
        }
        
        // 设置WebViewClient
        webView.setWebViewClient(new MyWebViewClient());
        
        // 设置WebChromeClient
        webView.setWebChromeClient(new MyWebChromeClient());
        
        // 添加JavaScript接口
        webView.addJavascriptInterface(new WebAppInterface(this), "Android");
    }
    
    private class MyWebViewClient extends WebViewClient {
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
            String url = request.getUrl().toString();
            
            // 处理特殊协议
            if (url.startsWith("tel:")) {
                Intent intent = new Intent(Intent.ACTION_DIAL, Uri.parse(url));
                startActivity(intent);
                return true;
            } else if (url.startsWith("mailto:")) {
                Intent intent = new Intent(Intent.ACTION_SENDTO, Uri.parse(url));
                startActivity(intent);
                return true;
            }
            
            // 在WebView中加载URL
            view.loadUrl(url);
            return true;
        }
        
        @Override
        public void onPageStarted(WebView view, String url, Bitmap favicon) {
            super.onPageStarted(view, url, favicon);
            progressBar.setVisibility(View.VISIBLE);
        }
        
        @Override
        public void onPageFinished(WebView view, String url) {
            super.onPageFinished(view, url);
            progressBar.setVisibility(View.GONE);
        }
        
        @Override
        public void onReceivedError(WebView view, WebResourceRequest request, 
                                   WebResourceError error) {
            super.onReceivedError(view, request, error);
            // 加载错误页面
            view.loadUrl("file:///android_asset/error.html");
        }
        
        @Override
        public void onReceivedSslError(WebView view, SslErrorHandler handler, 
                                      SslError error) {
            // 处理SSL错误
            AlertDialog.Builder builder = new AlertDialog.Builder(WebViewActivity.this);
            builder.setMessage("SSL证书错误,是否继续?");
            builder.setPositiveButton("继续", (dialog, which) -> handler.proceed());
            builder.setNegativeButton("取消", (dialog, which) -> handler.cancel());
            builder.create().show();
        }
    }
    
    private class MyWebChromeClient extends WebChromeClient {
        @Override
        public void onProgressChanged(WebView view, int newProgress) {
            progressBar.setProgress(newProgress);
        }
        
        @Override
        public void onReceivedTitle(WebView view, String title) {
            setTitle(title);
        }
        
        @Override
        public boolean onJsAlert(WebView view, String url, String message, 
                                JsResult result) {
            AlertDialog.Builder builder = new AlertDialog.Builder(WebViewActivity.this);
            builder.setMessage(message)
                .setPositiveButton("确定", (dialog, which) -> result.confirm())
                .setCancelable(false)
                .create()
                .show();
            return true;
        }
        
        @Override
        public boolean onShowFileChooser(WebView webView, 
                                       ValueCallback<Uri[]> filePathCallback,
                                       FileChooserParams fileChooserParams) {
            // 处理文件选择
            openFileChooser(filePathCallback);
            return true;
        }
    }
    
    @Override
    public void onBackPressed() {
        if (webView.canGoBack()) {
            webView.goBack();
        } else {
            super.onBackPressed();
        }
    }
    
    @Override
    protected void onDestroy() {
        if (webView != null) {
            webView.loadDataWithBaseURL(null, "", "text/html", "utf-8", null);
            webView.clearHistory();
            ((ViewGroup) webView.getParent()).removeView(webView);
            webView.destroy();
            webView = null;
        }
        super.onDestroy();
    }
}

JavaScript交互

public class WebAppInterface {
    private Context context;
    
    public WebAppInterface(Context context) {
        this.context = context;
    }
    
    @JavascriptInterface
    public void showToast(String message) {
        Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
    }
    
    @JavascriptInterface
    public String getDeviceInfo() {
        JSONObject json = new JSONObject();
        try {
            json.put("model", Build.MODEL);
            json.put("brand", Build.BRAND);
            json.put("version", Build.VERSION.RELEASE);
            json.put("sdk", Build.VERSION.SDK_INT);
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return json.toString();
    }
    
    @JavascriptInterface
    public void saveData(String key, String value) {
        SharedPreferences prefs = context.getSharedPreferences("WebData", 
            Context.MODE_PRIVATE);
        prefs.edit().putString(key, value).apply();
    }
    
    @JavascriptInterface
    public String getData(String key) {
        SharedPreferences prefs = context.getSharedPreferences("WebData", 
            Context.MODE_PRIVATE);
        return prefs.getString(key, "");
    }
}

HTML中调用Android方法

<!DOCTYPE html>
<html>
<head>
    <title>WebView Demo</title>
    <script type="text/javascript">
        function showAndroidToast(message) {
            Android.showToast(message);
        }
        
        function getDeviceInfo() {
            var info = Android.getDeviceInfo();
            var device = JSON.parse(info);
            document.getElementById('deviceInfo').innerHTML = 
                'Model: ' + device.model + '<br>' +
                'Brand: ' + device.brand + '<br>' +
                'Version: ' + device.version + '<br>' +
                'SDK: ' + device.sdk;
        }
        
        function saveToAndroid() {
            var key = document.getElementById('key').value;
            var value = document.getElementById('value').value;
            Android.saveData(key, value);
            showAndroidToast('Data saved!');
        }
        
        function loadFromAndroid() {
            var key = document.getElementById('key').value;
            var value = Android.getData(key);
            document.getElementById('value').value = value;
        }
    </script>
</head>
<body>
    <h1>WebView JavaScript Interface Demo</h1>
    
    <button onclick="showAndroidToast('Hello from WebView!')">Show Toast</button>
    <button onclick="getDeviceInfo()">Get Device Info</button>
    
    <div id="deviceInfo"></div>
    
    <input type="text" id="key" placeholder="Key">
    <input type="text" id="value" placeholder="Value">
    <button onclick="saveToAndroid()">Save</button>
    <button onclick="loadFromAndroid()">Load</button>
</body>
</html>

文件上传下载

文件下载

public class DownloadManager {
    private static final int BUFFER_SIZE = 4096;
    
    public interface DownloadListener {
        void onProgress(int progress);
        void onComplete(File file);
        void onError(Exception e);
    }
    
    public void downloadFile(String fileUrl, String savePath, 
                           DownloadListener listener) {
        new Thread(() -> {
            try {
                URL url = new URL(fileUrl);
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                connection.connect();
                
                // 获取文件大小
                int fileLength = connection.getContentLength();
                
                // 创建输入输出流
                InputStream input = new BufferedInputStream(connection.getInputStream());
                File file = new File(savePath);
                OutputStream output = new FileOutputStream(file);
                
                byte[] buffer = new byte[BUFFER_SIZE];
                int count;
                long total = 0;
                
                while ((count = input.read(buffer)) != -1) {
                    total += count;
                    
                    // 计算进度
                    if (fileLength > 0) {
                        int progress = (int) (total * 100 / fileLength);
                        runOnUiThread(() -> listener.onProgress(progress));
                    }
                    
                    output.write(buffer, 0, count);
                }
                
                output.flush();
                output.close();
                input.close();
                
                runOnUiThread(() -> listener.onComplete(file));
                
            } catch (Exception e) {
                runOnUiThread(() -> listener.onError(e));
            }
        }).start();
    }
    
    // 使用OkHttp下载
    public void downloadWithOkHttp(String url, String destPath, 
                                  DownloadListener listener) {
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder().url(url).build();
        
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                listener.onError(e);
            }
            
            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (!response.isSuccessful()) {
                    listener.onError(new IOException("Unexpected code " + response));
                    return;
                }
                
                ResponseBody body = response.body();
                long contentLength = body.contentLength();
                
                InputStream input = body.byteStream();
                File file = new File(destPath);
                OutputStream output = new FileOutputStream(file);
                
                byte[] buffer = new byte[BUFFER_SIZE];
                long total = 0;
                int count;
                
                while ((count = input.read(buffer)) != -1) {
                    total += count;
                    
                    int progress = (int) (total * 100 / contentLength);
                    runOnUiThread(() -> listener.onProgress(progress));
                    
                    output.write(buffer, 0, count);
                }
                
                output.flush();
                output.close();
                input.close();
                
                runOnUiThread(() -> listener.onComplete(file));
            }
        });
    }
    
    private void runOnUiThread(Runnable runnable) {
        new Handler(Looper.getMainLooper()).post(runnable);
    }
}

文件上传

public class UploadManager {
    
    public interface UploadListener {
        void onProgress(int progress);
        void onSuccess(String response);
        void onError(Exception e);
    }
    
    // 使用HttpURLConnection上传
    public void uploadFile(String uploadUrl, File file, 
                          Map<String, String> params,
                          UploadListener listener) {
        String boundary = "----" + System.currentTimeMillis();
        
        new Thread(() -> {
            try {
                URL url = new URL(uploadUrl);
                HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                
                // 设置请求属性
                connection.setDoOutput(true);
                connection.setDoInput(true);
                connection.setUseCaches(false);
                connection.setRequestMethod("POST");
                connection.setRequestProperty("Content-Type", 
                    "multipart/form-data; boundary=" + boundary);
                
                DataOutputStream dos = new DataOutputStream(connection.getOutputStream());
                
                // 添加参数
                for (Map.Entry<String, String> entry : params.entrySet()) {
                    dos.writeBytes("--" + boundary + "\r\n");
                    dos.writeBytes("Content-Disposition: form-data; name=\"" + 
                        entry.getKey() + "\"\r\n\r\n");
                    dos.writeBytes(entry.getValue() + "\r\n");
                }
                
                // 添加文件
                dos.writeBytes("--" + boundary + "\r\n");
                dos.writeBytes("Content-Disposition: form-data; name=\"file\"; filename=\"" + 
                    file.getName() + "\"\r\n");
                dos.writeBytes("Content-Type: application/octet-stream\r\n\r\n");
                
                FileInputStream fis = new FileInputStream(file);
                byte[] buffer = new byte[4096];
                int bytesRead;
                long totalBytes = file.length();
                long uploadedBytes = 0;
                
                while ((bytesRead = fis.read(buffer)) != -1) {
                    dos.write(buffer, 0, bytesRead);
                    uploadedBytes += bytesRead;
                    
                    int progress = (int) (uploadedBytes * 100 / totalBytes);
                    runOnUiThread(() -> listener.onProgress(progress));
                }
                
                dos.writeBytes("\r\n");
                dos.writeBytes("--" + boundary + "--\r\n");
                
                fis.close();
                dos.flush();
                dos.close();
                
                // 获取响应
                int responseCode = connection.getResponseCode();
                if (responseCode == HttpURLConnection.HTTP_OK) {
                    BufferedReader br = new BufferedReader(
                        new InputStreamReader(connection.getInputStream()));
                    StringBuilder response = new StringBuilder();
                    String line;
                    while ((line = br.readLine()) != null) {
                        response.append(line);
                    }
                    br.close();
                    
                    runOnUiThread(() -> listener.onSuccess(response.toString()));
                } else {
                    throw new IOException("Server returned: " + responseCode);
                }
                
            } catch (Exception e) {
                runOnUiThread(() -> listener.onError(e));
            }
        }).start();
    }
    
    // 使用Retrofit上传
    public void uploadWithRetrofit(File file, String description) {
        RequestBody requestFile = RequestBody.create(
            MediaType.parse("multipart/form-data"), file);
        
        MultipartBody.Part body = MultipartBody.Part.createFormData(
            "file", file.getName(), requestFile);
        
        RequestBody descBody = RequestBody.create(
            MediaType.parse("text/plain"), description);
        
        ApiService service = RetrofitClient.getInstance().getApiService();
        service.uploadFile(body, descBody).enqueue(new Callback<UploadResponse>() {
            @Override
            public void onResponse(Call<UploadResponse> call, 
                                 Response<UploadResponse> response) {
                if (response.isSuccessful()) {
                    // 上传成功
                }
            }
            
            @Override
            public void onFailure(Call<UploadResponse> call, Throwable t) {
                // 上传失败
            }
        });
    }
}

网络状态监测

public class NetworkStateManager {
    private Context context;
    private ConnectivityManager connectivityManager;
    private NetworkCallback networkCallback;
    
    public interface NetworkStateListener {
        void onNetworkAvailable();
        void onNetworkLost();
        void onNetworkTypeChanged(NetworkType type);
    }
    
    public enum NetworkType {
        WIFI, MOBILE, ETHERNET, NONE
    }
    
    public NetworkStateManager(Context context) {
        this.context = context;
        this.connectivityManager = (ConnectivityManager) 
            context.getSystemService(Context.CONNECTIVITY_SERVICE);
    }
    
    public boolean isNetworkAvailable() {
        NetworkInfo activeNetwork = connectivityManager.getActiveNetworkInfo();
        return activeNetwork != null && activeNetwork.isConnected();
    }
    
    public NetworkType getCurrentNetworkType() {
        NetworkInfo activeNetwork = connectivityManager.getActiveNetworkInfo();
        if (activeNetwork == null || !activeNetwork.isConnected()) {
            return NetworkType.NONE;
        }
        
        switch (activeNetwork.getType()) {
            case ConnectivityManager.TYPE_WIFI:
                return NetworkType.WIFI;
            case ConnectivityManager.TYPE_MOBILE:
                return NetworkType.MOBILE;
            case ConnectivityManager.TYPE_ETHERNET:
                return NetworkType.ETHERNET;
            default:
                return NetworkType.NONE;
        }
    }
    
    @RequiresApi(api = Build.VERSION_CODES.N)
    public void registerNetworkCallback(NetworkStateListener listener) {
        networkCallback = new ConnectivityManager.NetworkCallback() {
            @Override
            public void onAvailable(Network network) {
                listener.onNetworkAvailable();
            }
            
            @Override
            public void onLost(Network network) {
                listener.onNetworkLost();
            }
            
            @Override
            public void onCapabilitiesChanged(Network network, 
                                            NetworkCapabilities capabilities) {
                if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)) {
                    listener.onNetworkTypeChanged(NetworkType.WIFI);
                } else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)) {
                    listener.onNetworkTypeChanged(NetworkType.MOBILE);
                } else if (capabilities.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET)) {
                    listener.onNetworkTypeChanged(NetworkType.ETHERNET);
                }
            }
        };
        
        NetworkRequest request = new NetworkRequest.Builder()
            .addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
            .build();
        
        connectivityManager.registerNetworkCallback(request, networkCallback);
    }
    
    public void unregisterNetworkCallback() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && networkCallback != null) {
            connectivityManager.unregisterNetworkCallback(networkCallback);
        }
    }
}

数据解析

JSON解析

public class JsonParser {
    
    // 使用Gson解析
    public static <T> T parseJson(String json, Class<T> clazz) {
        Gson gson = new Gson();
        return gson.fromJson(json, clazz);
    }
    
    public static <T> List<T> parseJsonList(String json, Type typeOfT) {
        Gson gson = new Gson();
        return gson.fromJson(json, typeOfT);
    }
    
    // 手动解析JSON
    public static User parseUser(String json) throws JSONException {
        JSONObject jsonObject = new JSONObject(json);
        User user = new User();
        
        user.setId(jsonObject.getInt("id"));
        user.setName(jsonObject.getString("name"));
        user.setEmail(jsonObject.optString("email", ""));
        
        // 解析嵌套对象
        if (jsonObject.has("address")) {
            JSONObject addressJson = jsonObject.getJSONObject("address");
            Address address = new Address();
            address.setStreet(addressJson.getString("street"));
            address.setCity(addressJson.getString("city"));
            user.setAddress(address);
        }
        
        // 解析数组
        if (jsonObject.has("tags")) {
            JSONArray tagsArray = jsonObject.getJSONArray("tags");
            List<String> tags = new ArrayList<>();
            for (int i = 0; i < tagsArray.length(); i++) {
                tags.add(tagsArray.getString(i));
            }
            user.setTags(tags);
        }
        
        return user;
    }
    
    // 生成JSON
    public static String toJson(Object object) {
        Gson gson = new GsonBuilder()
            .setPrettyPrinting()
            .setDateFormat("yyyy-MM-dd HH:mm:ss")
            .create();
        return gson.toJson(object);
    }
}

XML解析

public class XmlParser {
    
    // 使用Pull解析器
    public static List<Item> parseXml(InputStream inputStream) 
            throws XmlPullParserException, IOException {
        List<Item> items = new ArrayList<>();
        
        XmlPullParser parser = Xml.newPullParser();
        parser.setInput(inputStream, "UTF-8");
        
        int eventType = parser.getEventType();
        Item currentItem = null;
        
        while (eventType != XmlPullParser.END_DOCUMENT) {
            String tagName = parser.getName();
            
            switch (eventType) {
                case XmlPullParser.START_TAG:
                    if ("item".equals(tagName)) {
                        currentItem = new Item();
                    } else if (currentItem != null) {
                        if ("title".equals(tagName)) {
                            currentItem.setTitle(parser.nextText());
                        } else if ("description".equals(tagName)) {
                            currentItem.setDescription(parser.nextText());
                        } else if ("link".equals(tagName)) {
                            currentItem.setLink(parser.nextText());
                        }
                    }
                    break;
                    
                case XmlPullParser.END_TAG:
                    if ("item".equals(tagName) && currentItem != null) {
                        items.add(currentItem);
                        currentItem = null;
                    }
                    break;
            }
            
            eventType = parser.next();
        }
        
        return items;
    }
    
    // 使用DOM解析
    public static Document parseWithDom(InputStream inputStream) 
            throws ParserConfigurationException, IOException, SAXException {
        DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
        DocumentBuilder builder = factory.newDocumentBuilder();
        return builder.parse(inputStream);
    }
}

网络安全

HTTPS配置

public class HttpsUtils {
    
    // 信任所有证书(仅用于测试)
    public static void trustAllCertificates() {
        try {
            TrustManager[] trustAllCerts = new TrustManager[]{
                new X509TrustManager() {
                    @Override
                    public void checkClientTrusted(X509Certificate[] chain, String authType) {
                    }
                    
                    @Override
                    public void checkServerTrusted(X509Certificate[] chain, String authType) {
                    }
                    
                    @Override
                    public X509Certificate[] getAcceptedIssuers() {
                        return new X509Certificate[0];
                    }
                }
            };
            
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, trustAllCerts, new SecureRandom());
            
            HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
            HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> true);
            
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    // 使用自定义证书
    public static SSLSocketFactory getSSLSocketFactory(Context context, int[] certificates) {
        try {
            CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(null);
            
            for (int i = 0; i < certificates.length; i++) {
                InputStream certificate = context.getResources().openRawResource(certificates[i]);
                keyStore.setCertificateEntry(String.valueOf(i), 
                    certificateFactory.generateCertificate(certificate));
                
                if (certificate != null) {
                    certificate.close();
                }
            }
            
            TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
                TrustManagerFactory.getDefaultAlgorithm());
            trustManagerFactory.init(keyStore);
            
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, trustManagerFactory.getTrustManagers(), new SecureRandom());
            
            return sslContext.getSocketFactory();
            
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        return null;
    }
}

数据加密

public class EncryptionUtils {
    private static final String AES_MODE = "AES/CBC/PKCS7Padding";
    private static final String CHARSET = "UTF-8";
    
    // AES加密
    public static String encrypt(String data, String key, String iv) {
        try {
            Cipher cipher = Cipher.getInstance(AES_MODE);
            SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(CHARSET), "AES");
            IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes(CHARSET));
            
            cipher.init(Cipher.ENCRYPT_MODE, keySpec, ivSpec);
            byte[] encrypted = cipher.doFinal(data.getBytes(CHARSET));
            
            return Base64.encodeToString(encrypted, Base64.NO_WRAP);
            
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    
    // AES解密
    public static String decrypt(String data, String key, String iv) {
        try {
            byte[] encrypted = Base64.decode(data, Base64.NO_WRAP);
            
            Cipher cipher = Cipher.getInstance(AES_MODE);
            SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(CHARSET), "AES");
            IvParameterSpec ivSpec = new IvParameterSpec(iv.getBytes(CHARSET));
            
            cipher.init(Cipher.DECRYPT_MODE, keySpec, ivSpec);
            byte[] decrypted = cipher.doFinal(encrypted);
            
            return new String(decrypted, CHARSET);
            
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    
    // MD5加密
    public static String md5(String input) {
        try {
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] messageDigest = md.digest(input.getBytes());
            
            StringBuilder hexString = new StringBuilder();
            for (byte b : messageDigest) {
                String hex = Integer.toHexString(0xFF & b);
                if (hex.length() == 1) {
                    hexString.append('0');
                }
                hexString.append(hex);
            }
            return hexString.toString();
            
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }
}

性能优化

1. 使用缓存

public class CacheManager {
    private static final long CACHE_SIZE = 10 * 1024 * 1024; // 10MB
    private static final String CACHE_DIR = "http_cache";
    
    public static Cache createCache(Context context) {
        File cacheDir = new File(context.getCacheDir(), CACHE_DIR);
        return new Cache(cacheDir, CACHE_SIZE);
    }
    
    public static OkHttpClient createCachedClient(Context context) {
        return new OkHttpClient.Builder()
            .cache(createCache(context))
            .addNetworkInterceptor(new CacheInterceptor())
            .build();
    }
    
    private static class CacheInterceptor implements Interceptor {
        @Override
        public Response intercept(Chain chain) throws IOException {
            Request request = chain.request();
            
            // 无网络时使用缓存
            if (!isNetworkAvailable()) {
                request = request.newBuilder()
                    .cacheControl(CacheControl.FORCE_CACHE)
                    .build();
            }
            
            Response response = chain.proceed(request);
            
            if (isNetworkAvailable()) {
                // 有网络时缓存60秒
                response = response.newBuilder()
                    .header("Cache-Control", "public, max-age=60")
                    .removeHeader("Pragma")
                    .build();
            } else {
                // 无网络时缓存4周
                response = response.newBuilder()
                    .header("Cache-Control", "public, only-if-cached, max-stale=2419200")
                    .removeHeader("Pragma")
                    .build();
            }
            
            return response;
        }
        
        private boolean isNetworkAvailable() {
            // 检查网络状态
            return true;
        }
    }
}

2. 请求合并和批处理

public class BatchRequestManager {
    private final List<Request> pendingRequests = new ArrayList<>();
    private final Handler handler = new Handler();
    private final Runnable batchRunnable = this::executeBatch;
    private static final long BATCH_DELAY = 100; // 100ms
    
    public void addRequest(Request request) {
        synchronized (pendingRequests) {
            pendingRequests.add(request);
        }
        
        // 延迟执行批处理
        handler.removeCallbacks(batchRunnable);
        handler.postDelayed(batchRunnable, BATCH_DELAY);
    }
    
    private void executeBatch() {
        List<Request> requests;
        synchronized (pendingRequests) {
            requests = new ArrayList<>(pendingRequests);
            pendingRequests.clear();
        }
        
        // 执行批量请求
        for (Request request : requests) {
            // 执行请求
        }
    }
}

3. 图片加载优化

public class ImageLoader {
    private final LruCache<String, Bitmap> memoryCache;
    private final DiskLruCache diskCache;
    
    public ImageLoader(Context context) {
        // 内存缓存
        int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
        int cacheSize = maxMemory / 8;
        
        memoryCache = new LruCache<String, Bitmap>(cacheSize) {
            @Override
            protected int sizeOf(String key, Bitmap bitmap) {
                return bitmap.getByteCount() / 1024;
            }
        };
        
        // 磁盘缓存
        File cacheDir = new File(context.getCacheDir(), "images");
        diskCache = DiskLruCache.open(cacheDir, 1, 1, 50 * 1024 * 1024);
    }
    
    public void loadImage(String url, ImageView imageView) {
        // 先从内存缓存获取
        Bitmap bitmap = memoryCache.get(url);
        if (bitmap != null) {
            imageView.setImageBitmap(bitmap);
            return;
        }
        
        // 从磁盘缓存获取
        bitmap = getBitmapFromDisk(url);
        if (bitmap != null) {
            memoryCache.put(url, bitmap);
            imageView.setImageBitmap(bitmap);
            return;
        }
        
        // 从网络加载
        downloadImage(url, imageView);
    }
    
    private void downloadImage(String url, ImageView imageView) {
        new AsyncTask<Void, Void, Bitmap>() {
            @Override
            protected Bitmap doInBackground(Void... params) {
                try {
                    URL imageUrl = new URL(url);
                    HttpURLConnection conn = (HttpURLConnection) imageUrl.openConnection();
                    conn.setDoInput(true);
                    conn.connect();
                    
                    InputStream input = conn.getInputStream();
                    Bitmap bitmap = BitmapFactory.decodeStream(input);
                    
                    // 保存到缓存
                    memoryCache.put(url, bitmap);
                    saveBitmapToDisk(url, bitmap);
                    
                    return bitmap;
                    
                } catch (IOException e) {
                    e.printStackTrace();
                }
                return null;
            }
            
            @Override
            protected void onPostExecute(Bitmap bitmap) {
                if (bitmap != null) {
                    imageView.setImageBitmap(bitmap);
                }
            }
        }.execute();
    }
}

最佳实践

1. 使用依赖注入

@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
    
    @Provides
    @Singleton
    fun provideOkHttpClient(): OkHttpClient {
        return OkHttpClient.Builder()
            .connectTimeout(30, TimeUnit.SECONDS)
            .readTimeout(30, TimeUnit.SECONDS)
            .addInterceptor(HttpLoggingInterceptor().apply {
                level = HttpLoggingInterceptor.Level.BODY
            })
            .build()
    }
    
    @Provides
    @Singleton
    fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit {
        return Retrofit.Builder()
            .baseUrl("https://api.example.com/")
            .client(okHttpClient)
            .addConverterFactory(GsonConverterFactory.create())
            .build()
    }
    
    @Provides
    @Singleton
    fun provideApiService(retrofit: Retrofit): ApiService {
        return retrofit.create(ApiService::class.java)
    }
}

2. 错误处理

public class ErrorHandler {
    
    public static void handleError(Context context, Throwable error) {
        String message;
        
        if (error instanceof IOException) {
            message = "网络连接失败,请检查网络设置";
        } else if (error instanceof HttpException) {
            HttpException httpException = (HttpException) error;
            switch (httpException.code()) {
                case 401:
                    message = "认证失败,请重新登录";
                    break;
                case 404:
                    message = "请求的资源不存在";
                    break;
                case 500:
                    message = "服务器错误,请稍后重试";
                    break;
                default:
                    message = "请求失败: " + httpException.code();
            }
        } else if (error instanceof JsonSyntaxException) {
            message = "数据解析失败";
        } else {
            message = "未知错误: " + error.getMessage();
        }
        
        Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
    }
}

3. 请求重试

public class RetryInterceptor implements Interceptor {
    private static final int MAX_RETRY = 3;
    private static final long RETRY_DELAY = 1000;
    
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        Response response = null;
        IOException lastException = null;
        
        for (int i = 0; i < MAX_RETRY; i++) {
            try {
                response = chain.proceed(request);
                
                if (response.isSuccessful()) {
                    return response;
                }
                
                // 服务器错误不重试
                if (response.code() >= 500) {
                    return response;
                }
                
            } catch (IOException e) {
                lastException = e;
                
                if (i < MAX_RETRY - 1) {
                    try {
                        Thread.sleep(RETRY_DELAY * (i + 1));
                    } catch (InterruptedException ie) {
                        Thread.currentThread().interrupt();
                    }
                }
            }
        }
        
        if (lastException != null) {
            throw lastException;
        }
        
        return response;
    }
}

调试技巧

1. 使用Charles或Fiddler抓包

// 配置代理
public static OkHttpClient createDebugClient() {
    OkHttpClient.Builder builder = new OkHttpClient.Builder();
    
    if (BuildConfig.DEBUG) {
        // 设置代理
        Proxy proxy = new Proxy(Proxy.Type.HTTP, 
            new InetSocketAddress("192.168.1.100", 8888));
        builder.proxy(proxy);
        
        // 信任所有证书(仅调试使用)
        builder.hostnameVerifier((hostname, session) -> true);
        builder.sslSocketFactory(createInsecureSocketFactory(), 
            createInsecureTrustManager());
    }
    
    return builder.build();
}

2. 网络日志

public class NetworkLogger {
    private static final String TAG = "Network";
    
    public static void logRequest(Request request) {
        Log.d(TAG, "━━━━━━ REQUEST ━━━━━━");
        Log.d(TAG, "URL: " + request.url());
        Log.d(TAG, "Method: " + request.method());
        
        Headers headers = request.headers();
        for (int i = 0; i < headers.size(); i++) {
            Log.d(TAG, headers.name(i) + ": " + headers.value(i));
        }
        
        if (request.body() != null) {
            try {
                Buffer buffer = new Buffer();
                request.body().writeTo(buffer);
                Log.d(TAG, "Body: " + buffer.readUtf8());
            } catch (IOException e) {
                Log.d(TAG, "Body: [Error reading body]");
            }
        }
    }
    
    public static void logResponse(Response response) {
        Log.d(TAG, "━━━━━━ RESPONSE ━━━━━━");
        Log.d(TAG, "Code: " + response.code());
        Log.d(TAG, "Message: " + response.message());
        
        Headers headers = response.headers();
        for (int i = 0; i < headers.size(); i++) {
            Log.d(TAG, headers.name(i) + ": " + headers.value(i));
        }
    }
}

常见问题

1. NetworkOnMainThreadException

问题:在主线程执行网络请求

解决方案:

// 使用AsyncTask
new AsyncTask<Void, Void, String>() {
    @Override
    protected String doInBackground(Void... params) {
        // 网络请求
        return HttpHelper.doGet(url);
    }
    
    @Override
    protected void onPostExecute(String result) {
        // 更新UI
    }
}.execute();

// 或使用协程(Kotlin)
lifecycleScope.launch(Dispatchers.IO) {
    val result = api.getData()
    withContext(Dispatchers.Main) {
        // 更新UI
    }
}

2. SSL证书问题

问题:HTTPS证书验证失败

解决方案:

// 1. 使用正确的证书
// 2. 添加自定义证书到raw目录
// 3. 配置network_security_config.xml

3. 大文件传输

问题:上传/下载大文件时内存溢出

解决方案:

// 使用流式传输
@Streaming
@GET
Call<ResponseBody> downloadFile(@Url String url);

// 分块上传
public void uploadLargeFile(File file) {
    long fileSize = file.length();
    long chunkSize = 1024 * 1024; // 1MB
    long chunks = (fileSize + chunkSize - 1) / chunkSize;
    
    for (int i = 0; i < chunks; i++) {
        // 上传每个块
    }
}

相关文章

总结

Android网络编程是构建现代应用的基础。掌握网络编程需要:

  1. 选择合适的网络库:根据项目需求选择HttpURLConnection、OkHttp或Retrofit
  2. 处理网络权限:正确配置网络权限和安全策略
  3. 数据解析:熟练使用JSON和XML解析
  4. 性能优化:使用缓存、批处理、图片优化等技术
  5. 错误处理:优雅地处理各种网络错误
  6. 安全考虑:使用HTTPS、数据加密保护用户隐私

通过合理使用这些技术,可以构建高效、安全、用户体验良好的网络应用。