首页 文章 精选 留言 我的

精选列表

搜索[文档解析],共10000篇文章
优秀的个人博客,低调大师

VMware vSphere 5.1 群集深入解析(一)

版权 Copyright?2012byDuncanEppingandFrankDenneman. 关于作者 DuncanEpping是VMware技术市场部首席架构师,Dun是vSphereHA和VMwarevCloud云套件的架构设计师,是VMware公司首批认证的设计专家(VCDX007)……(这里就不多译) Tim2009认为这是VMware虚拟化方面的一本专业好书,故使用google、有道、大学英语结合虚拟化项目实践翻译成中文,希望有用。 知识点 这本书是关于VMware产品的,仅代表个人观点,文章中的内容没有经过VMware公司的核准,也没有必要体现VMware的观点,这是作者的书,不是VMware的书 首先我们非常感谢VMware管理团队(KaushikBanerjee,JimSenicka,BogomilBalkanskyandRaghuRaghuram)对此书及相关项目的支持。 前言 数据中心通常都需要经过仔细的配置,设计,监控和其它操作任务,从而实现高效的运行应用程序。但是,这些活动的应用根本上是保证灯常亮,没有大量附加价值,未使IT服务成业务的核心目标,很多任务手工完成设置。假如应用程序的拥有者定义了高水准的商业需求,IT部门会转换为系统的层面,用底层的基础设施解释这些策略需求,并自动配置,管理和操作底层的系统去匹配策略目标,这就是VMware的目标,新技术的解决方案建立新一代数据中心。 数据中心被独立分开成二层-我们可以考虑的是做什么和怎么做,上层的区域运行他们的工作同时匹配策略目标-这就解释了做什么,VMware的目标是让事情尽可能的自动化,应用的拥有者不用精确的了解到虚拟机在哪台物理主机上运行,或者虚拟机应用了哪些有效的规则,应用的拥有者希望适当的设计和配置替代指定需求和期望,那样就可以提供服务来满足这些需求 下层的关于“怎么做”,这些核心的策略如群集高可用性,动态资源分配定义到这层,并被程序控制管理。有了群集我们不再需要单台服务器为工作单位,这就是这本书的主题和为什么这对vSphere部署成功如此重要,VMwarevSphere需要配置合适的群集级别去管理资源,也是为了达到更高服务水平所必须的,群集控制大量的服务器形成池从而协调资源分配,这些工作需求可能包括可用性,存储I/O需求和其它与应用拥有者相关的规格 因此,新时代的数据中心不仅仅是因为虚拟化,它整合了许多传统基础因素如计算,存储,网络等组件,让它们得以系统的管理,这个意思是说以前需要手工的配置,更改,发布,现在都被系统的管理起来,某些项目和虚拟化软件架构一样被具体化,现代化的软件为这些提供了灵活性和高效性,当工作需求改变,底层架构也随之能够适应和扩展来满足需求。 在很长一段时间里,我们期望越来越多的传统基础架构能够得到系统的管理,高水平的架构就像一块补丁,以应用程序为中心已经成为标准服务的一部分,扩展最好是在系统的层面。 网络也变得越来越有代表性,打个比方,安全规则将被分配给应用,而形成对比的是特有的设备被看成网络端口组,类似的创新也发生在存储领域,我们考虑虚拟机作为数据存储的单元,我们计划从物理存储器上迁移相关联的数据,如LUNs或者文件服务器上。 云计算的目标是所有类似的基础设备继续被动态的方式管理,细致的底层设计需要专业的知识,提供这样一本值得读的书,可以帮助IT管理员更集中精力去配置应用来满足商业需求,而不仅仅是维护IT基础设施保证机器灯亮。 我们希望你能在这本书中发现有作用和有意义的地方 RaghuRaghuram ExecutiveVicePresident,CloudInfrastructureandManagement VMware 第一部分vSphere高可用性 第一章介绍vSphere高可用性 当提供服务时,可用性是传统数据中心需要考虑的重要的方面之一,当在VMwarevSphere共享平台上提供服务时,为了面对停机时间的成倍增长,VMware设计了一个VMwarevSphereHA(高可用性)的功能,VMwarevSphereHA(高可用性)以下简称HA,它提供了一个简单且性价比高的解决方案,从而提高虚拟机上应用的高可用性且无关虚拟机的操作系统。vCenterServer的简单几步即可完成HA配置,同时提供统一的和简便的接口,在ESXi或者ESX服务器建立群集时,你可以开启HA功能,我们将在这本书中用ESXi服务器作为参照,也就是说以ESXi服务器为标准.功能的启用可以保护你们的虚拟机,当群集中一台主机出现故障,受影响的虚拟机会自动在同一个群集中其它的ESXi主机上重新启动。 图1:HA的活动流程 另外,当虚拟机的操作系统发生故障时,HA能够重新启动虚拟机上的操作系统,这个功能被称之为虚拟机监测,但有时候也称之为VM的HA,这听起来相当的复杂但也可以通过鼠标点击实现。 图2:点击HA的监测级别 @莫斯和本人分别做了一个实验,首先开启虚拟机监控为<虚拟机和应用程序监控>,然后在虚拟机选项中选择相应的虚拟机匹配不同的<主机隔离响应>,测试是否生效。 实验结果如下表 可以看出,虚拟机的原始状态跟主机隔离响应的策略无关,我俩还是蛮有疑惑的。 不像其它的群集解决方案,HA是一个相当简单的解决方案,只需要依次点击5次鼠标,另外,HA被广泛应用在所有的环境中,但是,HA和微软的MSCS(群集服务)不一样,它不是一个1:1的备份解决方案,MSCS和HA的主要不同点是,MSCS是设计成保护群集应用的状态,而HA被设计成保护虚拟机,无论虚拟机上是什么类型的应用,但也可以通过虚拟机和应用程序的监控扩展到应用层。 在有HA的情况下,故障转移发生的停机时间就是虚拟机在群集中另一节点上虚拟机重新启动的时间,而MSCS故障转移发生的停机时间为服务切换到群集中另一节点的时间,与很多人认为的观点形成对比的是,MSCS不保证在群集故障转移时是零停机时间,另外,为了更有效的利用这一机制,你们的应用需要开启群集状态监测。 可能有这样一个问题,当虚拟机重新启动,应用服务临时真空的情况下,为什么要用到HA,这个问题很简单,不是所有的虚拟机或者应用服务需要99.999%时间开机提供服务,HA能够满足足够多服务的需求,另外,许多应用不支持MSCS群集故障转移功能,这意味着如果群集中的应用没有被MSCS检测到时,不能保证应用的高可用性和数据一致性。 另外,MSCS群集配置比较复杂,需要专业的技术和背景,打个比方,补丁管理服务器和更新服务器在一个MSCS环境中,如果配置不正确会导致更多的故障停机时间及更复杂的程序配置方式。但HA可以减少复杂度,开销时间,资源消耗和停机时间,这些可以体现HA的重要性,相反的是MSCS,不需要任何改变的guest,HA仍可以在虚拟化层提供服务,而且,虚拟机监测除了安装VMwareTools不需要其它的附加软件或者系统模块,无论如何,安装VMwareTools是一个非常好的方法。如果需要更高基本的高可用性,VMware还可以通过应用程序监控提供,和赛门铁克一样被利用来弹性定义应用级别,还可以在内部团队进行开发时,增加应用的弹性。 HA已经一次又一次的证明自己,它已经广泛的应用于各个领域,如果你到今天为止还没有使用它,看完这部书希望你能相信。 vSphere5.1 当我们深入HA的主体架构中,并描述怎样配置使用HA时,我们首先简单的介绍下vSphere5.0和5.1的变化,描述启用HA的基本要求和步骤,聚焦这边书,可以增强虚拟架构中的稳定性,我们还认识到,你们有可能还不熟悉vSphere5.0,我们同样会强调vSphere5.0的变化,我们在适当的情况下,仍然会讨论功能和概念,包括自从vCenter2.0之后出现组件,以确保您在各个方面更全面的理解HA。 5.X的变化 在vSphere5.0之前,HA的功能没有得到大的增强,也许你在vSphere5.0和vSphere5.1之间看不到变化,但他们有些地方还是很突出。 在vSphere5.0的HA完全从底层被重新设计和开发,这也是HA从之前故障转移需要分钟为单位代替为秒为单位的原因 vSphere5.0中重新设计的HA,许多非常受欢迎的改变可以拿来介绍HA的扩展性,一些HA的关键组件完全被更改,同时添加了新的功能,为了便利,我们把改变列了下面的清单,那样我们可以更详细的讨论这个章节,vSphere5.0的所有改变如下表所示: 新的HA的代理——FDM是新的HA代理,HA已经从最底层重新设计,也就是说FDM替换了AAM代理 不依赖DNS——为了避免依赖DNS,HA只需要写入IP即可。 主节点的概念——主/备节点的数量限制被取消(vSphere4.1版本以前最多支持5个主节点) 支持管理网络分区——当存在多个网络分区时,允许有多个主节点 增强隔离验证——当管理网络出现故障时,避免误报 数据存储心跳检测——在通过存储层验证主机状态时,这种额外的信号检测可以减少误报的机会, 增强管理控制规则 1台主机故障允许4台主机接管(最大支持31台) 以百分比为控制粒度,可以允许你单独规定CPU或者内存的使用率 基于接入控制策略,可以允许多个主机成为故障主机的目标重启主机 vSphere5.1则增加了一些功能,虽然与vSphere5.0相比,这些似乎是次要的,他们是非常重要的了解,以便创建一个高度灵活的环境。 通过vSphereWebClient设置主机故障接纳值 能够检索跨越多个插槽的虚拟机的列表 增强了设备永久丢失的处理情况(vSphere5.0.1有介绍) 支持虚拟机系统的休眠模式 GuestSDK中包括应用监测SDK vSphereHA(FDM)VIB自动被添加到自动部署步骤中 通过”das.config.fdm.iso-lationPolicyDelaySec”设置延迟响应 HA工作需要哪些条件 每个产品功能都需要相关的前提条件支持,HA也不例外,了解HA的前提条件也是学习的基础部分,我们必须抛开之前我们提到的复杂的概念,来迎接全新的HA,我还要像您展示怎样配置HA。 先决条件 在配置HA前,强烈要求在环境中验证它的先决条件,为增加弹性,我们还建议在基础环境中也验证先决条件。 需求: 最少2台ESXi主机 安装ESXi的主机至少3GB内存 VMwarevCenterServer 虚拟机能访问的共享存储 可靠的网关或者其它IP地址 建议: 管理网络冗余(不是必须的,但强烈建议) 多路径共享存储 防火墙需求 在下表中是HA需要用于通信的端口,如果主机的内网环境运行着防火墙设备,为保证HA功能正常这些端口必须打开,在ESX或者ESXi防火墙上也同样需要打开以下端口,需要注意的地方是vSphere5.0之前需要多个端口来进行HA通信,而vSphere只需要用到一个端口。 表一:高可用端口设置 配置vSphere的高可用性 HA只需要点击几次即可完成配置,接下来的步骤将会展示怎样建立群集和开启HA,包括虚拟机监控,使用vSphereWebClient,这些设置和设计在接下来的章节内容中详细描述。 1.登录连接vCenterServer 2.数据中心右键建立新的群集 3.给新的群集命名,建议名称中至少包含位置信息,然后按序号排列,如ie.ams-hadrs-001 4.选择开启HA 5.启用主机监控和策略 6.在接入控制策略下选择作为故障切换空间容量保留的群集资源的百分比 7.开启”虚拟机和应用程序监控“ 8.点击“OK”完成配置 图3:群集即将完成配置信息 当HA群集建立完成,右键点击ESXi主机可以迁移它到群集中,如果加入了vCenter,在群集上右键添加ESXi主机即可 当一台ESXi主机首次添加到新建的群集中,HA的代理会被加载和配置,一旦代理配置完成,HA将会为运行中的ESXi主机提供保护。 正如我们所阐述的,HA是一个简单的群集解决方案,它可以在主机或者操作系统出现故障的几分钟内保证虚拟机继续工作,了解了HA的架构,当涉及到可用性时,我们能更容易解决问题,在接下来的章节,我们将讨论HA的架构和基本概念,我们还将讨论在客户的环境中我们如何根据需求来决策配置HA的方式。 本文转自 tim2009 51CTO博客,原文链接:http://blog.51cto.com/virtualbox/1168293,如需转载请自行联系原作者

优秀的个人博客,低调大师

Android RecyclerView (一) 使用完全解析

转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/45059587; 本文出自:【张鸿洋的博客】 概述 RecyclerView出现已经有一段时间了,相信大家肯定不陌生了,大家可以通过导入support-v7对其进行使用。 据官方的介绍,该控件用于在有限的窗口中展示大量数据集,其实这样功能的控件我们并不陌生,例如:ListView、GridView。 那么有了ListView、GridView为什么还需要RecyclerView这样的控件呢?整体上看RecyclerView架构,提供了一种插拔式的体验,高度的解耦,异常的灵活,通过设置它提供的不同LayoutManager,ItemDecoration , ItemAnimator实现令人瞠目的效果。 你想要控制其显示的方式,请通过布局管理器LayoutManager 你想要控制Item间的间隔(可绘制),请通过ItemDecoration 你想要控制Item增删的动画,请通过ItemAnimator 你想要控制点击、长按事件,请自己写(擦,这点尼玛。) 基本使用 鉴于我们对于ListView的使用特别的熟悉,对比下RecyclerView的使用代码: mRecyclerView = findView(R.id.id_recyclerview); //设置布局管理器 mRecyclerView.setLayoutManager(layout); //设置adapter mRecyclerView.setAdapter(adapter) //设置Item增加、移除动画 mRecyclerView.setItemAnimator(new DefaultItemAnimator()); //添加分割线 mRecyclerView.addItemDecoration(new DividerItemDecoration( getActivity(), DividerItemDecoration.HORIZONTAL_LIST)); ok,相比较于ListView的代码,ListView可能只需要去设置一个adapter就能正常使用了。而RecyclerView基本需要上面一系列的步骤,那么为什么会添加这么多的步骤呢? 那么就必须解释下RecyclerView的这个名字了,从它类名上看,RecyclerView代表的意义是,我只管Recycler View,也就是说RecyclerView只管回收与复用View,其他的你可以自己去设置。可以看出其高度的解耦,给予你充分的定制自由(所以你才可以轻松的通过这个控件实现ListView,GirdView,瀑布流等效果)。 Just like ListView Activity package com.zhy.sample.demo_recyclerview; import java.util.ArrayList; import java.util.List; import android.os.Bundle; import android.support.v7.app.ActionBarActivity; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView.ViewHolder; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; public class HomeActivity extends ActionBarActivity { private RecyclerView mRecyclerView; private List<String> mDatas; private HomeAdapter mAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_single_recyclerview); initData(); mRecyclerView = (RecyclerView) findViewById(R.id.id_recyclerview); mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); mRecyclerView.setAdapter(mAdapter = new HomeAdapter()); } protected void initData() { mDatas = new ArrayList<String>(); for (int i = 'A'; i < 'z'; i++) { mDatas.add("" + (char) i); } } class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.MyViewHolder> { @Override public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { MyViewHolder holder = new MyViewHolder(LayoutInflater.from( HomeActivity.this).inflate(R.layout.item_home, parent, false)); return holder; } @Override public void onBindViewHolder(MyViewHolder holder, int position) { holder.tv.setText(mDatas.get(position)); } @Override public int getItemCount() { return mDatas.size(); } class MyViewHolder extends ViewHolder { TextView tv; public MyViewHolder(View view) { super(view); tv = (TextView) view.findViewById(R.id.id_num); } } } Activity的布局文件 <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" > <android.support.v7.widget.RecyclerView android:id="@+id/id_recyclerview" android:divider="#ffff0000" android:dividerHeight="10dp" android:layout_width="match_parent" android:layout_height="match_parent" /> </RelativeLayout> Item的布局文件 <?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:background="#44ff0000" android:layout_height="wrap_content" > <TextView android:id="@+id/id_num" android:layout_width="match_parent" android:layout_height="50dp" android:gravity="center" android:text="1" /> </FrameLayout> 这么看起来用法与ListView的代码基本一致哈~~ 看下效果图: 看起来好丑,Item间应该有个分割线,当你去找时,你会发现RecyclerView并没有支持divider这样的属性。那么怎么办,你可以给Item的布局去设置margin,当然了这种方式不够优雅,我们文章开始说了,我们可以自由的去定制它,当然我们的分割线也是可以定制的。 ItemDecoration 我们可以通过该方法添加分割线:mRecyclerView.addItemDecoration() 该方法的参数为RecyclerView.ItemDecoration,该类为抽象类,官方目前并没有提供默认的实现类(我觉得最好能提供几个)。 该类的源码: public static abstract class ItemDecoration { public void onDraw(Canvas c, RecyclerView parent, State state) { onDraw(c, parent); } public void onDrawOver(Canvas c, RecyclerView parent, State state) { onDrawOver(c, parent); } public void getItemOffsets(Rect outRect, View view, RecyclerView parent, State state) { getItemOffsets(outRect, ((LayoutParams) view.getLayoutParams()).getViewLayoutPosition(), parent); } @Deprecated public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) { outRect.set(0, 0, 0, 0); } 当我们调用mRecyclerView.addItemDecoration()方法添加decoration的时候,RecyclerView在绘制的时候,去会绘制decorator,即调用该类的onDraw和onDrawOver方法, onDraw方法先于drawChildren onDrawOver在drawChildren之后,一般我们选择复写其中一个即可。 getItemOffsets 可以通过outRect.set()为每个Item设置一定的偏移量,主要用于绘制Decorator。 接下来我们看一个RecyclerView.ItemDecoration的实现类,该类很好的实现了RecyclerView添加分割线(当使用LayoutManager为LinearLayoutManager时)。 该类参考自:DividerItemDecoration package com.zhy.sample.demo_recyclerview; /* * Copyright (C) 2014 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * limitations under the License. */ import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.support.v7.widget.LinearLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView.State; import android.util.Log; import android.view.View; /** * This class is from the v7 samples of the Android SDK. It's not by me! * <p/> * See the license above for details. */ public class DividerItemDecoration extends RecyclerView.ItemDecoration { private static final int[] ATTRS = new int[]{ android.R.attr.listDivider }; public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL; public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL; private Drawable mDivider; private int mOrientation; public DividerItemDecoration(Context context, int orientation) { final TypedArray a = context.obtainStyledAttributes(ATTRS); mDivider = a.getDrawable(0); a.recycle(); setOrientation(orientation); } public void setOrientation(int orientation) { if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) { throw new IllegalArgumentException("invalid orientation"); } mOrientation = orientation; } @Override public void onDraw(Canvas c, RecyclerView parent) { Log.v("recyclerview - itemdecoration", "onDraw()"); if (mOrientation == VERTICAL_LIST) { drawVertical(c, parent); } else { drawHorizontal(c, parent); } } public void drawVertical(Canvas c, RecyclerView parent) { final int left = parent.getPaddingLeft(); final int right = parent.getWidth() - parent.getPaddingRight(); final int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { final View child = parent.getChildAt(i); android.support.v7.widget.RecyclerView v = new android.support.v7.widget.RecyclerView(parent.getContext()); final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child .getLayoutParams(); final int top = child.getBottom() + params.bottomMargin; final int bottom = top + mDivider.getIntrinsicHeight(); mDivider.setBounds(left, top, right, bottom); mDivider.draw(c); } } public void drawHorizontal(Canvas c, RecyclerView parent) { final int top = parent.getPaddingTop(); final int bottom = parent.getHeight() - parent.getPaddingBottom(); final int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { final View child = parent.getChildAt(i); final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child .getLayoutParams(); final int left = child.getRight() + params.rightMargin; final int right = left + mDivider.getIntrinsicHeight(); mDivider.setBounds(left, top, right, bottom); mDivider.draw(c); } } @Override public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) { if (mOrientation == VERTICAL_LIST) { outRect.set(0, 0, 0, mDivider.getIntrinsicHeight()); } else { outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0); } } } 该实现类可以看到通过读取系统主题中的android.R.attr.listDivider作为Item间的分割线,并且支持横向和纵向。如果你不清楚它是怎么做到的读取系统的属性用于自身,请参考我的另一篇博文:Android 深入理解Android中的自定义属性 获取到listDivider以后,该属性的值是个Drawable,在getItemOffsets中,outRect去设置了绘制的范围。onDraw中实现了真正的绘制。 我们在原来的代码中添加一句: mRecyclerView.addItemDecoration(new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST)); ok,现在再运行,就可以看到分割线的效果了。 该分割线是系统默认的,你可以在theme.xml中找到该属性的使用情况。那么,使用系统的listDivider有什么好处呢?就是方便我们去随意的改变,该属性我们可以直接声明在: <!-- Application theme. --> <style name="AppTheme" parent="AppBaseTheme"> <item name="android:listDivider">@drawable/divider_bg</item> </style> 然后自己写个drawable即可,下面我们换一种分隔符: <?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" > <gradient android:centerColor="#ff00ff00" android:endColor="#ff0000ff" android:startColor="#ffff0000" android:type="linear" /> <size android:height="4dp"/> </shape> 现在的样子是: 当然了,你可以根据自己的需求,去随意的绘制,反正是画出来的,随便玩~~ ok,看到这,你可能觉得,这玩意真尼玛麻烦,完全不能比拟的心爱的ListView。那么继续看。 LayoutManager 好了,上面实现了类似ListView样子的Demo,通过使用其默认的LinearLayoutManager。 RecyclerView.LayoutManager吧,这是一个抽象类,好在系统提供了3个实现类: LinearLayoutManager 现行管理器,支持横向、纵向。 GridLayoutManager 网格布局管理器 StaggeredGridLayoutManager 瀑布就式布局管理器 上面我们已经初步体验了下LinearLayoutManager,接下来看GridLayoutManager。 GridLayoutManager 我们尝试去实现类似GridView,秒秒钟的事情: //mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); mRecyclerView.setLayoutManager(new GridLayoutManager(this,4)); 只需要修改LayoutManager即可,还是很nice的。 当然了,改为GridLayoutManager以后,对于分割线,前面的DividerItemDecoration就不适用了,主要是因为它在绘制的时候,比如水平线,针对每个child的取值为: final int left = parent.getPaddingLeft(); final int right = parent.getWidth() - parent.getPaddingRight(); 因为每个Item一行,这样是没问题的。而GridLayoutManager时,一行有多个childItem,这样就多次绘制了,并且GridLayoutManager时,Item如果为最后一列(则右边无间隔线)或者为最后一行(底部无分割线)。 针对上述,我们编写了DividerGridItemDecoration。 package com.zhy.sample.demo_recyclerview; import android.content.Context; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.support.v7.widget.GridLayoutManager; import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView.LayoutManager; import android.support.v7.widget.RecyclerView.State; import android.support.v7.widget.StaggeredGridLayoutManager; import android.view.View; /** * * @author zhy * */ public class DividerGridItemDecoration extends RecyclerView.ItemDecoration { private static final int[] ATTRS = new int[] { android.R.attr.listDivider }; private Drawable mDivider; public DividerGridItemDecoration(Context context) { final TypedArray a = context.obtainStyledAttributes(ATTRS); mDivider = a.getDrawable(0); a.recycle(); } @Override public void onDraw(Canvas c, RecyclerView parent, State state) { drawHorizontal(c, parent); drawVertical(c, parent); } private int getSpanCount(RecyclerView parent) { // 列数 int spanCount = -1; LayoutManager layoutManager = parent.getLayoutManager(); if (layoutManager instanceof GridLayoutManager) { spanCount = ((GridLayoutManager) layoutManager).getSpanCount(); } else if (layoutManager instanceof StaggeredGridLayoutManager) { spanCount = ((StaggeredGridLayoutManager) layoutManager) .getSpanCount(); } return spanCount; } public void drawHorizontal(Canvas c, RecyclerView parent) { int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { final View child = parent.getChildAt(i); final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child .getLayoutParams(); final int left = child.getLeft() - params.leftMargin; final int right = child.getRight() + params.rightMargin + mDivider.getIntrinsicWidth(); final int top = child.getBottom() + params.bottomMargin; final int bottom = top + mDivider.getIntrinsicHeight(); mDivider.setBounds(left, top, right, bottom); mDivider.draw(c); } } public void drawVertical(Canvas c, RecyclerView parent) { final int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { final View child = parent.getChildAt(i); final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child .getLayoutParams(); final int top = child.getTop() - params.topMargin; final int bottom = child.getBottom() + params.bottomMargin; final int left = child.getRight() + params.rightMargin; final int right = left + mDivider.getIntrinsicWidth(); mDivider.setBounds(left, top, right, bottom); mDivider.draw(c); } } private boolean isLastColum(RecyclerView parent, int pos, int spanCount, int childCount) { LayoutManager layoutManager = parent.getLayoutManager(); if (layoutManager instanceof GridLayoutManager) { if ((pos + 1) % spanCount == 0)// 如果是最后一列,则不需要绘制右边 { return true; } } else if (layoutManager instanceof StaggeredGridLayoutManager) { int orientation = ((StaggeredGridLayoutManager) layoutManager) .getOrientation(); if (orientation == StaggeredGridLayoutManager.VERTICAL) { if ((pos + 1) % spanCount == 0)// 如果是最后一列,则不需要绘制右边 { return true; } } else { childCount = childCount - childCount % spanCount; if (pos >= childCount)// 如果是最后一列,则不需要绘制右边 return true; } } return false; } private boolean isLastRaw(RecyclerView parent, int pos, int spanCount, int childCount) { LayoutManager layoutManager = parent.getLayoutManager(); if (layoutManager instanceof GridLayoutManager) { childCount = childCount - childCount % spanCount; if (pos >= childCount)// 如果是最后一行,则不需要绘制底部 return true; } else if (layoutManager instanceof StaggeredGridLayoutManager) { int orientation = ((StaggeredGridLayoutManager) layoutManager) .getOrientation(); // StaggeredGridLayoutManager 且纵向滚动 if (orientation == StaggeredGridLayoutManager.VERTICAL) { childCount = childCount - childCount % spanCount; // 如果是最后一行,则不需要绘制底部 if (pos >= childCount) return true; } else // StaggeredGridLayoutManager 且横向滚动 { // 如果是最后一行,则不需要绘制底部 if ((pos + 1) % spanCount == 0) { return true; } } } return false; } @Override public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) { int spanCount = getSpanCount(parent); int childCount = parent.getAdapter().getItemCount(); if (isLastRaw(parent, itemPosition, spanCount, childCount))// 如果是最后一行,则不需要绘制底部 { outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0); } else if (isLastColum(parent, itemPosition, spanCount, childCount))// 如果是最后一列,则不需要绘制右边 { outRect.set(0, 0, 0, mDivider.getIntrinsicHeight()); } else { outRect.set(0, 0, mDivider.getIntrinsicWidth(), mDivider.getIntrinsicHeight()); } } 主要在getItemOffsets方法中,去判断如果是最后一行,则不需要绘制底部;如果是最后一列,则不需要绘制右边,整个判断也考虑到了StaggeredGridLayoutManager的横向和纵向,所以稍稍有些复杂。最重要还是去理解,如何绘制什么的不重要。一般如果仅仅是希望有空隙,还是去设置item的margin方便。 最后的效果是: ok,看到这,你可能还觉得RecyclerView不够强大? 但是如果我们有这么个需求,纵屏的时候显示为ListView,横屏的时候显示两列的GridView,我们RecyclerView可以轻松搞定,而如果使用ListView去实现还是需要点功夫的~~~ 当然了,这只是皮毛,下面让你心服口服。 StaggeredGridLayoutManager 瀑布流式的布局,其实他可以实现GridLayoutManager一样的功能,仅仅按照下列代码: // mRecyclerView.setLayoutManager(new GridLayoutManager(this,4)); mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(4, StaggeredGridLayoutManager.VERTICAL)); 这两种写法显示的效果是一致的,但是注意StaggeredGridLayoutManager构造的第二个参数传一个orientation,如果传入的是StaggeredGridLayoutManager.VERTICAL代表有多少列;那么传入的如果是StaggeredGridLayoutManager.HORIZONTAL就代表有多少行,比如本例如果改为: mRecyclerView.setLayoutManager(new StaggeredGridLayoutManager(4, StaggeredGridLayoutManager.HORIZONTAL)); 那么效果为: 可以看到,固定为4行,变成了左右滑动。有一点需要注意,如果是横向的时候,item的宽度需要注意去设置,毕竟横向的宽度没有约束了,应为控件可以横向滚动了。 如果你需要一样横向滚动的GridView,那么恭喜你。 ok,接下来准备看大招,如果让你去实现个瀑布流,最起码不是那么随意就可以实现的吧?但是,如果使用RecyclerView,分分钟的事。 那么如何实现?其实你什么都不用做,只要使用StaggeredGridLayoutManager我们就已经实现了,只是上面的item布局我们使用了固定的高度,下面我们仅仅在适配器的onBindViewHolder方法中为我们的item设置个随机的高度(代码就不贴了,最后会给出源码下载地址),看看效果图: 是不是棒棒哒,通过RecyclerView去实现ListView、GridView、瀑布流的效果基本上没有什么区别,而且可以仅仅通过设置不同的LayoutManager即可实现。 还有更nice的地方,就在于item增加、删除的动画也是可配置的。接下来看一下ItemAnimator。 ItemAnimator ItemAnimator也是一个抽象类,好在系统为我们提供了一种默认的实现类,期待系统多 添加些默认的实现。 借助默认的实现,当Item添加和移除的时候,添加动画效果很简单: // 设置item动画 mRecyclerView.setItemAnimator(new DefaultItemAnimator()); 系统为我们提供了一个默认的实现,我们为我们的瀑布流添加以上一行代码,效果为: 如果是GridLayoutManager呢?动画效果为: 注意,这里更新数据集不是用adapter.notifyDataSetChanged()而是notifyItemInserted(position)与notifyItemRemoved(position) 否则没有动画效果。 上述为adapter中添加了两个方法: public void addData(int position) { mDatas.add(position, "Insert One"); notifyItemInserted(position); } public void removeData(int position) { mDatas.remove(position); notifyItemRemoved(position); } Activity中点击MenuItem触发: @Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main, menu); return super.onCreateOptionsMenu(menu); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case R.id.id_action_add: mAdapter.addData(1); break; case R.id.id_action_delete: mAdapter.removeData(1); break; } return true; } 好了,到这我对这个控件已经不是一般的喜欢了~~~ 当然了只提供了一种动画,那么我们肯定可以去自定义各种nice的动画效果。 高兴的是,github上已经有很多类似的项目了,这里我们直接引用下:RecyclerViewItemAnimators,大家自己下载查看。 提供了SlideInOutLeftItemAnimator,SlideInOutRightItemAnimator,SlideInOutTopItemAnimator,SlideInOutBottomItemAnimator等动画效果。 Click and LongClick 不过一个挺郁闷的地方就是,系统没有提供ClickListener和LongClickListener。 不过我们也可以自己去添加,只是会多了些代码而已。 实现的方式比较多,你可以通过mRecyclerView.addOnItemTouchListener去监听然后去判断手势, 当然你也可以通过adapter中自己去提供回调,这里我们选择后者,前者的方式,大家有兴趣自己去实现。 那么代码也比较简单: class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.MyViewHolder> { //... public interface OnItemClickLitener { void onItemClick(View view, int position); void onItemLongClick(View view , int position); } private OnItemClickLitener mOnItemClickLitener; public void setOnItemClickLitener(OnItemClickLitener mOnItemClickLitener) { this.mOnItemClickLitener = mOnItemClickLitener; } @Override public void onBindViewHolder(final MyViewHolder holder, final int position) { holder.tv.setText(mDatas.get(position)); // 如果设置了回调,则设置点击事件 if (mOnItemClickLitener != null) { holder.itemView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { int pos = holder.getLayoutPosition(); mOnItemClickLitener.onItemClick(holder.itemView, pos); } }); holder.itemView.setOnLongClickListener(new OnLongClickListener() { @Override public boolean onLongClick(View v) { int pos = holder.getLayoutPosition(); mOnItemClickLitener.onItemLongClick(holder.itemView, pos); return false; } }); } } //... } adapter中自己定义了个接口,然后在onBindViewHolder中去为holder.itemView去设置相应 的监听最后回调我们设置的监听。 最后别忘了给item添加一个drawable: <?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android" > <item android:state_pressed="true" android:drawable="@color/color_item_press"></item> <item android:drawable="@color/color_item_normal"></item> </selector> Activity中去设置监听: mAdapter.setOnItemClickLitener(new OnItemClickLitener() { @Override public void onItemClick(View view, int position) { Toast.makeText(HomeActivity.this, position + " click", Toast.LENGTH_SHORT).show(); } @Override public void onItemLongClick(View view, int position) { Toast.makeText(HomeActivity.this, position + " long click", Toast.LENGTH_SHORT).show(); mAdapter.removeData(position); } }); 测试效果: ok,到此我们基本介绍了RecylerView常见用法,包含了: 系统提供了几种LayoutManager的使用; 如何通过自定义ItemDecoration去设置分割线,或者一些你想作为分隔的drawable,注意这里 巧妙的使用了系统的listDivider属性,你可以尝试添加使用divider和dividerHeight属性。 如何使用ItemAnimator为RecylerView去添加Item移除、添加的动画效果。 介绍了如何添加ItemClickListener与ItemLongClickListener。 可以看到RecyclerView可以实现: ListView的功能 GridView的功能 横向ListView的功能,参考Android 自定义RecyclerView 实现真正的Gallery效果 横向ScrollView的功能 瀑布流效果 便于添加Item增加和移除动画 整个体验下来,感觉这种插拔式的设计太棒了,如果系统再能提供一些常用的分隔符,多添加些动画效果就更好了。 通过简单改变下LayoutManager,就可以产生不同的效果,那么我们可以根据手机屏幕的宽度去动态设置LayoutManager,屏幕宽度一般的,显示为ListView;宽度稍大的显示两列的GridView或者瀑布流(或者横纵屏幕切换时变化,有点意思~);显示的列数和宽度成正比。甚至某些特殊屏幕,让其横向滑动~~再选择一个nice的动画效果,相信这种插件式的编码体验一定会让你迅速爱上RecyclerView。 参考资料 Android 自定义RecyclerView 实现真正的Gallery效果 本文转自 一点点征服 博客园博客,原文链接:http://www.cnblogs.com/ldq2016/p/5377225.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

Android内部存储与外部存储解析

Android开发的过程中。经常会涉及到存储,之前一直没有一个整体的概念,这篇文章就是进行一个知识点的梳理。 Android的存储有:内部存储、外部存储。 想要了解这两个概念,我们先将开发软件中的DDMS打开,看File Explorer,如下: 1、内部存储 上边的data文件夹,就是内部存储。data文件夹中有两个重要的文件夹app、data。 app文件夹存放着我们所有已安装的软件的apk文件。 data文件夹存放以包名命名的文件夹。每个文件夹里是: /data/data/包名/shared_prefs /data/data/包名/databases /data/data/包名/files /data/data/包名/cache 这四个文件夹,其中SharePreferenced的数据就是存在shared_prefs中。软件中的数据库文件就是存在databases中,普通文件存在files中,缓存存在cache中。 在内部存储中的数据,当相关的软件删除时,会被同时删除。 2、外部存储 图中的mnt文件夹就是外部存储,不同的手机生产厂商对应的文件夹还可能是storage文件夹。在storage文件夹中还有一个文件夹sdcard。这个就是我们平时调用获取外部存储api时获取文件夹。在这个文件夹中公有目录和私有目录。公有目录有九大类。私有目录只有Android这一个,里边也是以包名为目录的。 在很多文章中说,内部存储就是手机自带的内存、手机出厂时已经有的内存。外部存储就是通过扩展SD卡的功能后增加的存储卡,这种是不正确的。 早期的Android设备,的确内部存储时自带的、固定的。但是后来的手机将自身的存储扩展到了8G以及更高,许多手机也不再提供扩展SD卡功能。这时就只是在概念上把手机的存储划出了内部存储和外部存储。所以不管有没有SD卡,都有内部存储和外部存储。但是不管什么情况,访问内部存储和外部存储都用的同一套Android Api。 在外部存储中的数据,当卸载软件时,该软件存在私有目录/data/storage/Android/data/包名/ 下的数据将全部删掉。软件存在公有目录下的数据不会被删掉。 3、存储空间的操作 操作内部存储空间和外部存储空间的私有目录时,以context获取的。操作外部存储空间时,以Environmnet获取。方法总结如下: 内部存储 目录 方法 /data/data/包名/files context.getFilesDir() /data/data/包名/cache context.getCacheDir() 外部存储 目录 方法 根目录 Environment.getExternalStorageDirectory() 公有目录(九大公有目录) Environment.getExternalStoragePublicDirectory(String type) 私有目录/data/storage/Android/data/包名/files context.getExternalFilesDir(String type) 私有目录/data/storage/Android/data/包名/cache context.getExternalCacheDir() 其中,公有目录的type类型,我们查看源码: /** * Get a top-level shared/external storage directory for placing files of a * particular type. This is where the user will typically place and manage * their own files, so you should be careful about what you put here to * ensure you don't erase their files or get in the way of their own * organization. * <p> * On devices with multiple users (as described by {@link UserManager}), * each user has their own isolated shared storage. Applications only have * access to the shared storage for the user they're running as. * </p> * <p> * Here is an example of typical code to manipulate a picture on the public * shared storage: * </p> * {@sample development/samples/ApiDemos/src/com/example/android/apis/content/ExternalStorage.java * public_picture} * * @param type The type of storage directory to return. Should be one of * {@link #DIRECTORY_MUSIC}, {@link #DIRECTORY_PODCASTS}, * {@link #DIRECTORY_RINGTONES}, {@link #DIRECTORY_ALARMS}, * {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_PICTURES}, * {@link #DIRECTORY_MOVIES}, {@link #DIRECTORY_DOWNLOADS}, * {@link #DIRECTORY_DCIM}, or {@link #DIRECTORY_DOCUMENTS}. May not be null. * @return Returns the File path for the directory. Note that this directory * may not yet exist, so you must make sure it exists before using * it such as with {@link File#mkdirs File.mkdirs()}. */ public static File getExternalStoragePublicDirectory(String type) { throwIfUserRequired(); return sCurrentUser.buildExternalStoragePublicDirs(type)[0]; } 可以看出九种类型是: 类型 意义 Environment.DIRECTORY_MUSIC 音乐保存的位置 Environment.DIRECTORY_PODCASTS 用于保存podcast(博客)的音频文件 Environment.DIRECTORY_RINGTONES 保存铃声的位置 Environment.DIRECTORY_ALARMS 警报的铃声 Environment.DIRECTORY_NOTIFICATIONS 通知音保存的位置 Environment.DIRECTORY_PICTURES 下载的图片保存的位置 Environment.DIRECTORY_MOVIES 电影保存的位置 Environment.DIRECTORY_DOWNLOADS 下载文件保存的位置 Environment.DIRECTORY_DCIM 相机拍摄的图片和视频保存的位置 其中,context.getExternalFilesDir(String type)的类型有7种,看主要源码: /** * @param type The type of files directory to return. May be {@code null} * for the root of the files directory or one of the following * constants for a subdirectory: * {@link android.os.Environment#DIRECTORY_MUSIC}, * {@link android.os.Environment#DIRECTORY_PODCASTS}, * {@link android.os.Environment#DIRECTORY_RINGTONES}, * {@link android.os.Environment#DIRECTORY_ALARMS}, * {@link android.os.Environment#DIRECTORY_NOTIFICATIONS}, * {@link android.os.Environment#DIRECTORY_PICTURES}, or * {@link android.os.Environment#DIRECTORY_MOVIES}. * @return the absolute path to application-specific directory. May return * {@code null} if shared storage is not currently available. * @see #getFilesDir * @see #getExternalFilesDirs(String) * @see Environment#getExternalStorageState(File) * @see Environment#isExternalStorageEmulated(File) * @see Environment#isExternalStorageRemovable(File) */ @Nullable public abstract File getExternalFilesDir(@Nullable String type); 可以看出七种类型是: 类型 意义 Environment.DIRECTORY_MUSIC 音乐保存的位置 Environment.DIRECTORY_PODCASTS 用于保存podcast(博客)的音频文件 Environment.DIRECTORY_RINGTONES 保存铃声的位置 Environment.DIRECTORY_ALARMS 警报的铃声 Environment.DIRECTORY_NOTIFICATIONS 通知音保存的位置 Environment.DIRECTORY_PICTURES 下载的图片保存的位置 Environment.DIRECTORY_MOVIES 电影保存的位置 注意:这个方法是可以传一个null的参数的,表示获取的是当前目录。如果传入类型,则获取的是对应的子目录。 下边给出一个对上边讲述方法进行运用的一个工具类: import android.content.Context; import android.os.Environment; public class SDUtil { // 判断SD卡是否被挂载 public static boolean isSDCardMounted() { return Environment.MEDIA_MOUNTED.equals( Environment.getExternalStorageState()); } // 获取内部存储文件的存储路径 public static String getFilePath(Context context) { return context.getFilesDir().getPath(); } // 获取内部存储缓存的存储路径 public static String getCachePath(Context context) { return context.getCacheDir().getPath(); } // 获取外部存储根的存储路径,因为不同的商家外部存储的绝对路径可能不同,所以用相对路径进行操作 public static String getExternalPath() { if (isSDCardMounted()){ return Environment.getExternalStorageDirectory().getAbsolutePath(); } return null; } // 获取外部存储公共目录的存储路径 public static String getExternalPublicPath(String type) { if (isSDCardMounted()){ return Environment.getExternalStoragePublicDirectory(type).getAbsolutePath(); } return null; } // 获取外部存储私有目录的文件的存储路径 public static String getExternalFilePath(Context context,String type) { if (isSDCardMounted()){ return context.getExternalFilesDir(type).getAbsolutePath(); } return null; } // 获取外部存储私有目录的缓存的存储路径 public static String getExternalCachePath(Context context,String type){ if (isSDCardMounted()){ return context.getExternalCacheDir().getAbsolutePath(); } return null; } } 这篇博客是一篇学习总结,如有错误的地方,请大家指正。

优秀的个人博客,低调大师

物联网设备无线充电技术解析

物联网将会成为自互联网诞生以来,最具革命性的进展,众多的预测机构也都对物联网的前景保持乐观,它们认为:未来几年后联网的设备数量将会达到百亿级别甚至更多。 毫无疑问,以后普通消费者的日常生活中将会充满形形色色的联网设备。由此,设备续航能力开始变得尤为重要,尤其是对于那些不方便连接电源的设备,例如可穿戴产品、交通工具等等。 相信那些智能手环与手表的使用者对此深有体会。近两年,无线充电技术越来越受到关注与重视,因为它将能够很好的解决设备续航能力的问题。 接下来物联网智库小编就将目前的无线充电技术的具体情况汇总整理给大家。 1.应用现状 随着智能手机和智能硬件呈铺天盖地之势来袭,充电已经成为比钻石还硬的刚需。 现在有很多公司正致力于通过无线设备让手机时刻保持充电状态。无线充电技术是对能量转换方式的大革新,便携设备无线充电的优势远远不止于摆脱线缆的束缚。然而,从尼古拉?特斯拉首次传输电力至今已经超过100年,但我们依然未能释放能量转换的全部潜力。 2015年无线充电板等发射端设备呈现飙升态势,穿戴式装置是带动2015年无线充电发射端装置出货量成长最主要的动力来源。接下来几年,可以想象笔记型电脑将开始支援无线充电接收功能,公共场所布建无线充电发送设备的需求将出现快速成长,越来越多消费者在日常生活中使用无线充电技术。 2.现有技术分析 100年前尼古拉?特斯拉发明了“特斯拉线圈”,通过空气传播电力,开启了无线式电力传播的时代。在无线充电技术尚未大面积普及的今天,我们不妨先将它粗暴地分为近场和远场充电两大类。 近场 近场无线传输的方式有很多,如电磁感应、磁共振、电容耦合、磁力耦合等等。前两个应该是目前市场上最常用的技术。 电磁感应(电感性耦合) 它使用导线线圈之间建立的磁场实现电能的无线传输。当电流流经发送线圈时,它会产生一个磁场,进而在接收线圈中感应出一个电压。线圈耦合得越好,电能传输得就越好。 如应用于手机背部、牙刷底部和充电底座集成线圈,产生磁场,两个线圈的相互作用能够传输电流,从而实现无线充电。 磁共振(共振感应耦合) 这种方法利用共振现象在一定空间内无线传输电能,其原理与电磁感应是相同的。发送器和接收器线圈以相同的频率振荡(或共振),共振感应耦合可使能量以高强度进行传输。 消费领域的主要无线充电标准大多依赖于上述两种方法,不过这项技术的缺陷在于传输距离较短,所以很多支持无线充电的手机,需要较为精确地摆放在无线充电底座上,才能正常充电,比起有线充电的稳定和用户粘度,它并未在消费者群体中显示出多大的优越性。 近场较为成熟的技术标准主要有:无线充电联盟的Qi、4AWP以及PMA三大标准。 Qi标准的创立者WPC联盟一直致力于开发一种全球统一的无线充电技术标准。目前有200多家公司提供的800多种产品都支持Qi标准。联盟管理成员包括LG、高通、三星、TI、东芝和Verizon。 Airfuel联盟是个全球性生态系统,是PMA联盟和A4WP联盟合并的结果。这一合并之举加速了未来消费者无论到何处,设备充电将具有互操作性、便利性的愿景实现。组成联盟董事会的公司有AT&T、英特尔、安森美、Powermat、三星和WiTricity。 远距充电系统 相较于近场充电系统,远距充电系统将能量从功率集线器传递至特定设备的方法更为多元,蓝牙、Wi-Fi、超音波和红外线等都曾被试用过。 首先说说Wi-Fi,就在去年,美国华盛顿大学已经成功研发了利用WiFi网络给硬件设备充电的技术。这个团队在大约十米的WiFi覆盖距离内给数码相机等设备完成充电,未来可应用于手机充电。据悉,这个团队研发的是一个“WiFi供电系统”,这个系统由WiFi接入点(路由器)和定制的充电传感器组成。 这个充电传感器安装在硬件设备上,主要用来接收射频信号(RF)中的电能,然后将射频信号转化为直流电进行充电。除了上述硬件外,该团队还研发了一套软件方案,该方案可让路由器在传输数据的同时为外部设备供电。那么问题来了,用于WiFi传输的数据和充电的信号会不会存在干扰呢?研究团队表示,他们已经有特定的解决方案来防止两个信号之间的干扰。例如在路由器和传感器上做出相应的优化,两大信号的传输可以互不影响。 而基于射频(RF)的系统如WattUp、Cota,均使用一个或多个天线广播能量并进行通讯。例如,Cota无线充电技术实际上是使用现有的Wi-Fi和蓝牙天线来实现数据通讯和接收无线功率,然后将这些微讯号挹注到电池的充电电流。 以uBeam为代表的超音波系统中,路由器中的讯号产生器负责产生电讯号,经过处理产生超音波,经过聚焦便会产生充电电流。然而这对系统和设备的要求比较高:必须具备高效率,并且能承受大能量讯号 Wi-Charge则专注于将红外线转换为电力。发射端透过雷射二极管向接收器准确地射出红外线光束,接收器中的太阳能电池则负责将红外线光转换回电能。 最近的突破当属Energous,做到了无线充电距离目前最远。它利用射频电波将无线电波转化成蓄电池电力,配有特殊接收器的无线装置就可以将电力从空气中抽离出来,为放在钱包、口袋或任何地方的手机充电。这种技术目前还存在局限性,因为它只能为嵌入芯片的小型设备充电,而且这些设备需要与Miniature WattUp发射机直接接触。 无线充电系统实作应注意五大重点 相较于有线充电,无线充电系统在先天上有许多变数,若突破不成反成绊脚,那实在遗憾。所以一些改变必须取舍有度: 1.移动性 在无线充电系统的实作中,定位和跟踪多个移动接收器的能力至关重要。必须考虑用户应能随意移动而不会丢失讯号。 2.辐射安全 射频安全性取决于在不损害人类健康的前提下,人体可以承受的照射量,通常是以吸收率(SAR)用来定义这个极限值。消费类产品的安全性要求其实相当严格,因为它关乎能否让消费者建立安全感,不能只以通过安全规范为目标来设计。 3.系统干扰 无线充电系统基于高频率开关讯号,必须具备预测噪讯来源的能力,包括充电系统本身的噪讯和系统外部的噪讯。 4.成本 在成本方面,需要考虑的两项因素是电源成本和传输效率。美国每年的电池使用量高达29亿颗,若无线充电普及,将具有避免数百万颗电池被投入垃圾掩埋场的潜力。 5.非接触唤醒 如何为完全没电的设备进行无线充电?是否要用到有线和无线两种技术的融合?这是原理设计不能跳过的问题。 3.落地困难 无线充电技术的落地困境和智能家居遇到的窘迫简直是异曲同工,惺惺相惜。一个字,乱。 虽然无线充电技术在近年来被广泛关注,但至今仍未真正在消费电子领域普及。虽有巨头大佬们对无线充电技术的布局和研发,市场的冷淡却表明,从尝试到大规模商用还有几段坎坷。 一是市场产业链混乱,二是技术标准纷杂,有待统一。 快速发展的无线充电市场迫切要求制造商和开发商为设备间互操作性制订全球统一的无线充电标准。显然,标准不统一是目前无线充电技术难以进一步普及的一大瓶颈,供应商在他们的产品中采用这些技术的步伐非常缓慢。毕竟大部分消费者并不喜欢繁琐和零碎的操作体验。不过,许多厂家都已推出支持双模无线充电标准的产品,多一个选择同时也可能是最好的解决方案。 一旦在这场无线标准之争中明确胜者,那么这个市场将很快形成数十亿美元的通用无线充电器业务 4.未来展望 2016年也将是无线充电应用多元化的关键年。可客观预测,支援无线充电功能的笔记型电脑将在2016下半年问世,并带动相关充电设备需求。 未来,整个行业希望看到类似Wi-Fi那样拥有超远传输距离、稳定性更好的无线充电技术,但仍面临一些技术障碍以及通信信道的监管问题。所以,无线充电在短时间内仍是消费电子领域的配角,发展壮大尚需时日。 无线充电技术既方便又好用,而且打破了空间上的限制,因此用户们可以利用一台发射器同时给多台设备充电,而且对充电设备所处的位置也没有特别的要求,这将会给接下来的生活带来更多的便利。可以看到,虽然目前这项技术还存在有诸多的问题,但是,相信在物联网的需求刺激之下,这项技术将会与人们的日常生活走得越来越近。 本文转自d1net(转载)

优秀的个人博客,低调大师

WiFi行业9大趋势解析

有鉴于近期Wi-Fi创新消息不断出现,预计2016年无线LAN技术发展将出现10项趋势值得外界关注,例如第二波802.11ac问世、分析技术成为必备条件、2.5/5/10Gbps出现以及Wi-Fi与LTE冲突持续、与更多Wi-Fi会在物联网(IoT)上采用。 据TechTarget网站报导,在十种趋势中,首先是第二波802.11ac正式报到。第二波802.11ac通常是指符合下列三项定义其中之一。 第一是可支援3种以上MIMO串流,而且其中2~3项为外界熟知,第二则是频宽最高可达160MHz,第三则是可支援多用户MIMO功能。 评论认为,虽然上述所有功能在2015年底前仍未全部到位,但由于预期无线射频基础建设、设计、韧体、天线与管理软体都会陆续取得进展,代表第二波802.11ac也将在今年成为新主流。 第二则是分析(Analytics)将成为必备功能。分析是指与采用的巨量数据有关的技术,以无线LAN技术为例,届时产生出与效能最大化、安全、应用程式使用等数据量相当庞大,因此须仰赖分析工具。 第三则是2.5/5/10Gbps将取代1Gbps网路聚合(link aggregation)。随着第二波802.11ac出现后,代表1GbE时代将退场。不过,目前仍有讨论空间的则是2.5/5Gbps产品是否会取代目前的2Gbps网路聚合,或下一波升级会直接达到10Gbps。 第四则是云端管理功能增多。由于成本下降、稳定性提升、取得容易以及可透过手机掌握全球性业务成真后,云端网路管理已逐渐被外界熟知与运用。加上拜软体定义网路(SDN、网路即服务(networking-as-a service)、稳定性及容错提升所赐,预计今年将看见更多网路功能开始移植至云端上。 第五则是802.11ad/WiGig正式报到。随着许多产品开始部署后,外界对于802.11ad或Wi-Fi联盟(Wi-Fi Alliance)称为的WiGig错误想法,也将告一段落。届时外界不管在开放办公室或密闭空间内,都将见识到802.11ad庞大的资料传输流通量(Throughput)以及效能惊人表现。 第六则是Wi-Fi将主宰物联网市场,因为Wi-Fi将成为许多商用或消费者应用的无线首选技术,而且目前市场上已出现各种规格、价格、效能、电池寿命与成本的产品与元件。 第七则是Passpoint与Wi-Fi Aware将简化用户移动装置的使用。在Wi-Fi联盟推出Passpoint技术后,让基地台系统连接Wi-Fi网路无须透过点击,等于宣告过去必须点击SSID与输入密码来连接Wi-Fi网路做法将成为历史,而Wi-Fi Aware功能提供服务探测也会提高其便利性。 第八则是Wi-Fi与未授权LTE(unlicensed LTE)冲突将会持续。因为少数基地台业者在Wi-Fi使用的频谱上部署未授权版本LTE将在今年成为趋势。虽然该频谱并非Wi-Fi独有,不过,由于Wi-Fi目前已到处可见并在部份设定成为关键任务,加上目前未授权LTE版本会干扰Wi-Fi运作的结果,代表外界势必得想出对策。 第九则是Wi-Fi将更为常见,例如在汽车、飞机、家庭、职场或其他地方都将见到Wi-Fi踪影,甚至微软(Microsoft)与Google等企业也会推出公共存取Wi-Fi服务。 最后则是无线LAN在过去20年来一直创新后将会出现更多成果。例如国际电机电子工程师学会(IEEE)目前已部署新标准,包括5GHz频带吞吐量预计可达10Gbps的802.11ax以及60GHz可达20Gbps的802.11ay标准,都将为提升处理量再创下新的标竿。 本文转自d1net(转载)

优秀的个人博客,低调大师

Cortex-M3启动深度解析

Cortex-Mx启动,备忘,以免将来忘记。 中断向量表不用说,从重置中断开始吧 LDR R0, =SystemInit BLX R0 LDR R0, =__main BX R0 这里一共就执行了两个函数,SystemInit和__main。 我们一般在SystemInit里面配置系统时钟,这里跳过。 __main是我们今天的重点。 __main: 0x080000C0 4804 LDR r0,[pc,#16] ; @0x080000D4 0x080000C2 4685 MOV sp,r0 #设置栈顶 _main_scatterload: 0x080000C4 F000F956 BL.W __scatterload (0x08000374) #分散加载(拷贝初始值、清零变量) __main_after_scatterload: 0x080000C8 F000F8D4 BL.W __cpp_initialize__aeabi_ (0x08000274) #C++初始化(全局对象构造函数执行) _main_cpp_init: 0x080000CC 4800 LDR r0,[pc,#0] ; @0x080000D0 0x080000CE 4700 BX r0 #进入C++的main函数 分散加载这里将会初始化我们的全局静态变量 .text:00000000 __scatterload_rt2 .text:00000000 LDR R4, =Region$Table$Base .text:00000002 MOVS R5, #1 .text:00000004 LDR R6, =Region$Table$Limit .text:00000006 B loc_14 .text:00000008 ; --------------------------------------------------------------------------- .text:00000008 .text:00000008 loc_8 ; CODE XREF: __scatterload_rt2+16j .text:00000008 LDR R3, [R4,#0xC] .text:0000000A LDMIA R4!, {R0-R2} .text:0000000C ORRS R3, R5 .text:0000000E SUBS R4, #0xC .text:00000010 BLX R3 .text:00000012 ADDS R4, #0x10 .text:00000014 .text:00000014 loc_14 ; CODE XREF: __scatterload_rt2+6j .text:00000014 CMP R4, R6 .text:00000016 BCC loc_8 .text:00000018 BL __main_after_scatterload 可能汇编看起来不是很直观,我们配合看F5得到的反编译C代码 void _scatterload_rt2() { _DWORD *i; // r4@1 for ( i = &Region__Table__Base; (_UNKNOWN *)i < &Region__Table__Limit; i += 4 ) ((void (__fastcall *)(_DWORD, _DWORD, _DWORD))(i[3] | 1))(*i, i[1], i[2]); _main_after_scatterload(); JUMPOUT(&Region__Table__Base); } 从上面看出,有一张区域表,每4个int作为一段,每一段前三个为参数,第四个为函数指针。 经过调试得知: 第一个函数是__scatterload_copy,从某个Flash地址把数据拷贝给RAM里面的变量,也就是带有初始值的全局变量; 第二个函数是__scatterload_zeroinit,顾名思义,就是全局变量清零,只要没有初始值的全局变量,都清零,堆空间和栈空间一块清。 而在汇编文件里面我们有AREAHEAP,NOINIT, READWRITE, ALIGN=3。显然其中的NOINIT并没有生效 ER_IROM1:0800D704 Region$Table$Base DCD 0x800D72C ; #要拷贝的初始值来源,紧跟在固件源代码后面 DATA XREF: ER_IROM1:__scatterload_rt2o ER_IROM1:0800D704 ; ER_IROM1:off_8000390o ER_IROM1:0800D708 DCD 0x20000000 #要复制初始值的起始地址 ER_IROM1:0800D70C DCD 0xCC #带有初始值的区域大小 ER_IROM1:0800D710 DCD __scatterload_copy ER_IROM1:0800D714 DCD 0x800D7F8 ER_IROM1:0800D718 DCD 0x200000CC #要清零的变量起始地址 ER_IROM1:0800D71C DCD 0x132C #要清零的变量大小 ER_IROM1:0800D720 DCD __scatterload_zeroinit ER_IROM1:0800D724 EXPORT SHT$INIT_ARRAY$Base 因此,针对__scatterload_zeroinit而言,为了加快启动速度,建议堆空间设得尽量小,然后在SmartOS系统初始化的时候再重新设置堆空间 我不相信神话,我只相信汗水!我不相信命运,我只相信双手! 分类: 物联网 本文转自大石头博客园博客,原文链接:http://www.cnblogs.com/nnhy/p/cortex_m3_boot.html,如需转载请自行联系原作者

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册