Android入门(15)| 网络


WebView

WebView 可以在 应用程序中(而不是浏览器) 展示一些网页。

布局文件 web_layout.xml

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <WebView
        android:id="@+id/web_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>

活动文件:

public class WebActivity extends AppCompatActivity {
    
    

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

        WebView webView = findViewById(R.id.web_view);
        // 使WebView支持JavaScript脚本
        webView.getSettings().setJavaScriptEnabled(true);
        // 用当前WebView显示网页而不是浏览器
        webView.setWebViewClient(new WebViewClient());
        webView.loadUrl("https://www.bilibili.com/");
    }
}

要在 Android 中使用网络技术是需要在 AndroidManifest.xml 中声明权限的:

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

运行结果:
在这里插入图片描述


HTTP

使用HttpURLConnection

布局文件 http_layout.xml

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/button_sendRequest"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="发送请求"/>

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/response_text"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"/>
    </ScrollView>

</LinearLayout>
  • ScrollView控件: 以滚动形式查看屏幕外的内容。
  • TextView控件: 用以显示服务器返回的数据。

活动文件:

public class HTTPActivity extends AppCompatActivity {
    
    
    private static final String TAG = "HTTPActivity";
    TextView responseText;

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

        Button button_sendRequest = findViewById(R.id.button_sendRequest);
        responseText = findViewById(R.id.response_text);
        button_sendRequest.setOnClickListener(v->{
    
    
            sendRequestWithHttpURLConnection();
            Log.e(TAG, "click over");
        });
    }

    private void sendRequestWithHttpURLConnection() {
    
    
        // 开启子线程来发起网络请求
        new Thread(new Runnable() {
    
    
            @Override
            public void run() {
    
    
                HttpURLConnection connection = null;
                BufferedReader reader = null;
                try {
    
    
                    URL url = new URL("https://www.csdn.net/");

                    connection = (HttpURLConnection) url.openConnection();
                    connection.setRequestMethod("GET");
                    connection.setConnectTimeout(8000);
                    connection.setReadTimeout(8000);

                    InputStream in = connection.getInputStream();
                    Log.e(TAG, "get in");
                    // 下面对获取到的输入流进行读取
                    reader = new BufferedReader(new InputStreamReader(in));
                    StringBuilder response = new StringBuilder();
                    String line;
                    while((line = reader.readLine()) != null){
    
    
                        response.append(line);
                    }
                    Log.e(TAG, "run: "+response.toString());

                    // 安卓不允许在子线程中进行UI操作
                    // 通过runOnUiThread切换为主线程,然后将结果显示到界面中
                    runOnUiThread(new Runnable() {
    
    
                        @Override
                        public void run() {
    
    
                            responseText.setText(response.toString());
                        }
                    });
                } catch (Exception e) {
    
    
                    e.printStackTrace();
                } finally {
    
    
                    if(reader != null){
    
    
                        try {
    
    
                            reader.close();
                        } catch (IOException e){
    
    
                            e.printStackTrace();
                        }
                    }
                    if(connection != null){
    
    
                        connection.disconnect();
                    }
                }
            }
        }).start();
    }
}

运行结果:
在这里插入图片描述


使用OkHttp

OkHttp项目在github上的主页地址

build.gradle (:app) 文件的 dependencies 中添加依赖:

	// define a BOM and its version
    implementation(platform("com.squareup.okhttp3:okhttp-bom:4.9.3"))
    // define any required OkHttp artifacts without version
    implementation("com.squareup.okhttp3:okhttp")

活动文件:

public class HTTPActivity extends AppCompatActivity {
    
    
    private static final String TAG = "HTTPActivity";
    TextView responseText;

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

        Button button_sendRequest = findViewById(R.id.button_sendRequest);
        responseText = findViewById(R.id.response_text);
        button_sendRequest.setOnClickListener(v->{
    
    
            sendRequestWithOkHttp();
            Log.e(TAG, "click over");
        });
    }

    private void sendRequestWithOkHttp() {
    
    
        // 开启子线程来发起网络请求
        new Thread(new Runnable() {
    
    
            @Override
            public void run() {
    
    
                try {
    
    
                    OkHttpClient client = new OkHttpClient();
                    Request request = new Request.Builder()
                            .url("https://www.bilibili.com")
                            .build();
                    Log.e(TAG, "request: "+request);
                    Response response = client.newCall(request).execute();
                    Log.e(TAG, "response: "+response);
                    String responseData = response.body().string();
                    Log.e(TAG, "responseData: "+responseData);
                    runOnUiThread(new Runnable() {
    
    
                        @Override
                        public void run() {
    
    
                            responseText.setText(responseData);
                        }
                    });
                } catch (IOException e) {
    
    
                    e.printStackTrace();
                }
            }
        }).start();
    }
}

运行结果:
在这里插入图片描述


封装网络操作

封装HttpURLConnection

如果在每个使用到网络功能的地方都实现一遍发送HTTP请求的代码无疑是繁琐的。因此,不妨将常用的网络操作写成一个个静态方法,并将它们都存储在一个类中,如:

public class HttpUtil {
    
    
    private static final String TAG = "HttpUtil";

    public static String sendHttpRequest(String address){
    
    
        HttpURLConnection connection = null;
        try {
    
    
        	URL url =new URL(address);
            connection = (HttpURLConnection) url.openConnection();
            connection.setRequestMethod("GET");
            connection.setConnectTimeout(8000);
            connection.setReadTimeout(8000);
            connection.setDoInput(true);
            connection.setDoOutput(true);

            InputStream in = connection.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(in));
            StringBuilder response = new StringBuilder();
            String line;
            while((line = reader.readLine()) != null){
    
    
            	response.append(line);
            }
            return response.toString();
        } catch (Exception e) {
    
    
        	e.printStackTrace();
        	return e.getMessage();
        } finally {
    
    
            if(connection != null){
    
    
            	connection.disconnect();
            }
        }
    }
}

如此一来需要发送HTTP请求时即可如此实现:

String url = "https://www.bilibili.com";
String response = HttpUtil.sendHttpRequest(url);

但这仍有缺陷,sendHttpRequest() 方法内部并没有使用子线程,这意味着调用该方法时主线程有可能被阻塞,网络请求又是耗时操作,这对于运行效率而言无疑是种灾难。

而如果只是简单地在 sendHttpRequest() 方法中开启一个线程来发起HTTP请求,那么所有的耗时逻辑都是在子线程里进行的,sendHttpRequest() 方法会在 服务器还没来得及响应 的时候就执行结束了(子线程中的逻辑还没有执行完,主线程中已经结束了对sendHttpRequest() 方法的调用)。

因此应该配以回调机制来接受回馈数据,定义一个接口:

public interface HttpCallbackListener {
    
    
    // 成功响应时回调,参数为服务器返回的数据
    void onFinish(String response);
    // 操作错误时回调
    void onError(Exception e);
}

然后修改 HttpUtil.java

public class HttpUtil {
    
    
    private static final String TAG = "HttpUtil";

    public static void sendHttpRequest(final String address, HttpCallbackListener listener){
    
    
        new Thread(new Runnable() {
    
    
            @Override
            public void run() {
    
    
                HttpURLConnection connection = null;
                try {
    
    
                    URL url =new URL(address);
                    connection = (HttpURLConnection) url.openConnection();
                    connection.setRequestMethod("GET");
                    connection.setConnectTimeout(8000);
                    connection.setReadTimeout(8000);
                    connection.setDoInput(true);
                    connection.setDoOutput(true);

                    InputStream in = connection.getInputStream();
                    BufferedReader reader = new BufferedReader(new InputStreamReader(in));
                    StringBuilder response = new StringBuilder();
                    String line;
                    while((line = reader.readLine()) != null){
    
    
                        response.append(line);
                    }
                    
                    // 子线程中无法通过 return 返回数据,应通过 onFinish 方法回调
                    if(listener != null){
    
    
                        listener.onFinish(response.toString());
                        Log.e(TAG, "run: "+response.toString());
                    }
                } catch (Exception e) {
    
    
                    if(listener != null){
    
    
                        listener.onError(e);
                        Log.e(TAG, "run: Exception");
                    }
                } finally {
    
    
                    if(connection != null){
    
    
                        connection.disconnect();
                    }
                }
            }
        }).start();
    }
}

此时我们调用 sendHttpRequest() 方法时需要将 HttpCallbackListener 的实例传入:

    private void sendRequestWithOkHttp() {
    
    
        // 开启子线程来发起网络请求
        new Thread(new Runnable() {
    
    
            @Override
            public void run() {
    
    
                String url = "https://www.baidu.com";
                HttpUtil.sendHttpRequest(url, new HttpCallbackListener() {
    
    
                    @Override
                    public void onFinish(String response) {
    
    
                        runOnUiThread(new Runnable() {
    
    
                            @Override
                            public void run() {
    
    
                                responseText.setText(response);
                            }
                        });

                    }

                    @Override
                    public void onError(Exception e) {
    
    
                        Log.e(TAG, "onError: "+e);
                    }
                });
            }
        }).start();
    }

运行结果:
在这里插入图片描述


封装OkHttp

封装关于HTTP的操作:

public class HttpUtil {
    
    
    private static final String TAG = "HttpUtil";

    public static void sendHttpRequest(final String address, okhttp3.Callback callback){
    
    
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url(address)
                .build();
        Log.e(TAG, "request: "+request);
        client.newCall(request).enqueue(callback);
    }
}

调用 HttpUtil.sendHttpRequest() 发送请求的方法:

    // 开启子线程来发起网络请求,OkHttp
    private void sendRequestWithOkHttp(){
    
    
        new Thread(new Runnable() {
    
    
            @Override
            public void run() {
    
    
                HttpUtil.sendHttpRequest("https://www.bilibili.com", new okhttp3.Callback(){
    
    

                    @Override
                    public void onResponse(Call call, Response response) throws IOException {
    
    
                        String responseData = response.body().string();
                        runOnUiThread(new Runnable() {
    
    
                            @Override
                            public void run() {
    
    
                                responseText.setText(responseData);
                            }
                        });
                    }

                    @Override
                    public void onFailure(Call call, IOException e) {
    
    
                        Log.e(TAG, "onError: "+e);
                    }
                });
            }
        }).start();
    }

PS: 不论是使用 HttpURLConnection 还是 OkHttp最终的回调接口都还是在子线程中,因此如果想要执行 UI 操作必须借助 runOnUiThread() 方法进行线程转换。

运行结果:
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/Jormungand_V/article/details/123319755
今日推荐