首页 > 其他分享 >对于安卓发送 http 请求的实践

对于安卓发送 http 请求的实践

时间:2023-06-04 23:11:29浏览次数:44  
标签:http service 安卓 private 发送 weather void new public

配置

权限配置

要注意配置的位置

1 添加网络权限

<manifest >
    <application> .......</application>

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

2 配置明文网络流量

<application
	...
	android:usesCleartextTraffic="true"
	...>
	<activity>
	...
	...
	</activity>
</application>

android:usesCleartextTraffic 指示应用程序是否打算使用明文网络流量,例如明文HTTP。目标API级别为27或更低的应用程序的默认值为“ true”。面向API级别28或更高级别的应用默认为“ false”。

封装函数

GET 请求

这个也是我自己封装的专门用来发送 http 请求的类(我的请求没用到 post)

public class HttpUtil {

    /**
     * 发起 get 请求
     * @param api 请求的 api
     * @param pc 是否需要 PC 端的请求头,为了应对有些 api 只有 pc 端才能请求成功,但这只是极少数,一般为 false
     * @return 响应的 String 类型数据
     */
    public static String getApi(String api, boolean pc){

        Log.d("start","正在调用...");

        // 初始化连接对象
        HttpURLConnection connection=null;

        try {

            // 创建 URL
            URL url = new URL(api);

            // 开启对应 URL 的连接
            connection = (HttpURLConnection) url.openConnection();

            // 需要 PC 请求头
            if(pc){
                // 设置 PC 请求头
                // 注意这里的 SystemConstant.PC_USER_AGENT 是我自己封装的系统常量,粘贴时需要改动
                connection.setRequestProperty("user-agent",SystemConstant.PC_USER_AGENT);
            }

            // 设置连接超时时间
            connection.setConnectTimeout(3000);

            // 设置传递数据超时时间
            connection.setReadTimeout(3000);

            // 设置请求方式 GET / POST 一定要大写
            connection.setRequestMethod("GET");

            // 设置为写入模式(即:从连接中读取数据)
            connection.setDoInput(true);

            // 将写出模式设为 false
            connection.setDoOutput(false);

            // 建立连接
            connection.connect();

            // 获取响应码
            int responseCode = connection.getResponseCode();

            // 请求失败 抛出异常
            if (responseCode != HttpURLConnection.HTTP_OK) {
                throw new IOException("HTTP error code" + responseCode);
            }

            // 获取响应数据
            String result = getStringByStream(connection.getInputStream());

            // 响应数据为 null
            if (result == null) {
                Log.d("fail", "失败了");
                return null;
            }
            // 响应数据不为 null
            else{
                Log.d("success", "成功了 ");
                return result;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


    /**
     * 抽取的读取响应数据的函数
     * @param inputStream 输入流
     * @return 输入流字符串
     */
    private static String getStringByStream(InputStream inputStream){
        Reader reader;
        try {
            reader=new InputStreamReader(inputStream, StandardCharsets.UTF_8);
            char[] rawBuffer=new char[512];
            StringBuilder buffer=new StringBuilder();
            int length;
            while ((length=reader.read(rawBuffer))!=-1){
                buffer.append(rawBuffer,0,length);
            }
            return buffer.toString();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}

POST 请求

相比于 GET 请求,POST 可能需要添加 请求体参数

添加请求体参数方法:

DataOutputStream dos=new DataOutputStream(connection.getOutputStream());
String param="My param";
dos.writeBytes(param);

service 调用

在安卓开发中,http 请求必须在子线程(非主线程)中发起

封装 http 请求函数

/**
 * 获取天气信息的接口
 */
public void getWeather(){
    Log.d(TAG,"开始查询天气");

    new Thread(() -> {

        String res = HttpUtil.getApi(SystemConstant.WEATHER_API, false);

        if(res == null){
            return;
        }

        try {
            JSONObject resJson = new JSONObject(res);
            weatherJsonObject = resJson.getJSONArray("forecasts").getJSONObject(0);

            if(weatherResponseListener!=null){
                weatherResponseListener.response(weatherJsonObject);
            }

        } catch (JSONException e) {
            e.printStackTrace();
        }

    }).start();
}

这里有两个关键的变量:

  1. weatherJsonObject:JSONObject 类型,用于存储查询到的信息。
  2. weatherResponseListener:自定义的监听类型 ResponseListener,用于发起的请求接收到响应数据后发送给主线程进行相关操作。

ResponseListener 接口:

public interface ResponseListener {
    /**
     * http 请求响应数据回调函数
     * @param jsonObject 响应数据
     * @throws JSONException 抛出异常
     */
    void response(JSONObject jsonObject) throws JSONException;
}

关于系统使用该回调函数实现 service 主动与 activity 通信的方法,这里先不展开讲。

完整的 HttpService 代码:

public class HttpService extends Service {

    // 日志标签
    private static final String TAG = "HttpService";

    private JSONObject weatherJsonObject;

    // IBinder 对象用于传递实例
    private final IBinder binder = new MyBinder();

    // 向 IBinder 添加获取实例的方法
    public class MyBinder extends Binder {
        public HttpService getService() {
            return HttpService.this;
        }
    }

    private ResponseListener weatherResponseListener;

    public void setWeatherResponseListener(ResponseListener weatherResponseListener) {
        this.weatherResponseListener = weatherResponseListener;
    }

    /**
     * 获取天气信息的接口
     */
    public void getWeather(){
        Log.d(TAG,"开始查询天气");

        new Thread(() -> {

            String res = HttpUtil.getApi(SystemConstant.WEATHER_API, false);

            if(res == null){
                return;
            }

            try {
                JSONObject resJson = new JSONObject(res);
                weatherJsonObject = resJson.getJSONArray("forecasts").getJSONObject(0);

                if(weatherResponseListener!=null){
                    weatherResponseListener.response(weatherJsonObject);
                }

            } catch (JSONException e) {
                e.printStackTrace();
            }

        }).start();
    }
}

这个 service 是我自己封装的,相当于在最底层的 http 请求的基础上又包了一层。

activity 调用接口

这里的原理是通过绑定 service 成功时的回调方法获取 service 实例,然后调用 service 中的 setWeatherResponseListener(ResponseListener weatherResponseListener) 回调方法来接收请求的响应数据。

绑定 service 的同时通过回调获取数据并通过 Handler 通知主线程更新组件:

这些代码是在嵌套在 activity 组件中 fragment 里的,所以使用 getActivity() 来获取 activity 中的 this

public Handler handler = new Handler(Looper.getMainLooper()){
    @Override
    public void handleMessage(@NonNull Message msg) {
        super.handleMessage(msg);
        switch (msg.what){
            case HandlerConstant.UPDATE_WEATHER:
                updateWeather();
                getActivity().unbindService(serviceConnection);
                break;

            default:
        }
    }
};


/**
 * 查询天气
 */
private void queryWeather(){
    Log.d(TAG, "开始查询天气信息...");
    
    // 绑定 service 
    Intent httpIntent = new Intent(getActivity(), HttpService.class);
    getActivity().bindService(httpIntent, serviceConnection, Context.BIND_AUTO_CREATE);
}


private ServiceConnection serviceConnection = new ServiceConnection() {
    /**
     * 与 HttpService 绑定成功后调用
     * @param name
     * @param service
     */
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        httpService = ((HttpService.MyBinder) (service)).getService();
        if(httpService != null){
            // 调用获取天气的请求
            httpService.getWeather();

            // 天气接口回调
            httpService.setWeatherResponseListener(jsonObject -> initWeather(jsonObject));
        }
    }

    /**
     * 解绑成功后调用
     * @param name
     */
    @Override
    public void onServiceDisconnected(ComponentName name) {
        httpService = null;
    }
};

/**
 * 初始化 weather
 * @param jsonObject 响应数据
 * @throws JSONException 抛出 JSON 异常
 */
private void initWeather(JSONObject jsonObject) throws JSONException {
    weather = new Weather();

    JSONObject today = jsonObject.getJSONArray("casts").getJSONObject(0);

    weather.setCity(jsonObject.getString("city"));
    weather.setDate(jsonObject.getString("reporttime"));
    weather.setDayWeather(today.getString("dayweather"));
    weather.setNightWeather(today.getString("nightweather"));
    weather.setDayTemp(today.getString("daytemp"));
    weather.setNightTemp(today.getString("nighttemp"));

    // 这里是通知主线程调用 updateWeather()
    Message msg = new Message();
    msg.what = HandlerConstant.UPDATE_WEATHER;
    handler.sendMessage(msg);
}

@SuppressLint("SetTextI18n")
private void updateWeather(){
    cityText.setText(weather.getCity());
    dateText.setText(weather.getDate());
    weatherText.setText(weather.getDayWeather()+" 转 "+ weather.getNightWeather());
    tempText.setText(weather.getNightTemp()+" ~ "+weather.getDayTemp()+" 摄氏度");
}

以上代码在调用 http 请求接口方面的核心为:

/**
 * 查询天气
 */
private void queryWeather(){
    Log.d(TAG, "开始查询天气信息...");
    
    // 绑定 service 
    Intent httpIntent = new Intent(getActivity(), HttpService.class);
    getActivity().bindService(httpIntent, serviceConnection, Context.BIND_AUTO_CREATE);
}


private ServiceConnection serviceConnection = new ServiceConnection() {
    /**
     * 与 HttpService 绑定成功后调用
     * @param name
     * @param service
     */
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
        httpService = ((HttpService.MyBinder) (service)).getService();
        if(httpService != null){
            // 调用获取天气的请求
            httpService.getWeather();

            // 天气接口回调
            httpService.setWeatherResponseListener(jsonObject -> initWeather(jsonObject));
        }
    }

    /**
     * 解绑成功后调用
     * @param name
     */
    @Override
    public void onServiceDisconnected(ComponentName name) {
        httpService = null;
    }
};

我的 fragment 完整代码:

public class HomeFragment extends Fragment {

    // 日志标签
    public final String TAG = "HomeFragment";

    // 发送 http 请求的 service
    private HttpService httpService;

    // 天气信息
    private Weather weather;

    // 用于展示天气信息的组件
    private TextView cityText;
    private TextView dateText;
    private TextView weatherText;
    private TextView tempText;

    // 用于展示笔记信息的组件
    private ListView noteListView;

    public Handler handler = new Handler(Looper.getMainLooper()){
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case HandlerConstant.UPDATE_WEATHER:
                    updateWeather();
                    getActivity().unbindService(serviceConnection);
                    break;

                default:
            }
        }
    };


    /**
     * 构造函数
     */
    public HomeFragment() {
        // Required empty public constructor
    }


    /**
     * 当 Activity 完成onCreate() 时调用。
     * @param savedInstanceState
     */
    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        initView();
        initDatabase();
        initClickListener();
    }

    /**
     * 初始化视图组件
     */
    private void initView(){
        /*
         * 天气相关
         */
        cityText = getView().findViewById(R.id.city);
        dateText = getView().findViewById(R.id.datetime);
        weatherText = getView().findViewById(R.id.weather);
        tempText = getView().findViewById(R.id.temp);
    }

    /**
     * 初始化点击事件
     */
    private void initClickListener(){
    }


    /**
     * 创建时的回调方法
     * @param inflater
     * @param container
     * @param savedInstanceState
     * @return
     */
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

//        LayoutInflater lf = getActivity().getLayoutInflater();
//        View view =  lf.inflate(R.layout.fragment_home, container, false);

        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_home, container, false);
    }



    /**
     * fragment 可见时调用
     */
    @Override
    public void onStart() {
        super.onStart();
    }

    /**
     * 恢复 fragment 时调用
     */
    @Override
    public void onResume() {
        super.onResume();
        queryWeather();
    }

    /**
     * 查询天气
     */
    private void queryWeather(){
        Log.d(TAG, "开始查询天气信息...");
        Intent httpIntent = new Intent(getActivity(), HttpService.class);
        getActivity().bindService(httpIntent, serviceConnection, Context.BIND_AUTO_CREATE);
    }


    private ServiceConnection serviceConnection = new ServiceConnection() {
        /**
         * 与 HttpService 绑定成功后调用
         * @param name
         * @param service
         */
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            httpService = ((HttpService.MyBinder) (service)).getService();
            if(httpService != null){
                // 调用获取天气的请求
                httpService.getWeather();

                // 天气接口回调
                httpService.setWeatherResponseListener(jsonObject -> initWeather(jsonObject));
            }
        }

        /**
         * 解绑成功后调用
         * @param name
         */
        @Override
        public void onServiceDisconnected(ComponentName name) {
            httpService = null;
        }
    };

    /**
     * 初始化 weather
     * @param jsonObject 响应数据
     * @throws JSONException 抛出 JSON 异常
     */
    private void initWeather(JSONObject jsonObject) throws JSONException {
        weather = new Weather();

        JSONObject today = jsonObject.getJSONArray("casts").getJSONObject(0);

        weather.setCity(jsonObject.getString("city"));
        weather.setDate(jsonObject.getString("reporttime"));
        weather.setDayWeather(today.getString("dayweather"));
        weather.setNightWeather(today.getString("nightweather"));
        weather.setDayTemp(today.getString("daytemp"));
        weather.setNightTemp(today.getString("nighttemp"));

        Message msg = new Message();
        msg.what = HandlerConstant.UPDATE_WEATHER;
        handler.sendMessage(msg);
    }

    @SuppressLint("SetTextI18n")
    private void updateWeather(){
        cityText.setText(weather.getCity());
        dateText.setText(weather.getDate());
        weatherText.setText(weather.getDayWeather()+" 转 "+ weather.getNightWeather());
        tempText.setText(weather.getNightTemp()+" ~ "+weather.getDayTemp()+" 摄氏度");
    }
}

总结

我这里对于网络请求的代码结构采用分层的方法。

总共有三层。

第一层为最原始的发送 http 请求的代码。

第二层为 service 中子线程对第一层接口的调用。

第三层为 activity(fragment) 中通过绑定 service 时 ServiceConnection 中的回调方法获取 service 实例;然后通过 service 中的自己定义的 ResponseListener 类型的回调函数获取 service 接收到数据后主动发送来的响应信息;最后通过 Handler 的进程通信在主线程中对数据进行展示等只能在主线程的操作。

标签:http,service,安卓,private,发送,weather,void,new,public
From: https://www.cnblogs.com/huang-guosheng/p/17456659.html

相关文章

  • Java中用于发送HTTP请求的工具类
     HttpClientUtil是Java中用于发送HTTP请求的工具类,它是基于ApacheHttpClient实现的。下面是一个示例代码:importorg.apache.http.HttpEntity;importorg.apache.http.client.entity.UrlEncodedFormEntity;importorg.apache.http.client.methods.CloseableHttpResponse;import......
  • Java中用于发送HTTP请求的工具类
     HttpClientUtil是Java中用于发送HTTP请求的工具类,它是基于ApacheHttpClient实现的。下面是一个示例代码:importorg.apache.http.HttpEntity;importorg.apache.http.client.entity.UrlEncodedFormEntity;importorg.apache.http.client.methods.CloseableHttpResponse;import......
  • Java中用于发送HTTP请求的工具类
    ​ HttpClientUtil是Java中用于发送HTTP请求的工具类,它是基于ApacheHttpClient实现的。下面是一个示例代码:importorg.apache.http.HttpEntity;importorg.apache.http.client.entity.UrlEncodedFormEntity;importorg.apache.http.client.methods.CloseableHttpResponse;......
  • Java中用于发送HTTP请求的工具类
    ​ HttpClientUtil是Java中用于发送HTTP请求的工具类,它是基于ApacheHttpClient实现的。下面是一个示例代码:importorg.apache.http.HttpEntity;importorg.apache.http.client.entity.UrlEncodedFormEntity;importorg.apache.http.client.methods.CloseableHttpResponse;......
  • Java中HttpClientUtil工具类
     HttpClientUtil包含get和post方法。发送HttpPost或HttpGet请求一共三个步骤:1、创建CloseableHttpClient对象,用于执行excute方法2、创建HttpPost或者HttpGet请求对象3、执行请求,判断返回状态,接收响应对象  publicclassHttpClientUtil{/****编码集*/......
  • Java中HttpClientUtil工具类
     HttpClientUtil包含get和post方法。发送HttpPost或HttpGet请求一共三个步骤:1、创建CloseableHttpClient对象,用于执行excute方法2、创建HttpPost或者HttpGet请求对象3、执行请求,判断返回状态,接收响应对象  publicclassHttpClientUtil{/****编码集*/......
  • Java中HttpClientUtil工具类
    ​ HttpClientUtil包含get和post方法。发送HttpPost或HttpGet请求一共三个步骤:1、创建CloseableHttpClient对象,用于执行excute方法2、创建HttpPost或者HttpGet请求对象3、执行请求,判断返回状态,接收响应对象  publicclassHttpClientUtil{/****编码集......
  • Java中HttpClientUtil工具类
    ​ HttpClientUtil包含get和post方法。发送HttpPost或HttpGet请求一共三个步骤:1、创建CloseableHttpClient对象,用于执行excute方法2、创建HttpPost或者HttpGet请求对象3、执行请求,判断返回状态,接收响应对象  publicclassHttpClientUtil{/****编码集......
  • XMLHttpRequest简单介绍
    1.概述XMLHttpRequest(XHR)对象用于与服务器交互,我们通过XMLHttpRequest可以在不刷新页面的情况下请求特定URL获取数据,并且虽然名字叫XMLHttpRequest,但实际上可以用于获取任何类型的数据。2.使用方式XMLHttpRequest的使用主要可以分为如下几步:创建XMLHttpRequest对象建立......
  • haproxy vegeta压测https
     echo"GEThttps://mail.test.com/EWS/Exchange.asmx"|vegetaattack-rate=300-duration=300s-timeout=300s|teeresults.bin|vegetareport如果提示证书不受信任,则将其域名根证书(.cer)放到放到/etc/pki/ca-trust/source/anchors目录下然后运行/bin/update-ca-trust......