Volley手写属于自己的万能网络访问框架

用户在调用层(Activity或Service中),发起一个网络请求,该请求肯定包含url,请求参数(requestParameter),以及我们需要给调用层提供一个请求成功或失败以后回调监听的接口dataListener(这一点与Volley类似)。

在框架层,每一次用户请求可以看做一个Http任务,这些任务我们可以用一个请求队列存储起来,框架工作时不断地从请求队列中取出任务放到处理中心中,处理中心是一个线程池ThreadPool。使用线程池可以带来3个好处: 
1.降低资源消耗:通过重用已经创建的线程来降低线程创建和销毁的消耗 
2.提高响应速度:任务到达时不需要等待线程创建就可以立即执行。 
3.提高线程的可管理性:线程池可以统一管理、分配、调优和监控。

由于用户请求的数量是不确定的,所以请求队列的长度应该没有限制,所以这里的数据结构,我们应该使用链表。正好,java给我们提供了一个阻塞式队列LinkedBlockingQueue,它是一个单向链表实现的无界阻塞队列,先进先出,支持多线程并发操作。

再仔细考虑一下框架层的操作,用户不断发请求产生HttpTask,处理中心不断从请求队列中去任务,这和那个生产者消费者模式是不是很像?所以我们还需要考虑并发和同步问题,而LinkedBlockingQueue是线程安全的,实现了先进先出等特性,是作为生产者消费者的首选。LinkedBlockingQueue 可以指定队列的容量,也可以不指定,不指定的话,默认最大是Integer.MAX_VALUE,其中主要用到put和take方法,put方法在队列满的时候会阻塞直到有队列成员被消费,take方法在队列空的时候会阻塞,直到有队列成员被放进来。

至于处理中心的线程池,我们使用jdk里的ThreadPoolExecutor,具体用法可以自行百度,唯一需要注意的就是其中的拒绝策略。

代码编写

首先,我们需要一个线程池的管理类,来管理请求队列和处理中心处理任务。由于系统中仅有一个线程池管理的类,所以该类应该设计成单例模式

ThreadPoolManager.java

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 1.  线程池管理类
 */
public class ThreadPoolManager {
    //1.将请求任务放到请求队列中
    //通过阻塞式队列来存储任务
    private LinkedBlockingQueue<Runnable> queue = new LinkedBlockingQueue<>();
    //添加任务
    public void execute( Runnable runnable ){
        if( runnable != null ) {
            try {
                queue.put(runnable);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
    //2.把队列中的任务放到线程池
    private ThreadPoolExecutor threadPoolExecutor ;
    private ThreadPoolManager(){
        threadPoolExecutor = new ThreadPoolExecutor(4,20,15, TimeUnit.SECONDS,new ArrayBlockingQueue<Runnable>(4),rejectedExecutionHandler);
        //运行线程池
        threadPoolExecutor.execute(runnable);
    }
    //当线程数超过maxPoolSize或者keep-alive时间超时时执行拒绝策略
    private RejectedExecutionHandler rejectedExecutionHandler = new RejectedExecutionHandler() {
        /**
         * @param runnable 超时被线程池抛弃的线程
         * @param threadPoolExecutor
         */
        @Override
        public void rejectedExecution(Runnable runnable, ThreadPoolExecutor threadPoolExecutor) {
            //将该线程重新放入请求队列中
            try {
                queue.put(runnable);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    };
    //3.让他们开始工作起来
    //整个的工作线程
    private Runnable runnable = new Runnable() {
        @Override
        public void run() {
            while(true){
                Runnable runnable = null ;
                //不断从从请求队列中取出请求
                try {
                    runnable = queue.take();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //如果不为空,放入线程池中执行
                if( runnable != null ){
                    threadPoolExecutor.execute(runnable);
                }
            }

        }
    };

    //单例模式
    private static ThreadPoolManager singleInstance = new ThreadPoolManager();
    public static ThreadPoolManager getSingleIntance(){
        return singleInstance;
    }
}

接下来我们需要将写两个接口将用户的网络访问操作分成两部分(参考架构图),一个是请求(IHttpRequest),一个是响应(IHttpListener), 
在请求接口中,我们需要做的事有三个

  1. 设置url
  2. 设置请求参数
  3. 执行请求

IHttpRequest.java

/**
 * 封装请求
 */
public interface IHttpRequest {
    void setUrl(String url);
    void setRequestData( byte[] requestData );
    void execute();
    //需要设置请求和响应两个接口之间的关系
    void setHttpCallBack( IHttpListener httpListener );
}

在响应接口中,我们需要做的事也很简单

  1. 处理结果
  2. 回调应用层

IHttpListener.java

import java.io.InputStream;

/**
 * 封装响应
 */
public interface IHttpListener {
    //接受上一个接口的结果
    void onSuccess(InputStream inputStream);
    void onFailure();
}

接下来我们编写代表请求任务的类HttpTask,让它实现Runnable接口,并且维护IHttpRequest和IHttpListener两个接口的引用,在HttpTask的构造方法中,进行一些初始化操作,设置请求的url,请求参数,设置监听器等等。在将请求参数对象转换成字符串的过程中,我们使用了阿里的fastjson这个jar包。最后在run方法中,执行httpRequest的请求。另外注意这里泛型的使用。

HttpTask.java

import com.alibaba.fastjson.JSON;

import java.io.UnsupportedEncodingException;


public class HttpTask<T> implements Runnable {
    private IHttpRequest httpRequest;
    private IHttpListener httpListener;
    public<T> HttpTask( T requestInfo , String url , IHttpRequest httpRequest, IHttpListener httpListener){
        this.httpRequest = httpRequest;
        this.httpListener = httpListener;
        //设置url
        this.httpRequest.setUrl(url);
        //设置响应回调
        this.httpRequest.setHttpCallBack(httpListener);
        //设置请求参数
        if( requestInfo != null ){
            //将用户发送的请求参数对象转换成字符串
            String requestContent = JSON.toJSONString(requestInfo);
            //字符串转byte数组
            try {
                this.httpRequest.setRequestData(requestContent.getBytes("utf-8"));
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }

    }
    @Override
    public void run() {
        httpRequest.execute();
    }
}

接下来我们编写IHttpRequest的实现类,JsonHttpRequest , 在重写的execute方法中,使用原生的HttpURLConnection执行网络请求,请求成功后,回调IHttpListener的onSuccess方法。

如果想要传送其他数据(图片,文件等),同样实现IHttpRequest该接口即可,所以这个框架的扩展性十分良好。

JsonHttpRequest.java

import java.io.BufferedOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;

/**
 * Json版Http请求
 */

public class JsonHttpRequest implements IHttpRequest{

    private String url ;
    private byte[] requestData ;
    private IHttpListener httpListener;

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

    @Override
    public void setRequestData(byte[] requestData) {
        this.requestData = requestData;
    }

    //原生的网络操作在这里实现
    @Override
    public void execute() {
        httpUrlconnPost();
    }

    private HttpURLConnection urlConnection = null ;

    public void httpUrlconnPost(){
        URL url = null;
        try{
            url = new URL(this.url);
            //打开http连接
            urlConnection = (HttpURLConnection) url.openConnection();
            //设置连接的超时时间
            urlConnection.setConnectTimeout(6000);
            //不使用缓存
            urlConnection.setUseCaches(false);
            urlConnection.setInstanceFollowRedirects(true);
            //响应的超时时间
            urlConnection.setReadTimeout(3000);
            //设置这个连接是否可以写入数据
            urlConnection.setDoInput(true);
            //设置这个连接是否可以输出数据
            urlConnection.setDoOutput(true);
            //设置请求的方式
            urlConnection.setRequestMethod("POST");
            urlConnection.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
            urlConnection.connect();

            //使用字节流发送数据
            OutputStream out = urlConnection.getOutputStream();
            BufferedOutputStream bos = new BufferedOutputStream(out);
            if( requestData != null ){
                //把字节数组的数据写入缓冲区
                bos.write(requestData);
            }
            //刷新缓冲区,发送数据
            bos.flush();
            out.close();
            bos.close();

            //获得服务器响应
            if( urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK){
                InputStream in = urlConnection.getInputStream();
                //回调监听器的listener方法
                httpListener.onSuccess(in);
            }
        }catch ( Exception e){
            e.printStackTrace();
        }
    }

    @Override
    public void setHttpCallBack(IHttpListener httpListener) {
        this.httpListener = httpListener;
    }
}

接下来是IHttpListener的Json版本实现类,在该类中要注意的事就是回调结果给用户时要进行线程的切换(使用Handler),并且要将返回的json字符串转换成泛型对象(该对象由用户自定义)。

JsonHttpListener.java

import android.os.Handler;
import android.os.Looper;

import com.alibaba.fastjson.JSON;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

/**
 * Json版本的httpListener
 */

public class JsonHttpListener<M> implements IHttpListener{
    Class<M> responseClass;
    private IDataListener<M> dataListener;

    public JsonHttpListener(Class<M> responseClass, IDataListener<M> dataListener) {
        this.responseClass = responseClass;
        this.dataListener = dataListener;
    }

    //用于切换线程
    Handler handler = new Handler(Looper.getMainLooper());
    @Override
    public void onSuccess(InputStream inputStream) {
        //获取响应结果,把byte数据转换成String数据
        String content = getContent(inputStream);
        //将json字符串转换成对象
        final M response = JSON.parseObject(content,responseClass);
        //把结果传送到调用层
        handler.post(new Runnable() {
            @Override
            public void run() {
                if( dataListener != null ){
                    dataListener.onSuccess(response);
                }

            }
        });

    }

    @Override
    public void onFailure() {
        handler.post(new Runnable() {
            @Override
            public void run() {
                if( dataListener != null ){
                    dataListener.onFailure();
                }

            }
        });

    }

    /**
     * 将流转换成字符串
     * @param inputStream
     * @return
     */
    private String getContent(InputStream inputStream){
        String content = null ;
        BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
        StringBuilder sb = new StringBuilder();
        String line = null ;
        try{
            while( (line = reader.readLine()) != null){
                sb.append(line + "\n");
            }
        }catch ( IOException  e ){
            e.printStackTrace();
        }finally {
            try {
                inputStream.close();
                reader.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return sb.toString();
    }
}

最后两步

  1. 请求成功后,返回结果给调用层时,我们还要写一个数据返回的统一接口IDataListener来给用户使用(跟Volley一样)
  2. 不能让用户自己去创建HttpTask,用户请求也需要一个统一接口。

这样我们框架的封装性会更好。

IDataListener.java

/**
 * 回调调用层的接口,数据返回的统一接口
 */

public interface IDataListener<M> {
    void onSuccess( M m );
    void onFailure();
}

Volley.java

/**
 * 用户请求的统一接口
 */
public class Volley {
    public static<T,M> void sendJsonRequest( T requestInfo , String url , Class<M> response , IDataListener<M> dataListener){
        IHttpRequest httpRequest = new JsonHttpRequest();
        IHttpListener httpListener = new JsonHttpListener<>(response,dataListener);
        HttpTask<T> httpTask = new HttpTask<T>(requestInfo,url,httpRequest,httpListener);
        ThreadPoolManager.getSingleIntance().execute(httpTask);
    }
}

最后在MainActivity中测试

public void onClick(View view) {
                //Student为自己定义的javaBean
                Volley.sendJsonRequest(null, url, Student.class, new IDataListener<Student>() {
                    @Override
                    public void onSuccess(Student student) {
                        Toast.makeText(MainActivity.this,student.getName(),Toast.LENGTH_SHORT).show();
                    }

                    @Override
                    public void onFailure() {
                        Toast.makeText(MainActivity.this,"请求失败",Toast.LENGTH_SHORT).show();
                    }
                });
            }

想要拓展更多的功能,请求更多类型的数据,我们只需要实现IHttpRequest和IHttpListener这两个接口就行了。

 

参考:https://www.jianshu.com/p/396ada3885cc

避开PFC设计大坑:从环路分析到参数整定的5个常见误区解决方案 本文深入解析PFC电路设计中从环路分析到参数整定的5个常见误区,包括电感参数设计、小信号模型适用边界、电压环电流环耦合效应等。通过实际案例和PSIM仿真数据,提供工程落地的解决方案,帮助工程师避开设计陷阱,提升电路性能可靠性。 阅读详情

相关推荐

相控阵多功能雷达工作模式识别技术综述

本文综述了相控阵雷达工作模式识别技术的研究进展。首先介绍了相控阵雷达的典型工作模式分类及其信号特征参数,包括搜索模式(VS、RWS、TWS)、跟踪模式(STT、MTT、TAS)和其他模式(SAM、SAR)等。随后重点阐述了基于信号特征的识别方法,包括时域特征(PRI分析、脉冲幅度包络、数据率)、频域特征(载频变化、调制方式)和混合特征分析方法。最后讨论了当前技术面临的挑战发展趋势,包括复杂信号环境下的识别难题、新型雷达技术的适应需求以及深度学习技术的应用前景。该领域的研究对电子侦察和威胁评估具有重要意义。

Grow into a more wonderful you 1710

手写volley网络请求框架

    网络请求框架其实google已经提供了不少的开源框架,但为什么还需要手写呢?看到这篇文章的博友不知道有没有在一二线的企业工作过,像BAT这些企业,他们开发出的项目,很少会有用到谷歌或者android提供的原生api,这也是高级Android开发工程师所必备的技术,就是自己手写出开源框架的项目。接下来我就给大家演示一下volley框架手写实现,这个不同于volley本身的框架,在手写的过...

cWX411904的博客 516

零基础入门simulink建模仿真--基于Simulink的QPSK调制解调仿真建模示例

QPSK是一种相位调制技术,将两个比特映射到一个符号上,每个符号对应四个可能的相位之一(0°、90°、180°、270°)。通过Simulink,我们可以通过模块化的建模方式实现QPSK的调制和解调过程,并观察信号在信道中的传输效果。通过本指南,我们介绍了如何基于Simulink搭建一个完整的QPSK调制解调仿真模型,并进行仿真和性能评估。背景介绍:理解QPSK调制解调的基本原理及其应用。所需工具和环境:列出进行QPSK仿真所需的工具和环境。步骤详解。

amy_mhd的博客 1282

Volley网络请求框架简析——Android网络请求框架(三)

2019独角兽企业重金招聘Python工程师标准>>> ...

weixin_33901843的博客 254

Android进阶系列-手写高并发网络访问框架

一个项目,访问网络那是必须的。现在开源的网络框架很多。比如最开始的HeepClient,Volley,xUtils,最近很火的okhttp,还有例如retrofit,okGo这些都是很不错 的框架。但是毕竟是别人写的。出了什么问题都不好查找。这里自己封装了一个网络框架,记录一下封装思路。 采用线程池做网络请求的缓冲,可以做到高并发。同时将网络请求和网络处理分开,这样逻辑更清楚。这里的模式参考了V

SingleShu的博客 4498

Android Volley完全解析(二),使用Volley加载网络图片

在上一篇文章中,我们了解了Volley到底是什么,以及它的基本用法。本篇文章中我们即将学习关于Volley更加高级的用法,如何你还没有看过我的上一篇文章的话,建议先去阅读Android Volley完全解析(一),初识Volley的基本用法。 在上篇文章中有提到过,Volley是将AsyncHttpClient和Universal-Image-Loader的优点集成于一身的一个框架。我们都知道,Universal-Image-Loader具备非常强大的加载网络图片的功能,而使用Volley,我们也可以实现基

郭霖的专栏 16万+

Android仿Volley手写属于自己万能网络访问框架

在android网络通信中,我们平常开发时都会使用诸如Volley,Retrofit,AsyncHttpClient等等别人的框架,确实十分的便捷,省去了我们不少的时间。但是使用第三方框架也会带来一些不可避免的缺点。一、项目中大量使用第三方框架的缺点 引入较多冗余代码,别人框架中有许多代码是我们不需要的 框架中部分的函数,功能不满足我们的需求(定制性较弱) 下面,我们就仿照Volley框架的思想手撸

SakuraMashiro的博客 1270

自托管多智能体AI框架Pacific Slate:构建私有化AI协作平台

大语言模型(LLM)通过理解和生成自然语言,已成为AI应用的核心技术。其工作原理基于Transformer架构,通过海量数据预训练获得通用知识。这一技术价值在于能够处理复杂语义任务,推动自动化智能化升级。在实际应用中,LLM常被用于构建智能助手、内容生成和代码开发等场景。然而,单一模型在处理需要多步骤规划、工具调用和团队协作的复杂任务时存在局限。为此,多智能体(Multi-agent)系统应运而生,它通过让多个具备特定角色的AI智能体分工协作,共同解决复杂问题。Pacific Slate正是一个实现此理念

weixin_34185320的博客 299

万能Volley

v1olley能干那些事?发送get请求 public void getJson() { String url = "http://"+host+":8080/web/json.jsp?username=xjs&password=123456"; mQueue.add(new JsonObjectRequest(Method.GET, url, null, new List...

weixin_30871905的博客 79

okhttp,retrofit,volley,HttpClient,HttpUrlConnection之间的关系

Android网络开发不可避免的会接触到标题中的一些名词,本文整理下这个之间的关系。 对软件来说有个万能定律定律就是有什么“解决不了的问题就加个中间层,如果还是解决不了就多加几层” 基于unix的计算机操作系统可以分为内核层和用户层 1.内核层的驱动框架和系统调用。按网络层次来说,物理设备网卡,线路等对应最底层,tcp和ip由内核实现。对上的系统调用就围绕socket展开(诸如绑定,监听等)

firedancer0089的专栏 2023

【小超_Android】2014年框架类源码年度精品汇总

Android快速开发框架LoonAndroid 下载地址:http://www.dwz.cn/zOEmz 主要有以下模块: (1) 自动注入框架(只需要继承框架内的application既可) (2) 图片加载框架(多重缓存,自动回收,最大限度保证内存的安全性) (3) 网络请求模块(继承了基本上现在所有的http请求) (4) eventbus(集成一个开源的框架) (5

青涩丶年华 812

安卓怎么搭建框架

今天在我的石墨文档中看到以下内容的整理 2018.4.3号写下的 选择设计模式 MVC Model-View-Controller,经典模式,很容易理解,主要缺点有两个: View对Model的依赖,会导致View也包含了业务逻辑; Controller会变得很厚很复杂。 MVP Model-View-Presenter,MVC的一个演变模式,将Controller换成了Pres...

小马总的博客 853

Android开发常用开源框架(架构程序)

> Android反射系列: Android通过反射打造可以存储任何对象的万能SharedPreferences-- http://blog.csdn.net/nugongahou110/article/details/46913461 Android 通过反射让SQlite建表如此简单-- http://blog.csdn.net/nugongahou110/article/details/

灵思致远Leansmall的博客 370

Android快速开发框架Android_BaseLib,集成了常用工具类,自定义View控件,Base基类封装,常用开源框架

Android_BaseLib 这是一个用于Android快速开发的框架,主要是在以往的项目开发中,收集到的常用的功能: 1.常用到的工具类; 2.BaseActivity,BaseFragment,还有BaseView的封装,以便于对ViewPage中的View进行分别的管理,符合Java的封 装思想。 3.对BaseAdapter进行封装成MyBaseAdapter,引入BaseViewHolder,是个万能的ViewHolder; 4.常用定义

做更好的自己 6553

Android快速开发框架LoonAndroid

Android快速开发框架LoonAndroid 下载地址:http://www.devstore.cn/code/info/74.html 主要有以下模块: (1) 自动注入框架(只需要继承框架内的application既可) (2) 图片加载框架(多重缓存,自动回收,最大限度保证内存的安全性) (3) 网络请求模块(继承了基本上现在所有的http请求) (4) eventb

飞上北极星 1436

Android网络框架volley学习(一)基本用法

记录学习Android网络基础框架volley的过程。 首先我们需要将volley下载下来导入Android Studio中,我学习一个开源库,最好的方式就是将其源码以module的方式依赖到工程中去,这样我如果需要修改什么的话,就可以直接修改源码,同样volley学习也一样。 导入volley源码 1) 下载volley源码 git clone https://github.com/

ostracod 3063

Linux服务器RocketMQ和RocketMQ Dashboard安装部署

rockermq安装

qq_39984729的博客 216

大数据 之 Snappy

【代码】大数据 之 Snappy。

zhixingheyi_tian的博客 165

商超智能运营如何落地?从系统架构到实战避坑的完整技术路径

3. **多端交互展示层**:需覆盖顾客使用的**小程序、APP及H5公众号**,以及员工使用的管理后台。答:在应用层引入**适配器模式**。在项目启动时,应强制要求供应商或自研团队产出**部署文档**(含环境变量清单)和**二次开发文档**(含核心流程时序图),确保后续维护不受限于个人。- **多租户插件**:MyBatis Plus的`TenantLineInnerInterceptor`可实现SQL层面的自动拼接`store_id`条件,防止开发者因SQL编写疏漏导致的数据越权。

weixin_56812938的博客 374

【手搓 Agent 第2.3关】搭建 Agent 进阶能力:工具注册中心架构重构

本篇优化了之前编写 Agent 时的杂乱硬编码,使用工具注册中心统一调度,促使后期增添工具更加容易。顺便优化了 RAG 知识库的懒加载,使 Agent 启动更快。

2502_92964924的博客 326

Java深入解析篇二十之JavaStream API详解

Stream(流)是引入的数据处理抽象,位于包。它表示从数据源产生的元素序列,并支持对其进行函数式、聚合式操作。不是集合:流不存储数据,只描述对数据的计算;不是 IO 流:无关;惰性管道:中间操作只是登记,终端操作才触发实际计算。// 命令式写法(对照) // List<String> r = new ArrayList<>();

萧瑟余晖的博客 343

电商推返模式的技术架构系统落地实践

成功的电商推返模式系统,本质是。

weixin_42804741的博客 176

TIA博途中10种常用模拟滤波算法.docx

TIA博途中10种常用模拟滤波算法

基于YOLOv8的细胞检测计数系统源码(部署教程+训练好的模型+各项评估指标曲线).zip

基于YOLOv8的细胞检测计数系统源码(部署教程+训练好的模型+各项评估指标曲线).zip平均准确率:0.98类别:RBC、WBC、platelets【资源介绍】1、ultralytics-mainultralytics-main为YOLOv8源代码,里面涵盖基于yolov8分类、目标检测额、姿态估计、图像分割四部分代码,我们使用的是detect部分,也就是目标检测代码2、搭建环境安装anaconda 和 pycharm windows系统、mac系统、Linux系统都适配在anaconda中新建一个新的envs虚拟空间(可以参考博客来),命令窗口执行:conda create -n YOLOv8 python==3.8创建完YOLOv8-GUI虚拟空间后,命令窗口执行:source activate YOLOv8 激活虚拟空间然后就在YOLOv8虚拟空间内安装requirements.txt中的所有安装包,命令窗口执行:pip install -r requirements.txt使用清华源安装更快3、训练模型过程进入到\ultralytics-main\ultralytics\yolo\v8\detect\文件夹下,datasets即为我们需要准备好的数据集,训练其他模型同理。data文件夹下的bicycle.yaml文件为数据集配置文件,该文件为本人训练自行车检测模型时创建,训练其他模型,可自行创建。博文有介绍https://blog.csdn.net/DeepLearning_?spm=1011.2415.3001.5343train.py中238行,修改为data = cfg.data or './bicycle.yaml' # or yolo.ClassificationDataset("mnist")237行修改自己使用的预训练模型若自己有显卡,修改239行,如我有四张显卡,即改成args = dict(model=model, data=data, device=”0,1,2,3“)以上配置完成后运行train.py开始训练模型,训练完毕后会在runs/detect/文件夹下生成train*文件夹,里面包含模型和评估指标等4、推理测试训练好模型,打开predict.py,修改87行,model = cfg.model or 'yolov8n.pt',把yolov8n.pt换成我们刚才训练完生成的模型路径(在\ultralytics-main\ultralytics\yolo\v8\detect\runs\detect文件夹下),待测试的图片或者视频存放于ultralytics\ultralytics\assets文件夹,运行predict.py即可,检测结果会在runs/detect/train文件夹下生成。

上一篇: 性能是.NET Core的一个关键特性
下一篇: 报错Unexpected token u
weixin_33890526
博客等级 码龄11年 6200粉丝 144原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值