Hi,释锐的客户和合作商们:欢迎您准备一个常用电子邮箱花1分钟时间免费注册成为“我的释锐”客户门户网站的会员。注册步骤图解如下:
第1步:右上角“登录”
第2步:登录页面左下角“创建账户”
第3步:填写帐户信息,其中,电子邮箱地址必须唯一且有效,登录必备
第4步:准备首次登录验证
第5步:查收邮箱(2封来自释锐客户服务团队的邮件),其中1封是初始密码,另1封邮件是验证码
第6步:从邮件里拿到初始密码
第7步:用初始密码首次登录
第8步:再次查收邮箱,进行Email地址验证
第9步:直接点击邮箱里面的验证地址或者拷贝 验证码 去前面的登录页面,完成Email地址验证
第10步:点击“核实”按钮完成Email验证
第11步:首次登录成功后必须设置新密码
第12步:首次登录成功后必须设置一个提示问题,在忘记密码时有用
至此,恭喜您,完成了会员注册的所有工作,祝您用网愉快,需要协助请 QQ 1723102846 或者电话 021-60753203 。
新闻标签云 新闻标签云
最新论坛&教育社区帖子 最新论坛&教育社区帖子
• Android 回音消除(AcousticEchoCanceler)的使用
回音消除Google 开发文档原文: /** * Acoustic Echo Canceler (AEC). * <p>Acoustic Echo Canceler (AEC) is an audio pre-processor which removes the contribution of the * signal received from the remote party from the captured audio signal. * <p>AEC is used by voice communication applications (voice chat, video conferencing, SIP calls) * where the presence of echo with significant delay in the signal received from the remote party * is highly disturbing. AEC is often used in conjunction with noise suppression (NS). * <p>An application creates an AcousticEchoCanceler object to instantiate and control an AEC * engine in the audio capture path. * <p>To attach the AcousticEchoCanceler to a particular {@link android.media.AudioRecord}, * specify the audio session ID of this AudioRecord when creating the AcousticEchoCanceler. * The audio session is retrieved by calling * {@link android.media.AudioRecord#getAudioSessionId()} on the AudioRecord instance. * <p>On some devices, an AEC can be inserted by default in the capture path by the platform * according to the {@link android.media.MediaRecorder.AudioSource} used. The application should * call AcousticEchoCanceler.getEnable() after creating the AEC to check the default AEC activation * state on a particular AudioRecord session. * <p>See {@link android.media.audiofx.AudioEffect} class for more details on * controlling audio effects. */ 场景就是在手机播放声音和声音录制同时进行,但是手机播放的声音不会被本机录制,达到了消除的效果。微信对讲的最适合不过了,但是微信的回音消除好像是不是自己弄的。 文档大致意思:创建android.media.AudioRecord 对象的时候,可以通过这个对象获取到一个audio session 的ID,获取方法getAudioSessionId(),这个ID在创建AcousticEchoCanceler的时候要用到(创建对象:AcousticEchoCanceler.create(audioSessionId)),最后播放音频时(这里是用AudioTrack播放)传入这个ID就行了。 1.首先创建AudioRecord对象,里面的参数可以自己查资料知道什么是采样率,声道,位数。 private AudioRecord mRecorder; private byte[] pcm; private int mRecorderBufferSize; /** * 初始化录音 */ public void initRecorder() { mRecorderBufferSize = AudioRecord.getMinBufferSize(8000, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT); pcm = new byte[320]; mRecorder = new AudioRecord(MediaRecorder.AudioSource.VOICE_COMMUNICATION, 8000, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, mRecorderBufferSize); } 2.其次,初始化AudioTrack(注意下传入的audioSessionId) private AudioRecord mRecorder; private byte[] pcm; private int mRecorderBufferSize; /** * 初始化录音 */ public void initRecorder() { mRecorderBufferSize = AudioRecord.getMinBufferSize(8000, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT); pcm = new byte[320]; mRecorder = new AudioRecord(MediaRecorder.AudioSource.VOICE_COMMUNICATION, 8000, AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT, mRecorderBufferSize); } 3.最后创建AcousticEchoCanceler private AcousticEchoCanceler acousticEchoCanceler; private void initAEC() { if (AcousticEchoCanceler.isAvailable()) { if (acousticEchoCanceler == null) { acousticEchoCanceler = AcousticEchoCanceler.create(audioSessionId); Log.d(TAG, "initAEC: ---->" + acousticEchoCanceler + "\t" + audioSessionId); if (acousticEchoCanceler == null) { Log.e(TAG, "initAEC: ----->AcousticEchoCanceler create fail."); } else { acousticEchoCanceler.setEnabled(true); } } } } 4.最后播放就可以了(OK) public void write(byte[] data) { if (mAudioTrack != null && mAudioTrack.getPlayState() == AudioTrack.PLAYSTATE_PLAYING) { mAudioTrack.write(data, 0, data.length); } } 读取更多关于Android 回音消除(AcousticEchoCanceler)的使用 »
• 从MVC原理开始手敲一个MVC框架,体会当大神的乐趣
每一个程序员,在刚入行时学的第一个框架应该就是ssm了,其他的各种学习框架都是后期在工作中,随着业务的不断复杂,在工作和bug中不断成长起来的,但是最经典的应该还是最一开始的时候ssm框架吧 当时刚学习这个时候,就觉得,好牛啊,这样就可以实现一个网站,这群大神是怎么做到的啊,嘿嘿嘿,不知道大家当时有没有这样的问题产生,所以今天就带大家来搭建一个简单的mvc框架,从原理讲起,也能帮助大家更好的理解底层源码 好了,话不多说,我们来看一下 Springmvc基本原理流程 SpringMvc本质上就是对Servlet的封装。 因为创建一个Maven项目,然后在pom文件中增加一个依赖: <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <!-- 部署在服务器时,不使用这个servlet-api 而使用tomcat的--> <scope>provided</scope> </dependency> 2,创建DispatcherServlet,并注册到web.xml中 package com.dxh.edu.mvcframework.servlet; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; public class DxhDispatcherServlet extends HttpServlet { /** * 接收处理请求 */ @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { doPost(req, resp); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { } } web.xml: <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" "http://java.sun.com/dtd/web-app_2_3.dtd" > <web-app> <display-name>Archetype Created Web Application</display-name> <servlet> <servlet-name>dxhmvc</servlet-name> <servlet-class>com.dxh.edu.mvcframework.servlet.DxhDispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>springmvc.properties</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>dxhmvc</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app> 2,注解开发 因为要使用到注解,所以首先要自定义几个注解: 这里就不赘述如何自定义注解了,详情请看:https://www.cnblogs.com/peida/archive/2013/04/24/3036689.html Controller注解: @Documented @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface DxhController { String value() default ""; } Service注解: @Documented @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface DxhService { String value() default ""; } RequestMapping注解: @Documented @Target({ElementType.TYPE,ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface DxhRequestMapping { String value() default ""; } Autowired注解: @Documented @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface DxhAutowired { String value() default ""; } 编写测试代码: 测试代码我们放在同项目中的com.dxh.demo包中: package com.dxh.demo.controller; import com.dxh.demo.service.IDemoService; import com.dxh.edu.mvcframework.annotations.DxhAutowired; import com.dxh.edu.mvcframework.annotations.DxhController; import com.dxh.edu.mvcframework.annotations.DxhRequestMapping; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; @DxhController @DxhRequestMapping("/demo") public class DemoController { @DxhAutowired private IDemoService demoService; /** * URL:/demo/query */ @DxhRequestMapping("/query") public String query(HttpServletRequest request, HttpServletResponse response, String name){ return demoService.get(name); } } package com.dxh.demo.service; public interface IDemoService { String get(String name); } package com.dxh.demo.service.impl; import com.dxh.demo.service.IDemoService; import com.dxh.edu.mvcframework.annotations.DxhService; @DxhService("demoService") public class IDemoServiceImpl implements IDemoService { @Override public String get(String name) { System.out.println("Service实现类中的Name:"+ name); return name; } } 目录结构: 3,编写自定义DispatcherServlet中的初始化流程: 在创建好的DxhDispatcherServlet中重写init()方法,并在init方法中做初始化配置: 加载配置文件 springmvc.properties 扫描相关的类——扫描注解 初始化Bean对象(实现IOC容器,基于注解) 实现依赖注入 构造一个handleMapping处理器映射器,将配置好的url和method建立映射关系 @Override public void init(ServletConfig config) throws ServletException { //1. 加载配置文件 springmvc.properties String contextConfigLocation = config.getInitParameter("contextConfigLocation"); doLoadConfig(contextConfigLocation); //2. 扫描相关的类——扫描注解 doScan(""); //3. 初始化Bean对象(实现IOC容器,基于注解) doInstance(); //4. 实现依赖注入 doAutoWired(); //5. 构造一个handleMapping处理器映射器,将配置好的url和method建立映射关系 initHandleMapping(); System.out.println("MVC 初始化完成"); //6. 等待请求进入处理请求 } 以及5个空方法,这篇文章自定义MVC框架其实就是需要对这5个步骤的编写。 //TODO 5,构造一个映射器 private void initHandleMapping() { } //TODO 4,实现依赖注入 private void doAutoWired() { } //TODO 3,IOC容器 private void doInstance() { } //TODO 2,扫描类 private void doScan(String scanPackage) { } //TODO 1,加载配置文件 private void doLoadConfig(String contextConfigLocation) { } 3.1 加载配置文件 首先在resource目录中创建一个配置文件——springmvc.properties 表示要扫描com.dxh.demo下的所有注解。 然后在web.xml中进行配置: 这样,就可以通过config.getInitParameter("contextConfigLocation")获得这个路径。 在DxhDispatcherServlet中定义一个属性,我们把加载后的配置文件中的信息,存储在Properties 中 private Properties properties = new Properties();; //1,加载配置文件 private void doLoadConfig(String contextConfigLocation) { //根据指定路径加载成流: InputStream resourceAsStream = this.getClass().getClassLoader().getResourceAsStream(contextConfigLocation); try { properties.load(resourceAsStream); } catch (IOException e) { e.printStackTrace(); } } 3.2 扫描相关的类,扫描注解 上一步骤,我们已经把需要扫描的包存在Properties中,所以这里需要取出: //2. 扫描相关的类——扫描注解 doScan(properties.getProperty("scanPackage")); 把扫描到的类型的全类名存在一个List中缓存起来,等待使用,在DxhDispatcherServlet中定义一个list: //缓存扫描到的类的全类名 private List<String> classNames = new ArrayList<>(); 从配置文件中我们得到了一个需要扫描的包名(com.dxh.demo),我们需要根据classPath+包名,来得到它实际上在磁盘上存的路径,然后递归,直到把所有的该包下(包括子包...)所有的类文件(.class结尾)。然后存在在List classNames中。 //2,扫描类 //scanPackage :com.dxh.demo package--->磁盘的文件夹(File) private void doScan(String scanPackage) { //1.获得classPath路径 String clasPath = Thread.currentThread().getContextClassLoader().getResource("").getPath(); //2.拼接,得到scanPackage在磁盘上的路径 String scanPackagePath= clasPath + scanPackage.replaceAll("\\.","/"); File pack = new File(scanPackagePath); File[] files = pack.listFiles(); for (File file : files) { if (file.isDirectory()){ //子 package //递归 doScan(scanPackage+"."+file.getName()); //com.dxh.demo.controller }else if(file.getName().endsWith(".class")){ String className = scanPackage + "." + file.getName().replace(".class", ""); classNames.add(className); } } } 3.3 初始化Bean对象(实现IOC容器,基于注解) 上一步骤我们把扫描到的类的全类名放到了,list中,那么本次步骤需要遍历整个list: 遍历List,依次得到所有的全类名 通过反射得到类对象 根据类对象判断有没有注解,并区分controller和servicecontroller,它的id此处不做过多处理,不取value了,用类的首字母小写作为id,保存到IOC容器中。service,service层往往是有接口的,再以接口名为id再存入一份bean到ioc,便于后期根据接口类型注入 完成 代码实现: //IOC容器 private Map<String,Object> ioc = new HashMap<>(); //3,IOC容器 //基于classNames缓存的类的全限定类名,以及反射技术,完成对象创建和管理 private void doInstance() { if (classNames.size()==0) return; try{ for (int i = 0; i < classNames.size(); i++) { String className = classNames.get(i); //com.dxh.demo.controller.DemoController //反射 Class<?> aClass = Class.forName(className); //区分controller ,区分service if (aClass.isAnnotationPresent(DxhController.class)){ //controller的id此处不做过多处理,不取value了,用类的首字母小写作为id,保存到IOC容器中 String simpleName = aClass.getSimpleName();//DemoController String lowerFirstSimpleName = lowerFirst(simpleName); //demoController Object bean = aClass.newInstance(); ioc.put(lowerFirstSimpleName,bean); }else if (aClass.isAnnotationPresent(DxhService.class)){ DxhService annotation = aClass.getAnnotation(DxhService.class); //获取注解的值 String beanName = annotation.value(); //指定了id就以指定的id为准 if (!"".equals(beanName.trim())){ ioc.put(beanName,aClass.newInstance()); }else{ //没有指定id ,首字母小写 String lowerFirstSimpleName = lowerFirst(aClass.getSimpleName()); ioc.put(lowerFirstSimpleName,aClass.newInstance()); } //service层往往是有接口的,再以接口名为id再存入一分bean到ioc,便于后期根据接口类型注入 Class<?>[] interfaces = aClass.getInterfaces(); for (Class<?> anInterface : interfaces) { //以接口的类名作为id放入。 ioc.put(anInterface.getName(),aClass.newInstance()); } }else { continue; } } }catch (Exception e){ e.printStackTrace(); } } 3.4 实现依赖注入: 上一步骤把所有需要加载的bean,存入了ioc Map中,此时,我们就需要遍历这个map然后依次得到每个bean对象,然后判断对象中有没有被@****DxhAutowired修饰的属性。 遍历ioc这个map,得到每个对象 获取对象的字段(属性)信息 判断字段是否被@DxhAutowired修饰 判断@DxhAutowired有没有设置value值有,直接从ioc容器中取出,然后设置属性。无,需要根据当前字段的类型注入(接口注入) 代码实现: //4,实现依赖注入 private void doAutoWired() { if (ioc.isEmpty()){return;} //1,判断容器中有没有被@DxhAutowried注解的属性,如果有需要维护依赖注入关系 for (Map.Entry<String,Object> entry: ioc.entrySet()){ //获取bean对象中的字段信息 Field[] declaredFields = entry.getValue().getClass().getDeclaredFields(); for (Field declaredField : declaredFields) { if (!declaredField.isAnnotationPresent(DxhAutowired.class)){ continue; } //有该注解: DxhAutowired annotation = declaredField.getAnnotation(DxhAutowired.class); String beanName = annotation.value(); //需要注入的bean的Id if ("".equals(beanName.trim())){ //没有配置具体的beanId,需要根据当前字段的类型注入(接口注入) IDemoService beanName = declaredField.getType().getName(); } //开启赋值 declaredField.setAccessible(true); try { //字段调用,两个参数:(哪个对象的字段,传入什么) declaredField.set(entry.getValue(),ioc.get(beanName)); } catch (IllegalAccessException e) { e.printStackTrace(); } } } } 3.5 构造一个handleMapping处理器映射器 构造一个handleMapping处理器映射器,将配置好的url和method建立映射关系****。 手写MVC框架最关键的环节 假设有一个: 那么如何通过/demo/query定位到 DemoController类中的query这个方法 ? 之前我们所有被@DxhController(自定义Controller注解)的类,都存在了ioc 这个map中。 我们可以遍历这个map,得到每个bean对象 然后判断是否被@DxhController所修饰(排除@DxhService所修饰的bean) 然后判断是否被@DxhRequestMapping所修饰,有的话,就取其value值,作为baseUrl 然后遍历该bean对象中的所有方法,得到被@DxhRequestMapping修饰的方法。得到其value值,作为methodUrl。 baseUrl + methodUrl = url 我们把url和当前method绑定起来,存在map中,也就是建立了url和method建立映射关系。 代码实现: //handleMapping ,存储url和method直接的映射关系 private Map<String,Object> handleMapping = new HashMap<>(); //5,构造一个映射器,将url和method进行关联 private void initHandleMapping() { if (ioc.isEmpty()){return;} for (Map.Entry<String,Object> entry: ioc.entrySet()){ //获取ioc中当前遍历对象的class类型 Class<?> aClass = entry.getValue().getClass(); //排除非controller层的类 if (!aClass.isAnnotationPresent(DxhController.class)){ continue; } String baseUrl = ""; if (aClass.isAnnotationPresent(DxhRequestMapping.class)){ //Controller层 类上 注解@DxhRequestMapping中的value值 baseUrl = aClass.getAnnotation(DxhRequestMapping.class).value(); } //获取方法 Method[] methods = aClass.getMethods(); for (Method method : methods) { //排除没有@DxhRequestMapping注解的方法 if (!method.isAnnotationPresent(DxhRequestMapping.class)){continue;} //Controller层 类中方法上 注解@DxhRequestMapping中的value值 String methodUrl = method.getAnnotation(DxhRequestMapping.class).value(); String url = baseUrl+methodUrl; //建立url和method之间的映射关系,用map缓存起来 handleMapping.put(url,method); } } } 4,测试一下: 到目前位置,还没有完全写完,但是不妨碍我们测试一下看看刚才写的那部分内容有没有什么问题: 完整的pom文件: <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.dxh.edu</groupId> <artifactId>mvc</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <name>mvc Maven Webapp</name> <url>http://www.example.com</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.5</version> <!-- 部署在服务器时,不使用这个servlet-api 而使用tomcat的--> <scope>provided</scope> </dependency> </dependencies> <build> <plugins> <plugins> <!-- 编译插件定义编译细节--> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.2</version> <configuration> <source>11</source> <target>11</target> <encoding>utf-8</encoding> <!-- 告诉编译器,编译的时候记录下形参的真实名称--> <compilerArgs> <arg>-parameters</arg> </compilerArgs> </configuration> </plugin> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <version>2.2</version> <configuration> <port>8080</port> <path>/</path> </configuration> </plugin> </plugins> </build> </project> pom文件中加入了一个tomcat插件,并设置端口为8080,因此我们通过tomcat启动项目: 启动完成后,打开浏览器url中输入: http://localhost:8080/demo/query 浏览器中什么都没返回(我们的代码还没真正的完成,尚未编写处理请求步骤),同时控制台中打印了MVC初始化完成,可以认为,目前的代码没有明显的缺陷。 我们继续~~~~~ 5,改造initHandleMapping() 5.1 为什么改造? DxhDispatcherServlet这个类继承了HttpServlet,并重写了doGet和doPost方法,在doGet中调用了doPost方法,当我们使用反射调用方法时(method.invoke(......))发现少了一部分参数: 因此我们要改造initHandleMapping(),修改url和method的映射关系(不简简单单的存入map中)。 5.2 新建Handler类 package com.dxh.edu.mvcframework.pojo; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import java.util.regex.Pattern; public class Handler { //method.invoke(obj,)需要 private Object controller; private Method method; //spring中url支持正则 private Pattern pattern; //参数的顺序,为了进行参数绑定 ,Key 参数名, Value 代表第几个参数 private Map<String,Integer> paramIndexMapping; public Handler(Object controller, Method method, Pattern pattern) { this.controller = controller; this.method = method; this.pattern = pattern; this.paramIndexMapping = new HashMap<>(); } //getset方法这里省略,实际代码中需要... } 在Handler类中编写了4个属性: private Object controller:method.invoke(obj,)需要 private Method method:与url绑定的方法 private Pattern pattern:可以通过正则匹配,也可以直接写String url。 private Map<String,Integer> paramIndexMapping:参数的顺序,为了进行参数绑定 ,Key 参数名, Value 代表第几个参数 5.3 修改initHandleMapping() 首先,就不能直接通过Map<url,Method>的得方式进行关系映射了,使用一个list,泛型是刚才创建的Handler。 //handleMapping ,存储url和method直接的映射关系 // private Map<String,Method> handleMapping = new HashMap<>(); private List<Handler> handlerMapping = new ArrayList<>(); 改动前,改动后代码对比: 改动后的initHandleMapping(): //5,构造一个映射器,将url和method进行关联 private void initHandleMapping() { if (ioc.isEmpty()){return;} for (Map.Entry<String,Object> entry: ioc.entrySet()){ //获取ioc中当前遍历对象的class类型 Class<?> aClass = entry.getValue().getClass(); //排除非controller层的类 if (!aClass.isAnnotationPresent(DxhController.class)){ continue; } String baseUrl = ""; if (aClass.isAnnotationPresent(DxhRequestMapping.class)){ //Controller层 类上 注解@DxhRequestMapping中的value值 baseUrl = aClass.getAnnotation(DxhRequestMapping.class).value(); } //获取方法 Method[] methods = aClass.getMethods(); for (Method method : methods) { //排除没有@DxhRequestMapping注解的方法 if (!method.isAnnotationPresent(DxhRequestMapping.class)){continue;} //Controller层 类中方法上 注解@DxhRequestMapping中的value值 String methodUrl = method.getAnnotation(DxhRequestMapping.class).value(); String url = baseUrl+methodUrl; //把method所有信息以及url封装为Handler Handler handler = new Handler(entry.getValue(),method, Pattern.compile(url)); //处理计算方法的参数位置信息 Parameter[] parameters = method.getParameters(); for (int i = 0; i < parameters.length; i++) { Parameter parameter = parameters[i]; //不做太多的参数类型判断,只做:HttpServletRequest request, HttpServletResponse response和基本类型参数 if (parameter.getType()==HttpServletRequest.class||parameter.getType()==HttpServletResponse.class){ //如果时request和response对象,那么参数名称存 HttpServletRequest 和 HttpServletResponse handler.getParamIndexMapping().put(parameter.getType().getSimpleName(),i); }else{ handler.getParamIndexMapping().put(parameter.getName(),i); } } handlerMapping.add(handler); } } } 6, 请求处理开发 doPost(): 上一步骤,我们配置了 uri和method的映射关系,并封装到了Handler中存入list,那么接下来,就要通过HttpServletRequest,取出uri,然后找到具体的Handler: 通过HttpServletRequest取出uri找到具体的Handler 得到将调用方法的参数的数组 根据上述数组长度创建一个新的数组(参数数组,传入反射调用的) 通过req.getParameterMap()得到前台传来的参数parameterMap 遍历parameterMap 通过StringUtils.join方法把name=1&name=2格式的参数变为name[1,2] (需要commons-lang依赖) 参数匹配并设置 private Handler getHandler(HttpServletRequest req) { if (handlerMapping.isEmpty()){return null;} String url = req.getRequestURI(); //遍历 handlerMapping for (Handler handler : handlerMapping) { Matcher matcher = handler.getPattern().matcher(url); if (!matcher.matches()){continue;} return handler; } return null; } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException { //根据uri获取到能够处理当前请求的Handler(从handlerMapping中(list)) Handler handler = getHandler(req); if (handler==null){ resp.getWriter().write("404 not found"); return; } //参数绑定 //该方法所有参数得类型数组 Class<?>[] parameterTypes = handler.getMethod().getParameterTypes(); //根据上述数组长度创建一个新的数组(参数数组,传入反射调用的) Object[] paramValues = new Object[parameterTypes.length]; //以下就是为了向参数数组中设值,而且还得保证参数得顺序和方法中形参顺序一致。 Map<String,String[]> parameterMap = req.getParameterMap(); //遍历request中所有的参数 ,(填充除了request、response之外的参数) for (Map.Entry<String,String[]> entry: parameterMap.entrySet()){ //name=1&name=2 name[1,2] String value = StringUtils.join(entry.getValue(), ",");// 如同 1,2 //如果参数和方法中的参数匹配上了,填充数据 if (!handler.getParamIndexMapping().containsKey(entry.getKey())){continue;} //方法形参确实有该参数,找到它得索引位置,对应得把参数值放入paramValues Integer index = handler.getParamIndexMapping().get(entry.getKey()); //把前台传递过来的参数值,填充到对应得位置去 paramValues[index] = value; } Integer requestIndex = handler.getParamIndexMapping().get(HttpServletRequest.class.getSimpleName()); paramValues[requestIndex] = req; Integer responseIndex = handler.getParamIndexMapping().get(HttpServletResponse.class.getSimpleName()); paramValues[responseIndex] = resp; //最终调用handler得method属性 try { Object invoke = handler.getMethod().invoke(handler.getController(), paramValues); //简单操作,把方法返回的数据以字符串的形式写出 resp.getWriter().write(invoke.toString()); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } } 7,测试: 打开浏览器,url中输入:http://localhost:8080/demo/query?name=lisi 返回: 控制台中打印出: OK完成~ 转自:https://www.toutiao.com/i6903531694301676035/ 读取更多关于从MVC原理开始手敲一个MVC框架,体会当大神的乐趣 »
• 什么是 Lambda?该如何使用?
什么是Lambda? 我们知道,对于一个Java变量,我们可以赋给其一个“值”。 如果你想把“一块代码”赋给一个Java变量,应该怎么做呢? 比如,我想把右边那块代码,赋给一个叫做aBlockOfCode的Java变量: 在Java 8之前,这个是做不到的。但是Java 8问世之后,利用Lambda特性,就可以做到了。 当然,这个并不是一个很简洁的写法。所以,为了使这个赋值操作更加elegant, 我们可以移除一些没用的声明。 这样,我们就成功的非常优雅的把“一块代码”赋给了一个变量。而“这块代码”,或者说“这个被赋给一个变量的函数”,就是一个Lambda表达式。 但是这里仍然有一个问题,就是变量aBlockOfCode的类型应该是什么? 在Java 8里面,所有的Lambda的类型都是一个接口,而Lambda表达式本身,也就是”那段代码“,需要是这个接口的实现。这是我认为理解Lambda的一个关键所在,简而言之就是,Lambda表达式本身就是一个接口的实现。直接这样说可能还是有点让人困扰,我们继续看看例子。我们给上面的aBlockOfCode加上一个类型: 这种只有一个接口函数需要被实现的接口类型,我们叫它”函数式接口“。为了避免后来的人在这个接口中增加接口函数导致其有多个接口函数需要被实现,变成"非函数接口”,我们可以在这个上面加上一个声明@FunctionalInterface, 这样别人就无法在里面添加新的接口函数了: 这样,我们就得到了一个完整的Lambda表达式声明: Lambda表达式有什么作用? 最直观的作用就是使得代码变得异常简洁。 我们可以对比一下Lambda表达式和传统的Java对同一个接口的实现: 这两种写法本质上是等价的。但是显然,Java 8中的写法更加优雅简洁。并且,由于Lambda可以直接赋值给一个变量,我们就可以直接把Lambda作为参数传给函数, 而传统的Java必须有明确的接口实现的定义,初始化才行: 有些情况下,这个接口实现只需要用到一次。传统的Java 7必须要求你定义一个“污染环境”的接口实现MyInterfaceImpl,而相较之下Java 8的Lambda, 就显得干净很多。 Lambda结合FunctionalInterface Lib, forEach, stream(),method reference等新特性可以使代码变的更加简洁! 直接上例子。 假设Person的定义和List<Person>的值都给定。 现在需要你打印出guiltyPersons List里面所有LastName以"Z"开头的人的FirstName。 原生态Lambda写法:定义两个函数式接口,定义一个静态函数,调用静态函数并给参数赋值Lambda表达式。 这个代码实际上已经比较简洁了,但是我们还可以更简洁么? 当然可以。在Java 8中有一个函数式接口的包,里面定义了大量可能用到的函数式接口(java.util.function (Java Platform SE 8 ))。所以,我们在这里压根都不需要定义NameChecker和Executor这两个函数式接口,直接用Java 8函数式接口包里的Predicate<T>和Consumer<T>就可以了——因为他们这一对的接口定义和NameChecker/Executor其实是一样的。 第一步简化 - 利用函数式接口包: 静态函数里面的for each循环其实是非常碍眼的。这里可以利用Iterable自带的forEach()来替代。forEach()本身可以接受一个Consumer<T> 参数。 第二步简化 - 用Iterable.forEach()取代foreach loop: 由于静态函数其实只是对List进行了一通操作,这里我们可以甩掉静态函数,直接使用stream()特性来完成。stream()的几个方法都是接受Predicate<T>,Consumer<T>等参数的(java.util.stream (Java Platform SE 8 ))。你理解了上面的内容,stream()这里就非常好理解了,并不需要多做解释。 第三步简化 - 利用stream()替代静态函数: 对比最开始的Lambda写法,这里已经非常非常简洁了。但是如果,我们的要求变一下,变成print这个人的全部信息,及p -> System.out.println(p); 那么还可以利用Method reference来继续简化。所谓Method reference, 就是用已经写好的别的Object/Class的method来代替Lambda expression。格式如下: 第四步简化 - 如果是println(p),则可以利用Method reference代替forEach中的Lambda表达式: 这基本上就是能写的最简洁的版本了。 Lambda配合Optional<T>可以使Java对于null的处理变的异常优雅 这里假设我们有一个person object,以及一个person object的Optional wrapper: Optional<T>如果不结合Lambda使用的话,并不能使原来繁琐的null check变的简单。 只有当Optional<T>结合Lambda一起使用的时候,才能发挥出其真正的威力! 我们现在就来对比一下下面四种常见的null处理中,Java 8的Lambda+Optional<T>和传统Java两者之间对于null的处理差异。 情况一 - 存在则开干 情况二 - 存在则返回,无则返回屁 情况三 - 存在则返回,无则由函数产生 情况四 - 夺命连环null检查 由上述四种情况可以清楚地看到,Optional<T>+Lambda可以让我们少写很多ifElse块。尤其是对于情况四那种夺命连环null检查,传统java的写法显得冗长难懂,而新的Optional<T>+Lambda则清新脱俗,清楚简洁。 来源:https://www.zhihu.com/question/20125256/answer/324121308 读取更多关于什么是 Lambda?该如何使用? »
• 如何 发布直播资源并开展在线直播评课活动?
如何 开展网络直播评课活动? 开展网络直播评课活动的总流程跟《释锐 听课评课应用系统 使用总流程》基本一致,但是有两点需要特别注意: 第一点,参赛教师在提交参赛作品时必须【创建一个直播类教育资源】,该资源要预先发布并且完成审核工作; 第二点,由于是直播评课,评委必须在老师上课的时间段内完成评课,评课方式跟录播视频评课完全一样,直播视频可能有20秒左右的时间延迟。 如何创建一个直播视频类在线教育资源? 图1:HLS直播拉流网址 第1步:图1所示,登录云桌面系统,进入“我的个人资料-音视频”栏目,找到您的HLS直播拉流网址(如果空,代表手机号无效,填上有效的手机号即可开通),格式 https://XXX/YYY/ZZZ.m3u8,其中,XXX是直播服务器地址,YYY是直播应用地址(hls代表只直播不录播,hls4vip代表直播结束后自动录播,请在厂家指导下设置音视频参数),ZZZ是流媒体名称,一般是您的注册手机号或者电子邮件地址; 图2:发布一个直播视频类教育资源 第2步:图2所示,进入“教育资源公共服务平台-上传资源”页面,将第1步找到的HLS直播拉流网址填入资源输入框内(切记不要点击“选择一个资源文件”按钮); 图3:发布直播时间预告和活动封面图 第3步:图3所示,进入“ 第2步:首次编目资源”,完善画圈处的内容,尤其是 直播时间预告; 第4步:等待管理员审核通过,上线后即可作为参赛作品报名参赛评课; 图4:直播前评委评课界面(上课直播开始30秒之内,评委就能看到直播画面) 第5步:图4所示,上课的时间,评委远程同步参与评课。 读取更多关于如何 发布直播资源并开展在线直播评课活动? »
• 如何 用VLC和微信APP看合育宝直播视频?
如何用电脑版VLC工具观看合育宝直播? 从VLC官网下载并安装好VLC Player软件; 打开VLC Player软件; 点击“媒体-打开网络串流”菜单; 输入 rtmp://live.heyubao.com/live/139****4057?key=06***2 或者 https://heyubao.com/hls/139****4057.m3u8 格式的网络URL,点击播放即可观看合育宝直播视频。 如何用手机版VLC工具观看合育宝直播? 从苹果手机的 app store 或者 安卓 应用商店搜索 VLC for mobile 手机应用程序,并且安装好该APP; 打开VLC应用程序; 点击“网络-打开网络串流”栏目; 输入 rtmp://live.heyubao.com/live/139****4057?key=06***2 或者 https://heyubao.com/hls/139****4057.m3u8 格式的网络URL,点击“打开网络串流”按钮即可观看合育宝直播视频。 如何用微信APP观看合育宝直播? 打开微信APP; 搜索并打开 腾讯视频云 小程序; 点击 直播播放; 扫码 rtmp://live.heyubao.com/live/139****4057?key=06***2 格式的合育宝直播视频源 二维码,好像不支持 m3u8格式的直播视频源; 点击 播放 即可观看合育宝直播视频。 读取更多关于如何 用VLC和微信APP看合育宝直播视频? »
• K12有关学段问题导致学科没有正常显示
现象:巫溪县教育资源公共服务平台【学科】没有正常显示。 原因:添加了三个职业高中学段,而系统默认以学段3为分界点,高于学段3的学校归属高校范畴,而低于等于学段3(即0-12年级)的学校归属k12中小学范畴。 解决方案:修改云桌面系统,将学段分界点从3改到6,即中专含中专及一下的学段都归属为中小学。 读取更多关于K12有关学段问题导致学科没有正常显示 »
• 带你揭开BFC(Block Formatting Context)的神秘面纱
原创黑马程序员2020-07-22 15:55:36 1. 引言 在前端的布局手段中,一直有这么一个知识点,很多前端开发者都知道有它的存在,但是很多人也仅仅是知道它的存在而已,对它的作用也只是将将说得出来,可是却没办法说得非常的清晰。这个知识点,就是BFC。想要了解BFC的规则,前提必须是熟悉前端网页的多种布局手段,例如盒的显示模式display,三种布局手段标准流(normal)、浮动流(float)、定位流(position)等。你只有熟练掌握了这些布局手段之后,才能很好的理解BFC。今天这篇文章,来大家解析一下BFC,希望对各位新老朋友有所帮助。 2. 定义 BFC - Block Formatting Context 块级格式化上下文 BFC的定义,在官方文档到中,是这么介绍BFC的。 A block formatting context contains everything inside of the element creating it that is not also inside a descendant element that creates a new block formatting context. 强行翻译一下吧,简单来说,这句话的意思就是: 一个BFC区域包含创建该上下文元素的所有子元素,但是不包括创建了新的BFC的子元素的内部元素 很显然,哪怕强行翻译了,大部分人依旧是看不懂这句话的。看都看不懂,那自然就没什么能把它说明白。talk is cheap, show me the code.看不懂意思,我用代码来给你演示。 <div class="box1" id="HM_bfc1"> <div class="box2"></div> <div class="box3"></div> <div class="box4"></div> <div class="box5" id="HM_bfc2"> <div class="box6"></div> <div class="box7"></div> <div class="box8"></div> </div> </div> 用这段代码来解释上面那段BFC定义的话,就应该是这个意思:#HM_bfc1是一块BFC区域,这块区域包含了box2、box3、box4、box5,也就是所有#HM_bfc1的子元素。同时#HM_bfc2也创造了一块BFC区域,包含了box6,box7,box8。注意,第一个box1的BFC,只包括box1的子元素box2345,不包括box678。#HM_bfc2这个BFC同样也仅仅是包括自己的子元素box678。 划重点 每一个BFC区域只包括其子元素,不包括其子元素的子元素。(这1点比较容易理解) 每一个BFC区域都是独立隔绝的,互不影响!(这点不太好理解,但是后续会使用代码验证) 看完上面的描述,很多朋友依旧不懂,把第2节用心的再读一遍,相信你会有新的收获。然后往下继续阅读,你会豁然开朗。 3. 触发BFC 并不是任意一个元素都可以被当做BFC,只有当这个元素满足以下任意一个条件的时候,这个元素才会被当做一个BFC。 触发BFC的条件 body根元素 设置浮动,不包括none 设置定位,absoulte或者fixed 行内块显示模式,inline-block 设置overflow,即hidden,auto,scroll 表格单元格,table-cell 弹性布局,flex 上代码说明 首先, body元素是1个BFC,因为它满足我们的第1个条件(body根元素),这个BFC区域包含子元素hm1234,但是不包括两个p标签,需要注意的是,hm3不是一个BFC区域,因为他不满足上面任意1个条件。如果我们希望hm3也是1个BFC区域,只要让hm3满足上面任意一个条件即可。 这个时候,hm3元素被设置为了overflow为hidden,满足上面第5个条件,所以此时,hm3就成为了一个BFC区域,这个BFC区域包含其所有子元素 – 两个p标签。 划重点: 并不是所有的元素都是BFC, 只有满足了上面的任意1个条件之后,这个元素才成为1个BFC。 一个BFC区域,只包含其所有子元素,不包含子元素的子元素. 4. 利用BFC解决问题 在你明白了解BFC的触发规则之后,那么就需要利用BFC的特点来解决我们在布局中遇到的一些问题了,还记得我们之前说过,BFC有一个特点是:**每一个BFC区域都是相互独立,互不影响的。** 4.1 解决外边距的塌陷问题(垂直塌陷) 开发中,前端的布局手段,离不开外边距margin,那么,也会遇到一些问题,例如外边距的垂直塌陷问题。 通过以上的实例,我们会发现,代码给两个div盒子,都添加了四个方向的margin,讲道理,学过数学的都知道,100+100=200.可是,盒子之间的距离,现在却之后100px。这就是很典型的margin的塌陷,两段margin重叠到了一块,互相影响。那么,如何利用BFC,让这个问题得到解决呢。回忆下,上文说过,BFC,就是一个与世隔绝的独立区域,不会互相影响,那么,我们可以将这两个盒子,放到两个BFC区域中,即可解决这个问题。 4.2 利用BFC解决包含塌陷 当父子关系的盒子,给子元素添加margin-top,有可能会把父元素一起带跑 原本,正确的显示方式,应该是粉色盒子与红色盒子的顶部距离为50px,但是由于margin的塌陷问题,导致盒子内部的布局影响到了外部。这个时候,就可以触发BFC,将父盒子变成一个独立的区域,这样在BFC区域内部的任何操作,都不会影响到外部。 4.3 当浮动产生影响的时候,可以利用BFC来清除浮动的影响 以上代码表示,一个没有设置高度的父盒子,包含着七个子元素。如果此时,所有的子元素都浮动的话。 当所有的子元素都浮动了,这个时候,父盒子失去了原有的高度,这就是浮动的影响。这个时候,同样也可用BFC的机制,来清除浮动带来的影响。使用BFC,将所有的浮动元素包裹起来。 4.4 BFC可以阻止标准流元素被浮动元素覆盖 以上情况,红色盒子浮动,蓝色盒子时标准流,默认情况下,浮动元素覆盖了标准流元素。但是,如果将蓝色盒子的BFC触发,那么情况将有所变化。 当蓝色盒子触发了BFC之后,浮动元素再也不能覆盖它了,而且还能利用这个特性,来实现蓝色盒子宽度根据红色盒子的宽度来做自动适应 5. 总结 一个BFC区域只包含其子元素,不包括其子元素的子元素. 并不是所有的元素都能成为一块BFC区域,只有当这个元素满足条件的时候才会成为一块BFC区域 不同的BFC区域之间是相互独立的,互不影响的。利用这个特性我们可以让不同BFC区域之间的布局不产生影响. 读取更多关于带你揭开BFC(Block Formatting Context)的神秘面纱 »
• Android Tutorial 1
Android is an open source and Linux-based operating system for mobile devices such as smartphones and tablet computers. Android was developed by the Open Handset Alliance, led by Google, and other companies. This tutorial will teach you basic Android programming and will also take you through some advance concepts related to Android application development. Audience This tutorial has been prepared for the beginners to help them understand basic Android programming. After completing this tutorial you will find yourself at a moderate level of expertise in Android programming from where you can take yourself to next levels. Prerequisites Android programming is based on Java programming language so if you have basic understanding on Java programming then it will be a fun to learn Android application development. What is Android? Android is an open source and Linux-based Operating System for mobile devices such as smartphones and tablet computers. Android was developed by the Open Handset Alliance, led by Google, and other companies. Android offers a unified approach to application development for mobile devices which means developers need only develop for Android, and their applications should be able to run on different devices powered by Android. The first beta version of the Android Software Development Kit (SDK) was released by Google in 2007 where as the first commercial version, Android 1.0, was released in September 2008. On June 27, 2012, at the Google I/O conference, Google announced the next Android version, 4.1 Jelly Bean. Jelly Bean is an incremental update, with the primary aim of improving the user interface, both in terms of functionality and performance. The source code for Android is available under free and open source software licenses. Google publishes most of the code under the Apache License version 2.0 and the rest, Linux kernel changes, under the GNU General Public License version 2. Why Android ? Features of Android Android is a powerful operating system competing with Apple 4GS and supports great features. Few of them are listed below − Sr.No. Feature & Description 1 Beautiful UI Android OS basic screen provides a beautiful and intuitive user interface. 2 Connectivity GSM/EDGE, IDEN, CDMA, EV-DO, UMTS, Bluetooth, Wi-Fi, LTE, NFC and WiMAX. 3 Storage SQLite, a lightweight relational database, is used for data storage purposes. 4 Media support H.263, H.264, MPEG-4 SP, AMR, AMR-WB, AAC, HE-AAC, AAC 5.1, MP3, MIDI, Ogg Vorbis, WAV, JPEG, PNG, GIF, and BMP. 5 Messaging SMS and MMS 6 Web browser Based on the open-source WebKit layout engine, coupled with Chrome's V8 JavaScript engine supporting HTML5 and CSS3. 7 Multi-touch Android has native support for multi-touch which was initially made available in handsets such as the HTC Hero. 8 Multi-tasking User can jump from one task to another and same time various application can run simultaneously. 9 Resizable widgets Widgets are resizable, so users can expand them to show more content or shrink them to save space. 10 Multi-Language Supports single direction and bi-directional text. 11 GCM Google Cloud Messaging (GCM) is a service that lets developers send short message data to their users on Android devices, without needing a proprietary sync solution. 12 Wi-Fi Direct A technology that lets apps discover and pair directly, over a high-bandwidth peer-to-peer connection. 13 Android Beam A popular NFC-based technology that lets users instantly share, just by touching two NFC-enabled phones together. Android Applications Android applications are usually developed in the Java language using the Android Software Development Kit. Once developed, Android applications can be packaged easily and sold out either through a store such as Google Play, SlideME, Opera Mobile Store, Mobango, F-droid and the Amazon Appstore. Android powers hundreds of millions of mobile devices in more than 190 countries around the world. It's the largest installed base of any mobile platform and growing fast. Every day more than 1 million new Android devices are activated worldwide. This tutorial has been written with an aim to teach you how to develop and package Android application. We will start from environment setup for Android application programming and then drill down to look into various aspects of Android applications. Categories of Android applications There are many android applications in the market. The top categories are − History of Android The code names of android ranges from A to N currently, such as Aestro, Blender, Cupcake, Donut, Eclair, Froyo, Gingerbread, Honeycomb, Ice Cream Sandwitch, Jelly Bean, KitKat, Lollipop and Marshmallow. Let's understand the android history in a sequence. What is API level? API Level is an integer value that uniquely identifies the framework API revision offered by a version of the Android platform. Platform Version API Level VERSION_CODE Android 6.0 23 MARSHMALLOW Android 5.1 22 LOLLIPOP_MR1 Android 5.0 21 LOLLIPOP Android 4.4W 20 KITKAT_WATCH KitKat for Wearables Only Android 4.4 19 KITKAT Android 4.3 18 JELLY_BEAN_MR2 Android 4.2, 4.2.2 17 JELLY_BEAN_MR1 Android 4.1, 4.1.1 16 JELLY_BEAN Android 4.0.3, 4.0.4 15 ICE_CREAM_SANDWICH_MR1 Android 4.0, 4.0.1, 4.0.2 14 ICE_CREAM_SANDWICH Android 3.2 13 HONEYCOMB_MR2 Android 3.1.x 12 HONEYCOMB_MR1 Android 3.0.x 11 HONEYCOMB Android 2.3.4 Android 2.3.3 10 GINGERBREAD_MR1 Android 2.3.2 Android 2.3.1 Android 2.3 9 GINGERBREAD Android 2.2.x 8 FROYO Android 2.1.x 7 ECLAIR_MR1 Android 2.0.1 6 ECLAIR_0_1 Android 2.0 5 ECLAIR Android 1.6 4 DONUT Android 1.5 3 CUPCAKE Android 1.1 2 BASE_1_1 Android 1.0 1 BASE You will be glad to know that you can start your Android application development on either of the following operating systems − Microsoft Windows XP or later version. Mac OS X 10.5.8 or later version with Intel chip. Linux including GNU C Library 2.7 or later. Second point is that all the required tools to develop Android applications are freely available and can be downloaded from the Web. Following is the list of software's you will need before you start your Android application programming. Java JDK5 or later version Android Studio Here last two components are optional and if you are working on Windows machine then these components make your life easy while doing Java based application development. So let us have a look how to proceed to set required environment. Set-up Java Development Kit (JDK) You can download the latest version of Java JDK from Oracle's Java site − Java SE Downloads. You will find instructions for installing JDK in downloaded files, follow the given instructions to install and configure the setup. Finally set PATH and JAVA_HOME environment variables to refer to the directory that contains java and javac, typically java_install_dir/bin and java_install_dir respectively. If you are running Windows and installed the JDK in C:\jdk1.8.0_102, you would have to put the following line in your C:\autoexec.bat file. set PATH=C:\jdk1.8.0_102\bin;%PATH% set JAVA_HOME=C:\jdk1.8.0_102 Alternatively, you could also right-click on My Computer, select Properties, then Advanced, then Environment Variables. Then, you would update the PATH value and press the OK button. On Linux, if the SDK is installed in /usr/local/jdk1.8.0_102 and you use the C shell, you would put the following code into your .cshrc file. setenv PATH /usr/local/jdk1.8.0_102/bin:$PATH setenv JAVA_HOME /usr/local/jdk1.8.0_102 Alternatively, if you use Android studio, then it will know automatically where you have installed your Java. Android IDEs There are so many sophisticated Technologies are available to develop android applications, the familiar technologies, which are predominantly using tools as follows Android Studio Eclipse IDE(Deprecated) Android operating system is a stack of software components which is roughly divided into five sections and four main layers as shown below in the architecture diagram. Linux kernel At the bottom of the layers is Linux - Linux 3.6 with approximately 115 patches. This provides a level of abstraction between the device hardware and it contains all the essential hardware drivers like camera, keypad, display etc. Also, the kernel handles all the things that Linux is really good at such as networking and a vast array of device drivers, which take the pain out of interfacing to peripheral hardware. Libraries On top of Linux kernel there is a set of libraries including open-source Web browser engine WebKit, well known library libc, SQLite database which is a useful repository for storage and sharing of application data, libraries to play and record audio and video, SSL libraries responsible for Internet security etc. Android Libraries This category encompasses those Java-based libraries that are specific to Android development. Examples of libraries in this category include the application framework libraries in addition to those that facilitate user interface building, graphics drawing and database access. A summary of some key core Android libraries available to the Android developer is as follows − android.app − Provides access to the application model and is the cornerstone of all Android applications. android.content − Facilitates content access, publishing and messaging between applications and application components. android.database − Used to access data published by content providers and includes SQLite database management classes. android.opengl − A Java interface to the OpenGL ES 3D graphics rendering API. android.os − Provides applications with access to standard operating system services including messages, system services and inter-process communication. android.text − Used to render and manipulate text on a device display. android.view − The fundamental building blocks of application user interfaces. android.widget − A rich collection of pre-built user interface components such as buttons, labels, list views, layout managers, radio buttons etc. android.webkit − A set of classes intended to allow web-browsing capabilities to be built into applications. Having covered the Java-based core libraries in the Android runtime, it is now time to turn our attention to the C/C++ based libraries contained in this layer of the Android software stack. Android Runtime This is the third section of the architecture and available on the second layer from the bottom. This section provides a key component called Dalvik Virtual Machine which is a kind of Java Virtual Machine specially designed and optimized for Android. The Dalvik VM makes use of Linux core features like memory management and multi-threading, which is intrinsic in the Java language. The Dalvik VM enables every Android application to run in its own process, with its own instance of the Dalvik virtual machine. The Android runtime also provides a set of core libraries which enable Android application developers to write Android applications using standard Java programming language. Application Framework The Application Framework layer provides many higher-level services to applications in the form of Java classes. Application developers are allowed to make use of these services in their applications. The Android framework includes the following key services − Activity Manager − Controls all aspects of the application lifecycle and activity stack. Content Providers − Allows applications to publish and share data with other applications. Resource Manager − Provides access to non-code embedded resources such as strings, color settings and user interface layouts. Notifications Manager − Allows applications to display alerts and notifications to the user. View System − An extensible set of views used to create application user interfaces. Applications You will find all the Android application at the top layer. You will write your application to be installed on this layer only. Examples of such applications are Contacts Books, Browser, Games etc. Application components are the essential building blocks of an Android application. These components are loosely coupled by the application manifest file AndroidManifest.xml that describes each component of the application and how they interact. There are following four main components that can be used within an Android application − Sr.No Components & Description 1 Activities They dictate the UI and handle the user interaction to the smart phone screen. 2 Services They handle background processing associated with an application. 3 Broadcast Receivers They handle communication between Android OS and applications. 4 Content Providers They handle data and database management issues. Activities An activity represents a single screen with a user interface,in-short Activity performs actions on the screen. For example, an email application might have one activity that shows a list of new emails, another activity to compose an email, and another activity for reading emails. If an application has more than one activity, then one of them should be marked as the activity that is presented when the application is launched. An activity is implemented as a subclass of Activity class as follows − public class MainActivity extends Activity { } Services A service is a component that runs in the background to perform long-running operations. For example, a service might play music in the background while the user is in a different application, or it might fetch data over the network without blocking user interaction with an activity. A service is implemented as a subclass of Service class as follows − public class MyService extends Service { } Broadcast Receivers Broadcast Receivers simply respond to broadcast messages from other applications or from the system. For example, applications can also initiate broadcasts to let other applications know that some data has been downloaded to the device and is available for them to use, so this is broadcast receiver who will intercept this communication and will initiate appropriate action. A broadcast receiver is implemented as a subclass of BroadcastReceiver class and each message is broadcaster as an Intent object. public class MyReceiver extends BroadcastReceiver { public void onReceive(context,intent){} } Content Providers A content provider component supplies data from one application to others on request. Such requests are handled by the methods of the ContentResolver class. The data may be stored in the file system, the database or somewhere else entirely. A content provider is implemented as a subclass of ContentProvider class and must implement a standard set of APIs that enable other applications to perform transactions. public class MyContentProvider extends ContentProvider { public void onCreate(){} } We will go through these tags in detail while covering application components in individual chapters. Additional Components There are additional components which will be used in the construction of above mentioned entities, their logic, and wiring between them. These components are − S.No Components & Description 1 Fragments Represents a portion of user interface in an Activity. 2 Views UI elements that are drawn on-screen including buttons, lists forms etc. 3 Layouts View hierarchies that control screen format and appearance of the views. 4 Intents Messages wiring components together. 5 Resources External elements, such as strings, constants and drawable pictures. 6 Manifest Configuration file for the application. Let us start actual programming with Android Framework. Before you start writing your first example using Android SDK, you have to make sure that you have set-up your Android development environment properly as explained in Android - Environment Set-up tutorial. I also assume that you have a little bit working knowledge with Android studio. So let us proceed to write a simple Android Application which will print "Hello World!". Create Android Application The first step is to create a simple Android Application using Android studio. When you click on Android studio icon, it will show screen as shown below You can start your application development by calling start a new android studio project. in a new installation frame should ask Application name, package information and location of the project.− After entered application name, it going to be called select the form factors your application runs on, here need to specify Minimum SDK, in our tutorial, I have declared as API23: Android 6.0(Mashmallow) − The next level of installation should contain selecting the activity to mobile, it specifies the default layout for Applications. At the final stage it going to be open development tool to write the application code. Anatomy of Android Application Before you run your app, you should be aware of a few directories and files in the Android project − Sr.No. Folder, File & Description 1 Java This contains the .java source files for your project. By default, it includes an MainActivity.java source file having an activity class that runs when your app is launched using the app icon. 2 res/drawable-hdpi This is a directory for drawable objects that are designed for high-density screens. 3 res/layout This is a directory for files that define your app's user interface. 4 res/values This is a directory for other various XML files that contain a collection of resources, such as strings and colours definitions. 5 AndroidManifest.xml This is the manifest file which describes the fundamental characteristics of the app and defines each of its components. 6 Build.gradle This is an auto generated file which contains compileSdkVersion, buildToolsVersion, applicationId, minSdkVersion, targetSdkVersion, versionCode and versionName Following section will give a brief overview of the important application files. The Main Activity File The main activity code is a Java file MainActivity.java. This is the actual application file which ultimately gets converted to a Dalvik executable and runs your application. Following is the default code generated by the application wizard for Hello World! application − package com.example.helloworld; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } } Here, R.layout.activity_main refers to the activity_main.xml file located in the res/layout folder. The onCreate() method is one of many methods that are figured when an activity is loaded. The Manifest File Whatever component you develop as a part of your application, you must declare all its components in a manifest.xml which resides at the root of the application project directory. This file works as an interface between Android OS and your application, so if you do not declare your component in this file, then it will not be considered by the OS. For example, a default manifest file will look like as following file − <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.tutorialspoint7.myapplication"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest> Here <application>...</application> tags enclosed the components related to the application. Attribute android:icon will point to the application icon available under res/drawable-hdpi. The application uses the image named ic_launcher.png located in the drawable folders The <activity> tag is used to specify an activity and android:name attribute specifies the fully qualified class name of the Activity subclass and the android:label attributes specifies a string to use as the label for the activity. You can specify multiple activities using <activity> tags. The action for the intent filter is named android.intent.action.MAIN to indicate that this activity serves as the entry point for the application. The category for the intent-filter is named android.intent.category.LAUNCHER to indicate that the application can be launched from the device's launcher icon. The @string refers to the strings.xml file explained below. Hence, @string/app_name refers to the app_name string defined in the strings.xml file, which is "HelloWorld". Similar way, other strings get populated in the application. Following is the list of tags which you will use in your manifest file to specify different Android application components − <activity>elements for activities <service> elements for services <receiver> elements for broadcast receivers <provider> elements for content providers The Strings File The strings.xml file is located in the res/values folder and it contains all the text that your application uses. For example, the names of buttons, labels, default text, and similar types of strings go into this file. This file is responsible for their textual content. For example, a default strings file will look like as following file − <resources> <string name="app_name">HelloWorld</string> <string name="hello_world">Hello world!</string> <string name="menu_settings">Settings</string> <string name="title_activity_main">MainActivity</string> </resources> The Layout File The activity_main.xml is a layout file available in res/layout directory, that is referenced by your application when building its interface. You will modify this file very frequently to change the layout of your application. For your "Hello World!" application, this file will have following content related to default layout − <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:padding="@dimen/padding_medium" android:text="@string/hello_world" tools:context=".MainActivity" /> </RelativeLayout> This is an example of simple RelativeLayout which we will study in a separate chapter. The TextView is an Android control used to build the GUI and it have various attributes like android:layout_width, android:layout_height etc which are being used to set its width and height etc.. The @string refers to the strings.xml file located in the res/values folder. Hence, @string/hello_world refers to the hello string defined in the strings.xml file, which is "Hello World!". Running the Application Let's try to run our Hello World! application we just created. I assume you had created your AVD while doing environment set-up. To run the app from Android studio, open one of your project's activity files and click Run icon from the tool bar. Android studio installs the app on your AVD and starts it and if everything is fine with your set-up and application, it will display following Emulator window − Congratulations!!! you have developed your first Android Application and now just keep following rest of the tutorial step by step to become a great Android Developer. All the very best. (未完,待续) 读取更多关于Android Tutorial 1 »
• 解决独立显卡obs捕获显示器后黑屏界面问题
现象:新购2台win10操作系统的华为笔记本电脑上安装的obs直播软件,捕获显示器后是黑屏界面,即推流视频有声音,无图像;捕捉摄像头和窗口正常。 原因:这两台笔记本电脑都有俩显卡(集显和独显),系统默认先看时集成显卡,而obs默认用独立显卡。 解决方案:如下图 读取更多关于解决独立显卡obs捕获显示器后黑屏界面问题 »
• CentOS 8.0在大于2TB的硬盘上安装时需要采用GPT模式
现象:CentOS 8 在 曙光服务器上安装时无法识别硬盘,硬盘容量6TB,大于2TB 原因:安装CentOS 8时,如果硬盘容量小于2TB,系统默认会使用MBR模式来安装,若大于2TB时,需强制使用GPT分割 解决方案:出现安装Centos8引导画面之后,按“TAB”键,将命令行最后追加"inst.gpt"这个参数:>vmlinuz initrd=initrd.img inst.gpt 读取更多关于CentOS 8.0在大于2TB的硬盘上安装时需要采用GPT模式 »