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、网络处理时要注意的点
- 申请网络权限
- 异步处理
- 子线程中不能触碰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 可以学习