一个轻量级的网络架构

本文详细介绍了如何在Android项目中创建自定义网络架构,包括访问接口的方式、数据缓存策略以及异常处理流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目前,Android有许多开源的网络架构,比如官方的volley。今天我讲一下如何去创建自己的网络架构。

首先,要考虑的是用起来方便,大部分的工作都在底层完成。其次,考虑缓存,不同的接口数据可以配置不同的缓存时间。最重要的是,同一个接口,不同参数时的缓存。

下面就是根据我们的项目定制的网络架构:

后端数据采用json传递给APP,APP调用接口的方式,采用URL直接拼接参数和JSON传递参数。

后端约定数据格式JSON: {data:"data",status:0,message:"OK"}

data里面是所需要的数据

status状态码,0表示正常返回;1,用户信息错误照成的错误,此时message里面提示信息直接展示给用户(比如密码不正确);

            其他,服务器内部错误,message消息不展示给用户,BUG收集使用

访问接口需要做的工作:访问前,访问后

    访问后做的工作:接口正确,返回数据;接口正确,返回数据为空,比如请求列表等操作,获取用户订单(用户没有订单)等。接口错误。

一个Activity中可能有几次访问,需要区分各个访问。

由以上需求,可以制定以下

interface
package lib.bz365.network;

/**
 * 请求接口的回调
 */
public interface NetWorkCallBack {
    /**
     * 网络访问之前的操作
     * @param order 标记返回结果
     */
    void onPreNetTask(int order);
    /**
     * 网络访问之后
     * @param result 结果
     * @param message 需要显示的消息
     * @param order 标记返回结果
     */
    void onFinishFromNet(String result, String message, int order);
    /**
     * 网络访问错误
     * @param message 需要显示的消息
     * @param order 标记返回结果
     */
    void onErrorFromNet(String message, int order);
    /**
     * 返回数据为空
     * @param order 标记返回结果
     * @param message 需要显示的消息
     */
    void onDataIsEmpty(int order, String message);

}

下面,看以下缓存

我这里将缓存分成了五级,不缓存,秒,分,时,天,并在assets/XML中配置

<?xml version="1.0" encoding="utf-8"?>
<nodes>

    <!--
       url:
       cache_type: 0 不缓存,1 秒,2 分,3 时,4 天
       cache_value: 缓存对应数值
    -->

<!--
缓存时间6小时
-->
    <node
        cache_type="3"
        cache_value="6"
        url="" />
</nodes>

这里的url并不带参数,用来配置每个接口的缓存级别,可以创建三个xml,分别配置开发,测试,生产

一般情况下,开发时不使用缓存

缓存文件存储在应用内置缓存文件夹中,通过判断缓存文件的创建更新时间,来判断是否需要更新缓存

缓存的bean:

package lib.bz365.network;

public class NetNodeBean {
    private String url;
    private int cache_type;
    private int cache_value;

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public int getCache_type() {
        return cache_type;
    }

    public void setCache_type(int cache_type) {
        this.cache_type = cache_type;
    }

    public int getCache_value() {
        return cache_value;
    }

    public void setCache_value(int cache_value) {
        this.cache_value = cache_value;
    }

    @Override
    public String toString() {
        return "NetNodeBean [url=" + url + ", cache_type=" + cache_type
                + ", cache_value=" + cache_value + "]";
    }

}


xml解析的类:

package lib.bz365.network;

import java.io.IOException;
import java.io.InputStream;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import com.bz365.project.application.BZApplication;
import com.bz365.project.application.ConstantValues;

public class XMLParser {

    public static NetNodeBean parser(String targetUrl) {
        NetNodeBean netNodeBean = null;
        InputStream inputStream;
        try {
            if (ConstantValues.isDevelop) {
                inputStream = BZApplication.getInstance().getAssets()
                        .open("net_test.xml");
            } else {
                inputStream = BZApplication.getInstance().getAssets()
                        .open("net.xml");
            }
            DocumentBuilderFactory documentBuilderFactory = DocumentBuilderFactory
                    .newInstance();
            DocumentBuilder builder = documentBuilderFactory
                    .newDocumentBuilder();
            Document doc = builder.parse(inputStream);
            Element rootElement = doc.getDocumentElement();
            NodeList items = rootElement.getElementsByTagName("node");
            for (int i = 0; i < items.getLength(); i++) {
                Element node = (Element) items.item(i);
                String url = node.getAttribute("url");
                if (url.equals(targetUrl)) {
                    String cache_type = node.getAttribute("cache_type");
                    String cache_value = node.getAttribute("cache_value");
                    netNodeBean = new NetNodeBean();
                    netNodeBean.setUrl(url);
                    netNodeBean.setCache_type(Integer.parseInt(cache_type));
                    netNodeBean.setCache_value(Integer.parseInt(cache_value));
                    break;
                } else {
                    continue;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ParserConfigurationException e) {
            e.printStackTrace();
        } catch (SAXException e) {
            e.printStackTrace();
        }
        return netNodeBean;
    }

}

缓存文件的操作类:

package lib.bz365.network;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;

import lib.bz365.util.DebugUtil;

import android.os.AsyncTask;

import com.bz365.project.application.BZApplication;

public class FileCache {
    public static void saveCache(String fileName, String result) {
        FileAsyncTask asyncTask = new FileAsyncTask(fileName, result);
        asyncTask.execute();
    }

    public static String getCache(String fileName){
        String result = "";
        File file = new File(BZApplication.getInstance().getCacheDir(),
                fileName);
        if(!file.exists()){
            DebugUtil.LogD("cache", "缓存为空");
            return result;
        }
        FileInputStream inputStream;
        try {
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            inputStream = new FileInputStream(file);
            byte[] data = new byte[1024];
            int len = 0;
            while((len = inputStream.read(data))!=-1){
                outputStream.write(data, 0, len);
            }
            result = new String(outputStream.toByteArray(), "UTF-8");
            DebugUtil.LogD("cache", "从文件中提取" + outputStream.toString());
            inputStream.close();
            outputStream.close();
            DebugUtil.LogD("cache", "从文件中提取");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }

    public static long getFileUpdateTime(String fileName){
        File file = new File(BZApplication.getInstance().getCacheDir(),
                fileName);
        if(!file.exists()){
            DebugUtil.LogD("cache", "缓存为空");
            return 0l;
        }
        return file.lastModified();
    }

    private static class FileAsyncTask extends AsyncTask<String, Void, String>{

        private String fileName;
        private String result;

        public FileAsyncTask(String fileName, String result){
            this.fileName = fileName;
            this.result = result;
        }

        @Override
        protected String doInBackground(String... arg0) {
            File file = new File(BZApplication.getInstance().getCacheDir(),
                    fileName);
            if(file.exists()){
                file.delete();
            }
            try {
                file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
            FileOutputStream outputStream;
            try {
                outputStream = new FileOutputStream(file);
                outputStream.write(result.getBytes());
                outputStream.close();
                DebugUtil.LogD("cache", "保存到文件");
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }

        @Override
        protected void onPostExecute(String result) {
        }
    }
}

下面就是网络访问类,这里,调用网络接口时,不用考虑缓存,和接口返回的数据判断:

package lib.bz365.network;

import java.util.Date;

import lib.bz365.util.DebugUtil;
import lib.bz365.util.MD5;
import lib.bz365.util.StringUtil;

import org.json.JSONException;
import org.json.JSONObject;

import com.bz365.project.application.BZApplication;
import com.bz365.project.application.ConstantValues;

import android.os.AsyncTask;

public class AsynTaskForNet extends AsyncTask<String, Void, String> {

    /**
     * 需要单独对待的状态码
     */
    private int mark_Status;

    /**
     * 是否有特殊标记
     */
    private boolean hasMark;

    /**
     * 标记返回
     */
    private int order;

    private NetWorkCallBack callBack;

    public AsynTaskForNet(NetWorkCallBack callBack, int order) {
        this.hasMark = false;
        this.callBack = callBack;
        this.order = order;
    }

    public AsynTaskForNet(int mark_Status, NetWorkCallBack callBack, int order) {
        this.mark_Status = mark_Status;
        this.hasMark = true;
        this.callBack = callBack;
        this.order = order;
    }

    /**
     *
     * @param url
     *            URL
     * @param connect
     *            URL后拼接的参数
     * @param jsonString
     *            参数
     */
    public void getDatafromNet(String url, String connect, String jsonString) {
        execute(url, connect, jsonString);
    }

    /**
     * 是否需要保存缓存数据
     */
    private boolean saveCache;

    @Override
    protected String doInBackground(String... arg0) {

        if (isCache(arg0[0], arg0[1], arg0[2])) {
            
            return getCache(arg0[0], arg0[1], arg0[2]);
        } else {
            
            return WebServiceClient.doPostJson(arg0[0] + arg0[1], arg0[2]);
        }
    }

    @Override
    protected void onPreExecute() {
        callBack.onPreNetTask(order);
    }

    @Override
    protected void onPostExecute(String result) {
        if (StringUtil.isEmpty(result)) {
            callBack.onErrorFromNet("网络错误,请稍后再试", order);
            return;
        }
        try {
            JSONObject jsonObject = new JSONObject(result);
            int status = jsonObject.getInt("status");
            String message = jsonObject.getString("message");
            String data = jsonObject.getString("data");
            if (status == 0) {
                if ("null".equals(data) || "[]".equals(data)
                        || "{}".equals(data) || StringUtil.isEmpty(data)) {
                    callBack.onDataIsEmpty(order, message);
                } else {
                    if (saveCache)
                        FileCache.saveCache(cacheMark, result);
                    callBack.onFinishFromNet(result, message, order);
                }
            } else {
                if (hasMark && status == mark_Status) {
                    if (saveCache)
                        FileCache.saveCache(cacheMark, result);
                    callBack.onFinishFromNet(result, message, order);
                } else {
                    if (status == 1) {
                        callBack.onErrorFromNet(message, order);
                    } else {
                        callBack.onErrorFromNet("网络错误,请稍后再试", order);
                    }
                }
            }
        } catch (JSONException e) {
            e.printStackTrace();
            callBack.onErrorFromNet("网络错误,请稍后再试", order);
        }
    }

    private String cacheMark;

    /**
     * 判断是否需要缓存
     *
     * @param url
     * @param connect
     * @param jsonString
     * @return
     */
    private boolean isCache(String url, String connect, String jsonString) {
        cacheMark = MD5.getMessageDigest((url + connect + jsonString)
                .getBytes());
        NetNodeBean netNodeBean = XMLParser.parser(url);
        if (netNodeBean != null) {
            int cache_type = netNodeBean.getCache_type();
            int cache_value = netNodeBean.getCache_value();
            long cacha_time = 0l;
            long file_time = FileCache.getFileUpdateTime(cacheMark);
            if (cache_type == 0) {
                saveCache = false;
                return false;
            } else if (cache_type == 1) {
                saveCache = true;
                cacha_time = cache_value * 1000;
            } else if (cache_type == 2) {
                saveCache = true;
                cacha_time = cache_value * 1000 * 60;
            } else if (cache_type == 3) {
                saveCache = true;
                cacha_time = cache_value * 1000 * 60 * 60;
            } else if (cache_type == 4) {
                saveCache = true;
                cacha_time = cache_value * 1000 * 60 * 60 * 24;
            }
            if (file_time == 0) {
                return false;
            }
            long cur_time = new Date().getTime();
            if ((cur_time - cacha_time) < file_time) {
                saveCache = false;
                return true;
            }

        }
        return false;
    }

    /**
     * 返回缓存数据
     *
     * @param url
     * @param connect
     * @param jsonString
     * @return
     */
    private String getCache(String url, String connect, String jsonString) {
        return FileCache.getCache(cacheMark);
    }

}


下面是网络访问类;Android5.0后不支持httpclient,所以采用httpurlclicent

package lib.bz365.network;

import com.bz365.project.utils.statistics.StatisicsUtil;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;

import lib.bz365.util.CommonUtils;
import lib.bz365.util.DebugUtil;
import lib.bz365.util.StringUtil;
import lib.bz365.util.SystemOutUtil;

public class WebServiceClient {

    public static String doPostJson(String urlString, String jsonString) {
        try {
            URL url = new URL(urlString);
            SystemOutUtil.systemOut(urlString);
            HttpURLConnection http = (HttpURLConnection) url.openConnection();
            http.setRequestProperty("android-version",
                    CommonUtils.getVersionCode());
            http.setRequestProperty("app_channel", URLEncoder.encode(StatisicsUtil.getChannel(), "UTF-8"));
            http.setRequestMethod("POST");
            http.setRequestProperty("Content-Type", "application/json");
            http.setDoOutput(true);
            http.setDoInput(true);
            http.setUseCaches(false);
            System.setProperty("sun.net.client.defaultConnectTimeout", "10000");// 连接超时30秒
            System.setProperty("sun.net.client.defaultReadTimeout", "10000"); // 读取超时30秒
            if (!StringUtil.isEmpty(jsonString)) {
                OutputStream os = http.getOutputStream();
                DebugUtil.LogD(jsonString.toString());
                os.write(jsonString.toString().getBytes("UTF-8"));// 传入参数
                os.flush();
                os.close();
            }
            http.connect();
            DebugUtil.LogD("httpcode=" + http.getResponseCode());
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            byte[] data = new byte[1024];
            int len = 0;
            if (null != http.getInputStream())
                while ((len = http.getInputStream().read(data)) != -1) {
                    outputStream.write(data, 0, len);
                }
            String message = new String(outputStream.toByteArray(), "UTF-8");
            DebugUtil.LogD(message);
            SystemOutUtil.systemOut(message);
            return message;
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return "失败";
    }

}

使用:

/**
 * 雷达图页面
 */
public class RadarActivity extends AppBaseActivity implements RadarView.OnSelectItemListener, NetWorkCallBack, 


@Override
    public void onPreNetTask(int order) {
        showProgress();
    }

    @Override
    public void onFinishFromNet(String result, String message, int order) {
        closeProgress();
        DebugUtil.LogE("result", result);
        try {
            surpriseData = JsonUtils.toBean(result, new TypeToken<SurpriseData>() {
            }.getType());
            //TODO
        } catch (AppException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onErrorFromNet(String message, int order) {
        closeProgress();
        ShowToast(message);
    }

    @Override
    public void onDataIsEmpty(int order, String message) {
        closeProgress();
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值