天天看點

安卓基礎學習 Day21 |網絡程式設計(HTTP)寫在前面的話一、HTTP協定二、通路網絡三、開源項目-網絡請求四、補充

目錄

  • 寫在前面的話
  • 一、HTTP協定
  • 二、通路網絡
    • (一)概述
    • (二)測試-浏覽網絡圖檔
  • 三、開源項目-網絡請求
    • (一)概述
    • (二)測試-AsyncHttpClient+SmartImageView
  • 四、補充

寫在前面的話

1、參考自:https://b23.tv/NwYxbp

2、内容如果有不對的,希望可以指出或補充。

3、新知識。

一、HTTP協定

超文本傳輸協定(Hyper Text Transfer Protocol,HTTP):規定了浏覽器和伺服器間互相通信的規則。是一種請求/響應式(用戶端發送請求,服務端産生響應)的協定。整個響應的過程就是HTTP通信過程。

  • HTTP請求:當用戶端與伺服器建立連接配接後,向伺服器端發送的請求
  • HTTP響應:當伺服器端接收到用戶端的請求後會做出響應,如傳回資料。

二、通路網絡

(一)概述

1、GET和POST

GET請求方式:以實體的方式得到由請求URL所指向的資源資訊,它向伺服器送出的參數跟在(拼接)請求URL後面 [ 浏覽器位址欄中可以看到 ] ,參數和URL間用“?”隔開,每一個參數間用“&”隔開。

使用該方式通路網絡,URL的長度(參數也是)一般需小于1k(1K=1KB=1024Bytes)

注意:使用URLEncoder.encode(“值”)對參數進行URL編碼(因為需要傳到浏覽器位址欄中)。

POST請求方式:向伺服器送出請求時需要在請求後附加實體。它向伺服器送出的參數在請求後的實體中(請求體中),

該方式對URL的長度沒有限制

。采用該方式送出資料時,使用者在浏覽器中看不到向伺服器送出的請求參數,

是以POST方式相較GET方式更安全

無論時GET還是POST都需要注意編碼方式的一緻(用戶端與服務端)。

2、HttpURLConnection通路網絡使用步驟

需要new子線程

從安卓6.0開始,Google已經移除了HttpClient庫的支援,

推薦使用HttpURLConnection

建立url→建立HttpURLConnection對象→設定請求方式、逾時時間(防止連接配接被阻塞時無響應),擷取伺服器傳回的輸入流→關閉HTTP連接配接

3、Handler消息機制

在Android聯網操作中,都是在子線程中

是一種異步回調機制,主要負責主線程(主要就是UI界面)與子線程(耗時的操作)進行通信。其主要對象(四個關鍵對象):

  • Message:消息。
  • Handler:處理者,主要負責Message的發送與處理。
  • MessageQueue:消息隊列,主要用來存放Handler發送過來的消息,并按照

    先入先出

    的規則執行。
  • Looper:消息循環,不斷地從MessageQueue中抽取Message并交給Handler處理。

大概使用流程:Handler發送Message→存入MessageQueue→通過Looper取出Message→Handler處理Message→在HandlerMessage()中進行處理

(二)測試-浏覽網絡圖檔

功能:檢視網絡上的圖檔(使用HttpURLConnection的GET請求擷取網絡圖檔)。

1 依賴-項目清單檔案

安卓基礎學習 Day21 |網絡程式設計(HTTP)寫在前面的話一、HTTP協定二、通路網絡三、開源項目-網絡請求四、補充

2 布局

安卓基礎學習 Day21 |網絡程式設計(HTTP)寫在前面的話一、HTTP協定二、通路網絡三、開源項目-網絡請求四、補充

2 主要代碼

MainActivity.java

package com.example.testhttp;

import androidx.appcompat.app.AppCompatActivity;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.text.TextUtils;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.Toast;

import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;

public class MainActivity extends AppCompatActivity {

    private static final int CHANGE_UI = 1;//建立常量
    private static final int ERROR = 2;

    private HttpURLConnection conn;

    private EditText testEd;
    private ImageView testImg;
    //在主線程建立消息處理器Handler
    private Handler handler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            if(msg.what == CHANGE_UI){
                Bitmap bitmap = (Bitmap) msg.obj;
                testImg.setImageBitmap(bitmap);//
            }else if(msg.what == ERROR){
                Toast.makeText(MainActivity.this,"顯示錯誤",Toast.LENGTH_SHORT).show();
            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        //擷取控件
        testEd = findViewById(R.id.test_ed);
        testImg = findViewById(R.id.test_img);
    }

    public void test(View view){
        //擷取到輸入位址
        String path = testEd.getText().toString().trim();
        //判斷輸入是否為空
        if(TextUtils.isEmpty(path)){
            Toast.makeText(this,"不能為空",Toast.LENGTH_SHORT).show();
        }else {

            //在子線程中請求網絡
            new Thread(){ //開啟一個線程
                private Bitmap bitmap;

                @Override
                public void run() {
                    //連接配接伺服器GET請求擷取到圖檔
                    try {
                        URL url = new URL(path);//建立url
                        //根據url發送HTTP請求
                        conn = (HttpURLConnection) url.openConnection();
                        //設定
                        conn.setRequestMethod("GET");//請求方式
                        conn.setConnectTimeout(5000);//逾時時間5秒
                        int code = conn.getResponseCode();//得到服務端傳回的響應碼
                        //請求網絡成功的傳回碼為200
                        if(code == 200){
                            //擷取輸入流,裡面就是想要的資訊
                            InputStream is = conn.getInputStream();
                            //is轉換為Bitmap對象
                            bitmap = BitmapFactory.decodeStream(is);

                            ///将更改主界面的消息發送給主線程
                            Message msg = new Message();
                            msg.what = CHANGE_UI;//用于區分不同的消息
                            msg.obj = bitmap;//攜帶對應的資料
                            handler.sendMessage(msg);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        Message msg = new Message();
                        msg.what = ERROR;
                        handler.sendMessage(msg);
                    }
                    ///關閉連接配接
                    conn.disconnect();
                }
            }.start();

        }
    }
}
           

3 效果展示

運作結果如下。

安卓基礎學習 Day21 |網絡程式設計(HTTP)寫在前面的話一、HTTP協定二、通路網絡三、開源項目-網絡請求四、補充

三、開源項目-網絡請求

Day22内容。

(一)概述

1、AsyncHttpClient

AsyncHttpClient:Async就是異步的意思。可以處理異步(多條線程中處理任務)HTTP請求,也就是

會自動開啟一個子線程

,并通過匿名内部類處理回調結果。将對應的方法做了封裝。需要導入。

HTTP異步請求都是位于非UI線程中,不會阻塞UI操作,AsyncHttpClient通過線程池處理并發請求,處理檔案上傳、下載下傳,

響應結果自動成JSON格式

AsyncHttpClient常用類:

  • AsyncHttpClient:異步用戶端請求的類,提供了get、put、post、delete、head等請求方法。
  • AsyncHttpResponseHandler:繼承自ResponseHandlerInterface。是通路網絡後回調的接口,接收請求結果,如果通路成功則回調其中的OnSucess方法,否則回調OnFailure方法。
2、SmartImageView元件

SmartImageView:主要用于加速從網絡上加載圖檔,它繼承自Android自帶的ImageView元件。需要導入也需要布局。

(二)測試-AsyncHttpClient+SmartImageView

功能:解析伺服器上的JSON檔案并将其顯示到ListView控件上。

1、依賴

SmartImageView的jar包下載下傳

安卓基礎學習 Day21 |網絡程式設計(HTTP)寫在前面的話一、HTTP協定二、通路網絡三、開源項目-網絡請求四、補充

對應的build.gradle檔案

安卓基礎學習 Day21 |網絡程式設計(HTTP)寫在前面的話一、HTTP協定二、通路網絡三、開源項目-網絡請求四、補充

清單檔案

安卓基礎學習 Day21 |網絡程式設計(HTTP)寫在前面的話一、HTTP協定二、通路網絡三、開源項目-網絡請求四、補充
2、Tomcat伺服器

① 配置伺服器

下載下傳apache-tomcat-8.5.61.zip

安卓基礎學習 Day21 |網絡程式設計(HTTP)寫在前面的話一、HTTP協定二、通路網絡三、開源項目-網絡請求四、補充

② 啟動伺服器

安卓基礎學習 Day21 |網絡程式設計(HTTP)寫在前面的話一、HTTP協定二、通路網絡三、開源項目-網絡請求四、補充

③ 測試

安卓基礎學習 Day21 |網絡程式設計(HTTP)寫在前面的話一、HTTP協定二、通路網絡三、開源項目-網絡請求四、補充
3、布局

test_activity.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">
    <!--嵌套部分-->
    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">
        <!--進度條部分-->
        <LinearLayout
            android:id="@+id/show_loading"

            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center"
            android:orientation="vertical"
            android:visibility="visible">
            <!--進度條-->
            <ProgressBar
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"/>
            <TextView
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="正在加載中..."/>
        </LinearLayout>
        <!--展示部分ListView-->
        <ListView
            android:id="@+id/show_news"

            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_marginTop="10dp"/>
    </FrameLayout>

</LinearLayout>
           

test_item.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="70dp">
    <!--加載圖檔部分-->
    <com.loopj.android.image.SmartImageView
        android:id="@+id/item_img"

        android:layout_width="80dp"
        android:layout_height="60dp"

        android:layout_alignParentLeft="true"
        android:layout_marginLeft="5dp"
        android:layout_centerInParent="true"

        android:scaleType="centerCrop"
        android:src="@mipmap/ic_launcher"/>
    <!--文本部分-->
    <TextView
        android:id="@+id/item_title"

        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="5dp"
        android:layout_marginTop="10dp"
        android:layout_toRightOf="@id/item_img"

        android:text="标題"
        android:textColor="@color/black"
        android:textSize="18sp" />

    <TextView
        android:id="@+id/item_text"

        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/item_title"
        android:layout_toRightOf="@id/item_img"
        android:layout_marginLeft="5dp"
        android:layout_marginTop="5dp"

        android:text="描述"
        android:textSize="14sp" />

    <TextView
        android:id="@+id/item_talk"

        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:layout_alignParentRight="true"
        android:layout_marginBottom="5dp"
        android:layout_marginRight="10dp"

        android:text="評論"
        android:textSize="12sp"
        android:layout_marginLeft="60dp"
        android:layout_gravity="bottom"
        android:textColor="#aaaaaa"/>
</RelativeLayout>

           
4、代碼

NewsInfo.java

package com.example.testhttp;

//JSON資料内容
public class NewsInfo {
    //字段名與JSON檔案資料字段一緻
    private String icon;//圖檔路徑
    private String title;//标題
    private String content;//描述的内容
    private int type;//類型
    private long comment;//評論數

    public NewsInfo(String icon, String title, String content, int type, long comment) {
        this.icon = icon;
        this.title = title;
        this.content = content;
        this.type = type;
        this.comment = comment;
    }

    public String getIcon() {
        return icon;
    }

    public void setIcon(String icon) {
        this.icon = icon;
    }

    public String getTitle() {
        return title;
    }

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

    public String getContent() {
        return content;
    }

    public void setContent(String content) {
        this.content = content;
    }

    public int getType() {
        return type;
    }

    public void setType(int type) {
        this.type = type;
    }

    public long getComment() {
        return comment;
    }

    public void setComment(long comment) {
        this.comment = comment;
    }
}

           

JsonParse.java

安卓基礎學習 Day21 |網絡程式設計(HTTP)寫在前面的話一、HTTP協定二、通路網絡三、開源項目-網絡請求四、補充

為了友善以後更改,做如下的添加。

安卓基礎學習 Day21 |網絡程式設計(HTTP)寫在前面的話一、HTTP協定二、通路網絡三、開源項目-網絡請求四、補充

Test2.java

package com.example.testhttp;

import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.AsyncHttpResponseHandler;
import com.loopj.android.image.SmartImageView;

import java.util.List;

import cz.msebera.android.httpclient.Header;

public class Test2 extends AppCompatActivity {
    //test_activity
    private LinearLayout showLoading;
    private ListView showNews;
    //test_item
    private SmartImageView itemImg;
    private TextView itemTitle,itemText,itemTalk;

    private List<NewsInfo> newsInfoList;//聲明集合
    private NewsInfo newsInfo;

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

        //擷取到控件
        showLoading = findViewById(R.id.show_loading);
        showNews = findViewById(R.id.show_news);
        //填充資料
        fillData();//調用
    }

    //使用AsyncHttpClient通路網絡
    private void fillData() {
        //建立AsyncHttpClient對象
        AsyncHttpClient client = new AsyncHttpClient();

        //預設為GET請求方式
        client.get(getString(R.string.server_url), new AsyncHttpResponseHandler() {

            @Override
            //請求成功
            public void onSuccess(int statusCode, Header[] headers, byte[] responseBody) {
                try {
                    //調用JsonParse工具類解析JSON檔案資料
                    String json = new String(responseBody, "utf-8");//轉換為json資料
                    newsInfoList = JsonParse.getNewsInfo(json);

                    if (newsInfoList == null) {
                        Toast.makeText(Test2.this, "解析失敗", Toast.LENGTH_SHORT).show();
                    } else {
                        //更新界面
                        Handler handler = new Handler();
                        handler.postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                showLoading.setVisibility(View.INVISIBLE);//進度條改成不顯示
                                showNews.setAdapter(new NewsAdapter());//展示
                            }
                        },5000);//5秒後執行
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onFailure(int statusCode, Header[] headers, byte[] responseBody, Throwable error) {
                Toast.makeText(Test2.this, "請求失敗", Toast.LENGTH_SHORT).show();
            }

        });
    }

    //ListView擴充卡
    private class NewsAdapter extends BaseAdapter {

        //條目對象
        @Override
        public Object getItem(int position) {
            return null;
        }

        //條目id
        @Override
        public long getItemId(int position) {
            return 0;
        }

        @Override
        //listview的條目數
        public int getCount() {
            return newsInfoList.size();
        }

        @Override
        //擷取到條目資訊view
        public View getView(int position, View convertView, ViewGroup parent) {

            View view = View.inflate(Test2.this, R.layout.test_item, null);

            //擷取控件
            itemImg = view.findViewById(R.id.item_img);
            itemTitle = view.findViewById(R.id.item_title);
            itemText = view.findViewById(R.id.item_text);
            itemTalk = view.findViewById(R.id.item_talk);
            newsInfo = newsInfoList.get(position);//擷取到要顯示的資料

            //SmartImageView加載指定路徑的圖檔
            //參數1:具體路徑,參數2、3:顯示成功/失敗加載的圖檔
            itemImg.setImageUrl(newsInfo.getIcon(), R.mipmap.ic_launcher, R.mipmap.ic_launcher);
            //設定标題
            itemTitle.setText(newsInfo.getTitle());
            //設定描述文字
            itemText.setText(newsInfo.getContent());

            //設定類型
            int type = newsInfo.getType();
            switch (type) {
                //不同新聞類型設定不同的顔色和不同的内容
                //其他的則是預設的文字内容
                case 1:
                    itemTalk.setText("評論數:" + newsInfo.getComment());
                    break;
                case 2:
                    //紅色的專題文字
                    itemTalk.setTextColor(Color.RED);
                    itemTalk.setText("專題新聞");
                    break;
                case 3:
                    itemTalk.setTextColor(Color.BLUE);
                    itemTalk.setText("LIVE");
                    break;
            }
            return view;//傳回條目資訊
        }

    }
}

           
5、效果展示

運作結果如下。

安卓基礎學習 Day21 |網絡程式設計(HTTP)寫在前面的話一、HTTP協定二、通路網絡三、開源項目-網絡請求四、補充

四、補充

1、com.google.gson.stream.MalformedJsonException報錯的解決辦法

我發生的問題是源自JSON資料的問題,格式多了個在“}”前多了個“,”。