天天看点

安卓基础学习 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数据的问题,格式多了个在“}”前多了个“,”。