【Android】网络编程数据处理

1、需要申请权限

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

2、写一版简单的程序(在主线程中网络请求,会报错)

java:

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import org.w3c.dom.Text;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

public class NetworkActivity extends AppCompatActivity implements View.OnClickListener{
    
    

    EditText mEditText;
    TextView mTextView;
    Button mButton;

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

        findViews();
        setListeners();

        String url = getEditTextUrl();

    }

    private void setListeners() {
    
    
        mButton.setOnClickListener(this);
    }

    private void findViews() {
    
    
        mEditText = findViewById(R.id.edittext_network);
        mTextView = findViewById(R.id.textview_network);
        mButton = findViewById(R.id.button_network);
    }

    @Override
    public void onClick(View v) {
    
    
        switch (v.getId()){
    
    
            case R.id.button_network:
                String url = getEditTextUrl();

                // 请求网络数据
                String data = requestData(url);
                mTextView.setText(data);
                break;

        }
    }

    private String requestData(String urlString) {
    
    
        try {
    
    
            URL url = new URL(urlString);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setConnectTimeout(30000);//半分钟之内没有返回超时
            connection.setRequestMethod("GET");//方法
            connection.connect();
            int responseCode = connection.getResponseCode();//状态码
            String responseMessage = connection.getResponseMessage();//消息
            InputStream inputStream = connection.getInputStream();//输入流
            Reader reader = new InputStreamReader(inputStream, "UTF-8");
            char[] buffer = new char[1024];
            reader.read(buffer);
            String content = new String(buffer);
            return content;

        } catch (MalformedURLException e) {
    
    
            e.printStackTrace();
            Toast.makeText(NetworkActivity.this, "非法url", Toast.LENGTH_SHORT).show();
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
        return null;
    }

    private String getEditTextUrl() {
    
    
        return mEditText != null ? mEditText.getText().toString() : "";
    }
}

xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".NetworkActivity">

    <EditText
        android:id="@+id/edittext_network"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="请输入网址"
        android:layout_gravity="center_horizontal"/>
    <Button
        android:id="@+id/button_network"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="获取数据"
        android:layout_gravity="center_horizontal"/>
    <TextView
        android:id="@+id/textview_network"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="this is result"/>
</LinearLayout>

在输入框输入http://www.baidu.com后,点获取数据按钮,闪退。
报错信息如下,主要是NetworkOnMainThreadException,意思是不能在主线程中进行网络请求。

2020-10-13 21:09:16.884 20915-20915/? E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.dj.aboutactivity, PID: 20915
    android.os.NetworkOnMainThreadException

3、改进成异步处理,用到AsyncTask

import androidx.appcompat.app.AppCompatActivity;

import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

import org.w3c.dom.Text;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

public class NetworkActivity extends AppCompatActivity implements View.OnClickListener{
    
    

    EditText mEditText;
    TextView mTextView;
    Button mButton;

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

        findViews();
        setListeners();

        String url = getEditTextUrl();

    }

    private void setListeners() {
    
    
        mButton.setOnClickListener(this);
    }

    private void findViews() {
    
    
        mEditText = findViewById(R.id.edittext_network);
        mTextView = findViewById(R.id.textview_network);
        mButton = findViewById(R.id.button_network);
    }

    @Override
    public void onClick(View v) {
    
    
        switch (v.getId()){
    
    
            case R.id.button_network:
                String url = getEditTextUrl();

                // 请求网络数据
                new RequestNetworkDataTask().execute(url);

                break;
        }
    }

    private String requestData(String urlString) {
    
    
        try {
    
    
            URL url = new URL(urlString);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setConnectTimeout(30000);//半分钟之内没有返回超时
            connection.setRequestMethod("GET");//方法
            connection.connect();
            int responseCode = connection.getResponseCode();//状态码
            String responseMessage = connection.getResponseMessage();//消息
            InputStream inputStream = connection.getInputStream();//输入流
            Reader reader = new InputStreamReader(inputStream, "UTF-8");
            char[] buffer = new char[1024];
            reader.read(buffer);
            String content = new String(buffer);
            return content;

        } catch (MalformedURLException e) {
    
    
            e.printStackTrace();
            //Toast.makeText(NetworkActivity.this, "非法url", Toast.LENGTH_SHORT).show(); // 线程中运行这句话会闪退
        } catch (IOException e) {
    
    
            e.printStackTrace();
        }
        return null;
    }

    private String getEditTextUrl() {
    
    
        return mEditText != null ? mEditText.getText().toString() : "";
    }


    // 异步任务处理
    class RequestNetworkDataTask extends AsyncTask<String, Integer, String>{
    
    

        // 在后台work之前
        @Override
        protected void onPreExecute() {
    
    
            super.onPreExecute();
            // 主线程
            // UI Loading 那个圆圈
        }

        // 后台操作中
        @Override
        protected String doInBackground(String[] params) {
    
    
            String result = requestData(params[0]);
            return result;
        }

        // 在后台work之后

        @Override
        protected void onPostExecute(String result) {
    
    
            super.onPostExecute(result);
            //执行完之后在主线程中

            mTextView.setText(result);
        }

        // 取消

        @Override
        protected void onCancelled() {
    
    
            super.onCancelled();
        }

        // 更新

        @Override
        protected void onProgressUpdate(Integer... values) {
    
    
            super.onProgressUpdate(values);
        }
    }
}

4、网络处理时要注意的点

  1. 申请网络权限
  2. 异步处理
  3. 子线程中不能触碰UI

5、请求结果的处理

5-1 xml解析

比json耗空间,较少用了

解析方式1:SAX
SAXParseHandler.java

package com.dj.aboutactivity.xml;

import android.text.TextUtils;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import java.util.ArrayList;
import java.util.List;

public class SAXParseHandler extends DefaultHandler {
    
    


    public static final String ITEM = "item";
    private List<WebURL> mWebURLs;
    WebURL mWebURL;

    boolean mIsItem = false;

    @Override
    public void startDocument() throws SAXException {
    
    
        super.startDocument();
        mWebURLs = new ArrayList<>();//文档开始的时候,要新建一个ArrayList
    }

    @Override
    public void endDocument() throws SAXException {
    
    
        super.endDocument();

    }

    // 元素开始解析的时候
    @Override
    public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException {
    
    
        super.startElement(uri, localName, qName, attributes);
        mWebURL = new WebURL();
        if(TextUtils.equals(localName, ITEM)){
    
    //localName是item,attributes是属性(id,web等)
            for(int i=0;i<attributes.getLength();++i){
    
    
                if(TextUtils.equals(attributes.getLocalName(i), "id")){
    
    
                    mWebURL.setID(Integer.parseInt(attributes.getValue(i)));
                }
            }
            mIsItem = true;
        }
        mIsItem = false;
    }

    @Override
    public void endElement(String uri, String localName, String qName) throws SAXException {
    
    
        super.endElement(uri, localName, qName);
        if(TextUtils.equals(localName, ITEM)){
    
    
            mWebURLs.add(mWebURL);//添加到链表中
        }
    }

    @Override
    public void characters(char[] ch, int start, int length) throws SAXException {
    
    
        super.characters(ch, start, length);
        String content = String.valueOf(ch, start, length);//读出来百度,淘宝等字样

        if(mIsItem){
    
    
            mWebURL.setContent(content);
            mIsItem = false;
        }

    }

    public List<WebURL> getXMLList(){
    
    
        return mWebURLs;
    }
}

使用也非常简单:

 void testSAXParse() throws ParserConfigurationException, SAXException, IOException {
    
    
        SAXParserFactory saxParserFactory = SAXParserFactory.newInstance();
        SAXParser saxParser = saxParserFactory.newSAXParser();
        XMLReader xmlReader = saxParser.getXMLReader();

        SAXParseHandler saxParseHandler = new SAXParseHandler();
        xmlReader.setContentHandler(saxParseHandler);

        InputStream inputStream = getResources().openRawResource(R.raw.test);

        InputSource inputSource = new InputSource(inputStream);//把流给它

        xmlReader.parse(inputSource);

        saxParseHandler.getXMLList();
}

或者更简单的版本:
只是以上内容的简写,实质相同

XMLReader xmlReaderTest = SAXParserFactory.newInstance().newSAXParser().getXMLReader();
xmlReaderTest.setContentHandler(new SAXParseHandler());
xmlReaderTest.parse(new InputSource(getResources().openRawResource(R.raw.test)));

解析方式2:pull
是Android官方使用的解析方法,Activity中解析xml用的pull方法。
要注意,xml文件位置应放在res下的xml文件夹里(没有就新建)。

// pull解析  xml里面才能读到
XmlResourceParser xmlResourceParser = getResources().getXml(R.xml.test);

try {
    
    
    while(xmlResourceParser.getEventType() != XmlResourceParser.END_DOCUMENT){
    
    
        if(xmlResourceParser.getEventType() == XmlResourceParser.START_TAG){
    
    
            String tagName = xmlResourceParser.getName();
            if(TextUtils.equals(tagName, "item")){
    
    
                String id = xmlResourceParser.getAttributeNamespace(0);
            }
        }
    }
} catch (XmlPullParserException e) {
    
    
    e.printStackTrace();
}

解析方式3:DOM
这种方式与前面两者都不同,sax和pull是逐个标签读入,而DOM是一次性读入整个xml文件,所以只适合读入小文件,不适合读大文件。

5-2 json解析

好的网站:https://jsonlint.com/,该网站可以自动调整json文件格式

1、直接用原生方法

// json
InputStream is = getResources().openRawResource(R.raw.json);// 获得输入流
String jsonString = getStringByInputStream();//从输入流获得字符串
try {
    
    
    JSONObject jsonObject = new JSONObject(jsonString);//new一个json对象,把字符串传入
    String title = jsonObject.getString("title");//获得字符串类型的数据,标识是“title”
    JSONObject userJSONObject = jsonObject.getJSONObject("user");//获得json对象,标识是“user”
    userJSONObject.getLong("id");//获得数字,标识是“id”
    JSONArray jsonArray = jsonObject.getJSONArray("images");//获得数组,标识是“images”
} catch (JSONException e) {
    
    
    e.printStackTrace();
}

对应的文件放在raw文件夹下,json.txt:

{
    
    
	"user": {
    
    
		"id": 100001,
		"name": "dj",
		"activate": "https://blog.csdn.net/qq_30885821"
	},
	"title": "please read my articles!",
	"content": "just so so",
	"images": [
		"https://blog.csdn.net/qq_30885821/article/details/108228900",
		"https://blog.csdn.net/qq_30885821/article/details/106733930",
		"https://blog.csdn.net/qq_30885821/article/details/108805633"
	],
	"block": "博客阅读",
	"discussNumber": "1010",
	"datetime": "2020-10-17 14:16:32"
}

2、使用GSON

project structure——dependencies——选择当前Moudle——点加号——选第1 个Add Library Dependency——输入gson,search——OK
此时在build.gradle中就有了implementation 'com.google.code.gson:gson:2.8.6'

使用方法简单,一步到位,将json数据转换为对象:

// gson 
Gson gson = new Gson();
UserData userData = gson.fromJson(jsonString, UserData.class);

前提是要构建UserData类:

package com.dj.aboutactivity.json;

import com.google.gson.annotations.SerializedName;

import java.util.List;

public class UserData {
    
    

    @SerializedName("title")
    private String mTitle;

    @SerializedName("content")
    private String mContent;

    @SerializedName("user")
    private User mUser;

    @SerializedName("images")
    private List<String> mImages;

    // get & set methods
    public String getTitle() {
    
    
        return mTitle;
    }

    public void setTitle(String title) {
    
    
        mTitle = title;
    }

    public String getContent() {
    
    
        return mContent;
    }

    public void setContent(String content) {
    
    
        mContent = content;
    }

    public User getUser() {
    
    
        return mUser;
    }

    public void setUser(User user) {
    
    
        mUser = user;
    }

    public List<String> getImages() {
    
    
        return mImages;
    }

    public void setImages(List<String> images) {
    
    
        mImages = images;
    }


    // 用户子类
    public class User{
    
    
        @SerializedName("id")
        private long mId;

        @SerializedName("name")
        private String mName;

        @SerializedName("avatar")
        private String mAvatar;
    }
}

3、获取网络状态

利用ConnectivityManager和NetworkInfo:

package com.dj.aboutactivity;

import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;

public class NetWorkUtil {
    
    
    public void testNetwork(Context context){
    
    
        ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI);

        boolean ifWifiConnected = networkInfo.isConnected();
        networkInfo = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
        boolean isMobileConnection = networkInfo.isConnected();
    }

    public boolean isOnline(Context context){
    
    
        ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
        return (networkInfo != null && networkInfo.isConnected());
    }
}

4、其他常用开源库

android-async-http
volly
OKHttp
RetroFit

5、小技巧

Postman,帮你与后台交互,下面几条教程一条比一条牛:
https://www.jianshu.com/p/549ff9f922d6
https://blog.csdn.net/u013613428/article/details/51557804
https://blog.csdn.net/fxbin123/article/details/80428216

另有Restful 可以学习

猜你喜欢

转载自blog.csdn.net/qq_30885821/article/details/109018464