首页 文章 精选 留言 我的

精选列表

搜索[快速入门],共10000篇文章
优秀的个人博客,低调大师

Maven入门简明教程

自定义View系列教程00–推翻自己和过往,重学自定义View 自定义View系列教程01–常用工具介绍 自定义View系列教程02–onMeasure源码详尽分析 自定义View系列教程03–onLayout源码详尽分析 自定义View系列教程04–Draw源码分析及其实践 自定义View系列教程05–示例分析 自定义View系列教程06–详解View的Touch事件处理 自定义View系列教程07–详解ViewGroup分发Touch事件 自定义View系列教程08–滑动冲突的产生及其处理 探索Android软键盘的疑难杂症 深入探讨Android异步精髓Handler 详解Android主流框架不可或缺的基石 站在源码的肩膀上全解Scroller工作机制 Android多分辨率适配框架(1)— 核心基础 Android多分辨率适配框架(2)— 原理剖析 Android多分辨率适配框架(3)— 使用指南 Maven简介 Maven是一个项目管理工具 Maven主要功能:管理依赖、项目构建 Maven的使用需要依赖JDK Maven工程项目结构如下图所示: 安装Maven 第一步 在官网http://maven.apache.org下载Maven;将安装包解压至本地,如:D:\apache-maven-3.0.5 第二步 配置Maven环境变量MAVEN_HOME,值为D:\apache-maven-3.0.5 配置Maven环境变量PATH,值为;%MAVEN_HOME%\bin; 第三步 测试Maven是否安装成功。在命令行中输入:mvn -v 再回车 第四步 初始化Maven本地仓库。在命令行窗口中输入命令mvn help:system 待命令执行完毕后会在~/.m2文件夹下(~ 代表当前用户目录)生成本地仓库repository,例如: 为了方便开发和管理,在D盘建立文件夹apache-maven-setting用于存放用户的Maven配置信息。 将C:\Users\lf.m2下的repository拷贝至D:\apache-maven-setting 将D:\apache-maven-3.0.5\conf下的settings.xml拷贝至D:\apache-maven-setting文件夹中。 在D:\apache-maven-setting的settings.xml中添加一行代码用于指定新的本地仓库的地址 <localRepository>D:\apache-maven-setting\repository</localRepository> 详情请参见下图: 在完成如上操作后,D:\apache-maven-setting的目录结构如下: Eclipse整合Maven 安装Maven插件 新版的eclipse中已经集成好了Maven,无需再另行安装插件。如果是低版eclipse请自行在线或者离线安装。安装成功后在eclipse中可以看到: 设置Maven安装路径 将路径设置为磁盘本地Maven的安装路径。 设置Maven的用户配置 在此修改全局配置和用户配置,请注意路径;配置后本地仓库Local Repository也会自动变更为本地仓库的目录。 创建Java Web项目 第一步 File —–> new —–> Maven Project 第二步 第三步 点击 Finish 即可看到我们创建的工程,如下图所示: 看到此处,有些疑惑了:工程中不但有一个Java Resources还有一个src;这两者基本上是一模一样的,这两个有什么区别么? 其实,Java Resources中的内容和src文件夹里代码是一样的,为了方便开发人员更快地阅读Java代码,它以包的形式展现了我们的项目的Java代码。但是细心的人发现了:src下比Java Resources还多了一个webapp的文件夹,该文件夹用于放置前端页面以及脚本等等内容;目前该文件夹是空的,我们现为其添加WEB-INF文件夹和index.jsp文件从而与以往的dynamic web project保持一致。 嗯哼,文件夹和index.jsp都有了,但是报错了…….没事,我们来简单地配置一下即可: Java Build Path —–> Libraries —–> Add Library… —–> Server Runtime 添加Tomcat即可 第四步 在pom.xml中配置Tomcat <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>cn.com</groupId> <artifactId>Maven01</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <build> <plugins> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <configuration> <port>8082</port> <path>/Maven01</path> </configuration> </plugin> </plugins> </build> </project> 第五步 部署运行,Run As —–> Maven build 输入tomcat7:run再点击Run部署至服务端;浏览器中输入:http://localhost:8082/Maven01/index.jsp即可访问 Maven添加Jar包 一起来瞅瞅在Maven中如何添加第三方jar;比如,现在需要JUnit测试需要对应的Jar包。 第一步 在http://mvnrepository.com中找到需要的jar包 第二步 依据官网文档将其配置至pom.xml <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>cn.com</groupId> <artifactId>Maven01</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <build> <plugins> <plugin> <groupId>org.apache.tomcat.maven</groupId> <artifactId>tomcat7-maven-plugin</artifactId> <configuration> <port>8082</port> <path>/Maven01</path> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.7</version> </dependency> </dependencies> </project> groupId:定义当前Maven组织名称 artifactId:定义实际项目名称 version:定义当前项目的当前版本号 在Maven中每个工程都有它唯一的组织名、项目名、版本 ,三者可构成Maven坐标 第三步 好了,现在已经通过maven的方式导入了jar包,简单地测试一下: /** * @author 原创作者:谷哥的小弟 * @blog 博客地址:http://blog.csdn.net/lfdfhl * @time 创建时间:2017年8月9日 下午2:43:40 * @info 描述信息:测试代码 */ package cn.com.test; public class TestJar { @org.junit.Test public void test(){ System.out.println("hello maven"); } } OK!

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

Storm入门之附录C

本文翻译自《Getting Started With Storm》译者:吴京润 编辑:郭蕾 方腾飞 安装实际的例子 译者注:有些软件的最新版本已有变化,译文不会完全按照原文翻译,而是列出当前最新版本的软件。 首先,从下述GitHub的URL克隆这个例子: > git clone git://github.com/storm-book/examples-ch06-real-life-app.git src/main 包含拓扑的源码 src/test 包含拓扑的测试用例 webapps目录 包含Node.js Web可以执行拓扑应用 . ├── pom.xml ├── src │ ├── main │ │ └── java │ └── test │ └── groovy └── webapp 安装Redis Redis的安装是相当简单的: 从Redis站点下载最新的稳定版(译者注:翻译本章时最新版本是2.8.9。) 解压缩 运行make,和make install。 上述命令会编译Redis并在PATH目录(译者注:/usr/local/bin)创建可执行文件。 可以从Redis网站上获取更多信息,包括相关命令文档及设计理念。 安装Node.js 安装Node.js也很简单。从http://www.nodejs.org/#download下载最新版本的Node.js源码。 当前最新版本是v0.10.28 下载完成,解压缩,执行 <b>./configure</b> <b>make</b> <b>make install</b> 可以从官方站点得到更多信息,包括在不同平台上安装Node.js的方法。 构建与测试 为了构建这个例子,需要先启动redis-server >nohup redis-server & 然后执行mvn命令编译并测试这个应用。 >mvn package … [INFO] ———————————————————————— [INFO] BUILD SUCCESS [INFO] ———————————————————————— [INFO] Total time: 32.163s [INFO] Finished at: Sun Jun 17 18:55:10 GMT-03:00 2012 [INFO] Final Memory: 9M/81M [INFO] 运行拓扑 启动了redis-service并成功构建之后,在LocalCluster启动拓扑。 >java -jar target/storm-analytics-0.0.1-jar-with-dependencies.jar 启动拓扑之后,用以下命令启动Node.js Web应用: >node webapp/app.js NOTE:拓扑和Node.js命令会互相阻塞。尝试在不同的终端运行它们。 演示这个例子 在浏览器输入http://localhost:3000/开始演示这个例子! 关于作者 Jonathan Leibiusky,MercadoLibre的主要研究与开发人员,已在软件开发领域工作逾10年之久。他已为诸多开源项目贡献过源码,包括“Jedis”,它在VMware和SpringSource得到广泛使用。 Gabriel Eisbruch一位计算机科学学生,从2007年开始在Mercadolibre(NASDAQ MELI)任架构师。主要负责研究与开发软件项目。去年,他专门负责大数据分析,为MercadoLibre实现了Hadoop集群。 Dario Simonassi在软件开发领域有10年以上工作经验。从2004年开,他专门负责大型站点的操作与性能。现在他是MercadoLibre(NASDAQ MELI)的首席架构师,领导着该公司的架构师团队。 文章转自并发编程网-ifeve.com

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

Storm入门之附录B

本文翻译自《Getting Started With Storm》译者:吴京润 编辑:郭蕾 方腾飞 安装Storm集群 译者注:本附录的内容已经有些陈旧了。最新的Storm已不再必须依赖ZeroMQ,各种依赖的库和软件也已经有更新的版本。 有以下两种方式创建Storm集群: 使用Storm部署在亚马逊EC2上面创建一个集群,就像你在第6章看到的。 手工安装(详见本附录) 要手工安装Storm,需要先安装以下软件 Zookeeper集群(安装方法详见管理向导) Java6.0 Python2.6.6 Unzip命令 NOTE:Nimbus和管理进程将要依赖Java、Python和unzip命令 安装本地库: 安装ZeroMQ: 01 wgethttp://download.zeromq.org/historic/zeromq-2.1.7.tar.gz 02 03 tar-xzf zeromq-2.1.7.tar.gz 04 05 cdzeromq-2.1.7 06 07 ./configure 08 09 make 10 11 sudomakeinstall 安装JZMQ: 1 git clonehttps://github.com/nathanmarz/jzmq.git 2 cdjzmq 3 ./autogen.sh 4 ./configure 5 make 6 sudomakeinstall 本地库安装完了,下载最新的Storm稳定版(写作本书时是Storm0.7.1。译者注:翻译本章时已是v0.9.1,可从http://storm.incubator.apache.org/或https://github.com/apache/incubator-storm/releases下载),并解压缩。 编辑配置文件,增加Storm集群配置(可以从Storm仓库的defaults.yaml看到所有的默认配置)。 编辑Storm目录下的conf/storm.yaml,添加以下参数,增加集群配置: storm.zookeeper.servers: – "zookeeper addres 1" – "zookeeper addres 2" – "zookeeper addres N" storm.local.dir: "a local directory" nimbus.host: "Nimbus host addres" supervisor.slots.ports: – supervisor slot port 1 – supervisor slot port 2 – supervisor slot port N 参数解释:storm.zookeeper.servers 你的zookeeper服务器地址。 storm.local.dir: Storm进程保存内部数据的本地目录。(务必保证运行Storm进程的用户拥有这个目录的写权限。) nimbus.host Nimbus运行的机器的地址 supervisor.slots.ports 接收消息的工人进程监听的端口号(通常从6700开始);管理进程为这个属性指定的每个端口号运行一个工人进程。 当你完成了这些配置,就可以运行所有的Storm进程了。如果你想运行一个本地进程测试一下,就把nimbus.host配置成localhost。 启动一个Storm进程,在Storm目录下执行:./bin/storm 进程名。 NOTE:Storm提供了一个出色的叫做Storm UI的工具,用来辅助监控拓扑。 文章转自 并发编程网-ifeve.com

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

ios入门之界面基础

学习移动app开发,我们常常从讲解基本的控件开始,如UILabel、UISearchBar、UIButton、UITextField等等。在实现一个简单的ios 应用之前,我们首先来看ios开发中一些基本的概念。 视图控制器(View Controllers) 视图控制器是MVC(Modl-View-Controller)模式的逻辑部分。按照字面意思,这个控制器能够控制某个视图。 UIViewController 苹果极力推崇MVC这种开发模式,并且帮我们实现了一个叫做UIViewController的控制器,它是UIKit的一部分。UIKit是众多能够制作交互界面元素的类,如果你在某个类的开头是UI,那么这个类属于UIkit。UIViewController视图属性被连接到一个视图文件,大多数情况下,是一个storyboard文件。 UIViewController提供一些需要的方法和属性,通常我们在使用的时候只需要将UIViewController子类化即可。如: class mySubController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Do any addition setup after loading the view } } 在这个例子中,父类就是UIViewController。viewDidLoad()是UIViewcontroller默认的方法。 UINavigationController 我们在编写一个ios软件的时候,往往不只一个界面,界面之前跳转我们常常会用到navigation controller这么一个东西。一个UINavigationController可以在数组中支持多个UIViewController,导航控制器(navigation controller)按照先进后出的堆栈管理原则对我们创建的UIViewController进行管理。通过self.title属性来设置导航栏的标题。如: self.title =@"登录"; Table View Table views是用来显示滚动视图的控件,滚动视图是iOS Apps中最常见的用户界面。滚动视图中的每一行叫做cell,cell是用了展示table view中每行的内容。table view可以有很多个cell,多个cell组成section(组)。在iPhone的设置界面,就是用不同的section把界面分开,像通知中心,控制中心,个人隐私,每个table view都有header和footer,header是在cell上面,footer在cell下面。 Delegation 在很多的OA软件中,往往都有定时提醒这么一个功能。在App内部发生某个事件时,就会发出提醒,为某个事件订阅或者接收提醒的过程叫做delegation(委托)。例如,我们使用delegate创建table view,并告知要绘制10行。 override func tableView ( tableView: UITableView, numberOfRowsInSection section: Int ) -> Int { //Return the number of rows in the section return 10 } UITableViewController UITableViewController会自动创建一个table view,然后设置tableView属性,同时也需要委托自己获取所有需要的delegate方法。 UITableViewDataSource UITableView的delegate协议有三个必须要写的方法,叫做UITableViewDataSource。这个协议包括组的数量,美组中行的数量,以及cell如何展现。 第一个方法是numberOfSectionsInTableView(_:),如: override func numberOfSectionsInTableView(tableView: UITableView) -> Int { //#warning Potentially incomplete method implementation. //return the number of sections. return 0 } 注:注意到return那行目前是零,这意味着这个table view中没有组。苹果公司增加了一个警告注释,说如果组的个数是零,那么就不会显示行,组包含行cell,没有了组section,行cell也就不会被显示出来。 第二个方法是tableView(_:numberOfRowsInSection:),这个方法决定了某个组里具体有多少行,当然这里也不能为0: override func tableView(tableView: UITableView,numberOfRowsInSection section: Int) -> Int { //#warning Incomplete method implementation // Return the number of rows in the section return 5 } 第三个方法是tableView(:cellForRowAtIndexPath:),这个方法里有个参数值叫indexPath,是一个NSIndexPath。section组属性的索引是当前组,cell行属性的索引是当前行: 第一组第一行的索引NSIndexPath是0,0。 第一组第四行的索引NSIndexPath是0,3。 第三组第一行的索引NSIndexPath是2,0。可以用点语法调用section和row属性: var currentRow = indexPath.row var currentSection = indexPath.section tableView代码: override func tableView(tableView: UITableView,cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell { let cell =tableView.dequeueReusableCellWithIdentifier("Cell", forIndexPath: indexPath) as UITableViewCell return cell } ios跳转实例 为了方便大家的理解,我们先来一个简单的跳转的实例。1)打开Xcode,点击顶部菜单栏的File -> New -> Project,从模板中选择Single View Application,点击Next。如图: 2)输入项目名称等属性,点击Next。 3)打开Main.storyboard,点击Inspector上工具栏中第一个图标File Inspector,鼠标移动到到中间部分,不勾选Use Auto Layout选项。这时会出现一个对话框,选择iPhone。 4)选中这个界面,然后点击顶部菜单栏的Editor -> Embed In -> Navigation Controller。一个新的scene会增加到Storyboard中,一个scene表示App一屏或者一个界面。Navigation Controller Scene和之前的View Controller Scene是连接在一起的,这连接说明View Controller Scene是Navigation Controller Scene里第一个出现视图,点击Storyboard Editor左下角的盒子按钮打开Document Outline,Document Outline显示了storyboard文件中所有的控件以及控件所处的层次等级。 5)接下来我们在ViewController.m中新建一个按钮,用来跳转到第二个界面。先创建一个按钮,代码如下: UIButton * button=[UIButton buttonWithType:UIButtonTypeSystem]; button.frame=CGRectMake(130, 220, 100, 30); [button addTarget:self action:@selector(toNext) forControlEvents:UIControlEventTouchUpInside]; [button setTitle:@"跳转登录" forState:UIControlStateNormal]; [self.view addSubview:button]; 然后通过action添加跳转方法: //跳转到登录界面 -(void)toNext{ UIBarButtonItem * back=[[UIBarButtonItem alloc]init]; back.title = @"返回"; self.navigationItem.backBarButtonItem = back; SecondViewController * second = [[SecondViewController alloc]init]; [self.navigationController pushViewController:second animated:YES]; } 整体的代码结构如下:

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

GreenDAO系列之(1)入门

关于greenDao 简介 greenDAO 是一个开源的ORM数据库框架。它帮助开发者从日常的数据库的读写sql语句中解放出来,开发者只需要关注具体的Java对象,就能够进行数据库的访问操作。 greenDao features 1.强大的性能,可能是ORM数据库中性能最好的。官方把greenDao和OrmLite、ActiveAndroid做的性能对比,数据如下: 易于使用的API 低内存消耗 包size比较小,如果不包含加密,大概proguard后的包size为8k。 支持数据库加密: 支持SQLCipher。SQLCipher对个人开发者来说倒不错,不过对于公司来说吸引力不大。 greenDao 核心类说明 如上图所示,greenDao有几个核心类: DaoMaster : db的管理类,是db的总入口,总管的角色,管理着database创建、

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

Xamarin android SwipeRefreshLayout入门实例

android SwipeRefreshLayout 是实现的效果就是上滑下拉刷新ListView 获取其他控件数据.基本上每个App都有这种效果。Google提供了一个官方的刷新控件SwipeRefreshLayout,当然你得引入V4兼容包哦还不错项目中也用到了。所以就演示一下这个控件怎么使用吧. 还是先看一下Android SwipeRefreshLayout的API吧 谷歌翻译是这么说的: 的SwipeRefreshLayout应该用于每当用户可以通过一个垂直扫掠姿态刷新的图的内容。每当完成刷新姿态刷卡被告知实例这种观点应该添加一个OnRefreshListener的活动。该SwipeRefreshLayout将通知每一个手势再次完成一次每个听者和;听者负责正确确定何时开始实际内容的刷新。如果侦听确定不应该有一个刷新,它必须调用setRefreshing(假)来取消刷新的任何可视指示。如果活动希望只显示进度动画,它应该调用setRefreshing(真)。要禁用的姿态和进步的动画,在视图上调用的setEnabled(假)。 这种布局应该由将被刷新为手势的结果,只能支持一个直接子视图的父。此视图也将作出手势的目标和将被迫以匹配的宽度,并在此布局提供的高度。该SwipeRefreshLayout不提供无障碍的事件;相反,必须提供一个菜单项,以允许内容的刷新无论使用该手势。 看一下 效果图: 具体代码如下,先看一下布局页:Main.axml <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v4.widget.SwipeRefreshLayout android:id="@+id/swipeRefreshLayout" android:layout_width="match_parent" android:layout_height="match_parent" > <ListView android:id="@+id/listView" android:layout_width="match_parent" android:layout_height="match_parent"> </ListView> </android.support.v4.widget.SwipeRefreshLayout> </LinearLayout>MainActivity.cs: using Android.App; using Android.Runtime; using Android.Widget; using Android.OS; using Android.Support.V4.Widget; namespace SwipeRefreshLayoutDemo { [Activity(Label = "SwipeRefreshLayoutDemo", MainLauncher = true, Icon = "@drawable/icon")] public class MainActivity : Activity { int count = 1; private SwipeRefreshLayout swipeRefreshLayout; private ListView listView; private ArrayAdapter<string> adapter; private JavaList<string> data= new JavaList<string>{"恩比德","拉塞尔","安东尼-戴维斯","西蒙斯"}; protected override void OnCreate(Bundle bundle) { base.OnCreate(bundle); SetContentView(Resource.Layout.Main); listView = (ListView)FindViewById(Resource.Id.listView); swipeRefreshLayout = FindViewById<SwipeRefreshLayout>(Resource.Id.swipeRefreshLayout); swipeRefreshLayout.Refresh += (s, e) => { data.Add("张林-布莱恩特"); adapter.NotifyDataSetChanged(); swipeRefreshLayout.SetColorScheme(Android.Resource.Color.HoloRedLight); swipeRefreshLayout.Refreshing=false; }; adapter = new ArrayAdapter<string>(this,Android.Resource.Layout.SimpleListItem1,data); listView.Adapter = adapter; } } } 示例非常简单,体验一下效果而已。也许有人很郁闷了,这个JavaList是什么玩意?如果用List的话,下拉刷新就没有效果。目前就到这儿,过两天去问问牛哥,看是怎么回事。 昨天晚上写的,今天下午来改一改。终于找到了原因,这个Android自带的适配器选项样式对于List可能是个bug,所以呢自己写一个Adapter就可以用List了 示例代码下载: http://download.csdn.net/detail/kebi007/9652257 作者:张林 原文地址:http://blog.csdn.net/kebi007/article/details/52801731 转载随意注明出处

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

推送 从入门到放弃

推送 推送简直就是一种轻量级的骚扰方式 自从有了推送,各个公司基本上都在使用推送,这确实是一个比较好的提醒方式,Android较iOS强的一个部分,也就是在于Android的Notification。Google教育我们利用好Android的通知模块,做更多友好的交互,可这句话,翻译成中文,不知不觉,就变成了在Notification中推送各种广告,而且仅仅就是一些广告,Notification各种牛逼的功能,完全不需要,这也违背了Google设计Notification的初衷。 更关键的是,现在随便找一款App,没有推送的真是凤毛麟角,更可恶的是,做外卖的App给我推送奥运新闻,一条新闻十几个App推送,以至于现在很多用户都非常反感各种推送广告,就我本人而言,基本上会禁用所有广告类的App的推送。 本人非常反感推送,借用王思聪的一句话,XXX App天天给我推送各种广告,还TM是自己做的推送,真是绝了。 推送方案 轮询 轮询是最简单的与服务器保持通信的方式,即循环向服务器通信。这个方案的特点就是通信由客户端主动发起,你需要自己实现轮询消息队列、频率等等参数,在功耗和效果间做权衡,类似于TCP的短连接。 SMS 这个其实就是借助短信来实现信息的展示,只不过把短信内容展示到了Notification中,这个方案,到达率确实高,毕竟短信是比较可靠、稳定的,但劣势也很明显,就是成本很高,而且在Android平台上,短信的权限比较开放,容易被劫持。 长连接 长连接和前面提到的短连接,都是基于Socket连接的方式,他们的区别在与,短连接是每次数据传输完毕后就断开连接,而长连接不会。所以,基于轮询的方式,每次都要进行链路的连接,性能消耗更大,基于长连接的方式,就是对这点的改进。应用一旦与服务器连接成功,并不会主动断开连接,后面的通信都基于这个通道。目前大部分的推送服务都是基于长连接的推送,在后台维护一个Service,维持应用与服务端之间的TCP长连接。 推送方案 iOS iOS这边使用系统统一的APNs,所有推送消息都由苹果的服务器进行下发,同时,也由系统进行统一展示和处理。 GCM 与iOS一样,Android同样有一套内置的推送方案,但很可惜的是,Google的服务在中国大陆无法使用,草了个蛋。 第三方推送服务 专业的第三方推送 极光 个推 友盟推送 手机ROM厂商推送 华为推送 小米推送 BAT级别的全家桶 阿里推送 信鸽推送 百度推送 关于第三方推送服务在各个App中的使用率,大家可以参考贾吉鑫的这篇文章: https://mp.weixin.qq.com/s?__biz=MzA5OTMxMjQzMw==&mid=2648112527&idx=1&sn=b23c1b5f3e32e343ad96d705bd4d63ff 第三方推送注意 这些推送服务大同小异,基本上一家使用了一个新功能,另外几家,也会很快推出这个功能,就例如之前比较火的,『共享推送通道进行App唤醒』这个技术,友盟、个推推出后,很快其它推送服务商就支持了,所以开发者并不需要担心哪一家推送功能比较强。 这里还需要说下现在的『推送唤醒』这样一个功能,简单的说,就是所有安装了A推送的App,只要有一个还活着,就可以把其它安装了A推送的App拉起来,从而提高推送的到达率。有些阿里系、百度系的App,被大家称作『全家桶』,实际上就是因为这个原因,这个方式,确实能在一定程度上提高推送到达率,但另一方面,也破坏了Android生态,增加了功耗,打乱了系统的清理策略。 另外,小米推送、华为推送,大家接入的原因可能很简单,就是他们的手机市场占有率比较高,接入他们自家的推送,可以在一定程度上提高到达率,但需要注意的是,推送分为透传和非透传两种方式,透传即我们自己App处理推送消息,而非透传,则是交给相应的PushSDK处理,对于小米推送、华为推送来说,只有采用非透传消息,到达率采用保证,而透传消息,与其它推送并没有什么区别,换句话说,小米手机、华为手机,只对非透传的推送消息做了可靠性保证,但非透传消息的展示格式非常固定、简单,且不能自定义,这是一个很大的问题,这点应该是很多开发者的误区。 最后,很多推送服务都需要在Application中进行初始化,同时,各种被唤醒策略,又会拉起Application,导致推送进程的重复,所以,这里经常需要对进程名进行过滤,非主进程,不进行初始化。 自建推送服务 基本都是基于AndroidPN、MQTT、XMPP、长连接这些方式去实现的,自己搭建Push平台服务,一个最大的问题就是服务端的架构设计,不仅成本高,而且效果不一定好,建议中小企业不要轻易尝试。 推送名词解释 RegistrationID\ClientID 一般来说,类似这类ID都是用于唯一标识应用\用户的,每个App在每台手机上都会生成一个唯一ID。 RegistrationID\ClientID生成规则 Android平台上因为国内存在大量山寨设备,所以很多设备的IMEI、Mac地址、AndroidID 都有可能为空或者错误,所以不能单独作为唯一标识,需要将这些进行组合起来使用。 对于应用卸载后RegistrationID的问题,很多PushSDK的策略是,生成一个DeviceID保存到本地存储,应用被卸载后如果被重新安装,如果检测到存储里的DeviceID还在的话,就判定是同一个设备,不重新生成RegistrationID。 AppKey\AppID 这些Key基本都是用于验证App的,每个包名对应一个加密的Key。 透传\非透传 非透传消息是指推送消息被PushSDK获取并处理,透传消息是指推送消息被PushSDK交给宿主应用处理,非透传消息通常只能设置一些固定的样式,比较简单,而透传消息,可以由App自定义处理,比较灵活。 推送数据基础 累计注册 通过应用使用的appid统计用户注册总量。 日在线用户 通过应用使用的appid统计当天的在线用户数。 活跃用户 通过应用使用的appid统计当天在推送平台激活过的用户总数。 在线下发率 在线消息下发数/总下发数。 回执率 消息回执数(去重)/消息在线下发数。 到达率 到达数/实际下发数。 百日内联网用户数(可推送用户数) 是指最近三个月内有登录过(设备与推送服务端建立长链接)的设备总数,即有效可下发的用户数。一般的推送服务端认为,设备在100天内没有登录请求,认为该设备已经失效,所以无需再次发送。 实际下发数 实际可推送设备数(在消息有效期内,有联网并推送进程正常的设备,即消息有效期内的在线下发数。消息有效期就是设置的离线时间)。 到达数 客户端SDK接收到消息的设备数(通过统计客户端SDK接收到消息后的回执获得)。 展示数 用自定义非透传消息在用户手机展示过的设备数。 点击数 点击通知栏消息的设备数。 推送数据分析 那么关于推送,大家实际上最关系的,就是『到达率』。那么这个到达率究竟怎么计算呢? 首先我们举个例子来说明上面的这些数据背后的实际意义,例如,我们有一款App,有100w的下载量,每个App启动后,都将上报给服务器一个唯一ID,所以,累计注册量就是100w,也称发送总量。 那么在服务端准备发送推送的时候,当前手机端推送进程还活着的,也就是说推送的长连接还健在的,就是在线设备,如果按天算,那么就叫日在线设备数,我们假设这个数字是60w。 OK,推送发出去后,客户端收到推送消息,并产生回执,代表完成了一次推送,假设这些完成推送的设备是55w,这个就是送达设备数。一般来说,只要设备在线,基本都能送达,所以这个数字和在线设备数非常接近,不接近的话,这个推送基本就有问题了,其中可能送不达的原因就在于网络切换等导致长连接断掉这类因素。 那么到这里,一般的推送服务商会使用送达设备数/在线设备数的方式来计算到达率,当然,前面我们也说了,这个比例一定是很高的,如果保持长连接的设备都不能收到推送,那一定是有问题了。 而一般的到达率,应该是送达设备数/可送达设备数,也就是百日内活跃的设备数,这样一除,这个比例一下子就小了很多,因为谁也不知道,这一百天内曾经活跃的用户,第二天是不是就已经把你卸载了。所以说,Android下统计推送的到达率一般都很低,而推送服务商宣传的到达率都很高,这其实就是一个偷换概念的问题,我们说的是一般的到达率,而服务商宣传的是在线到达率。 而且,这个到达率与iOS完全没有可比性,因为iOS统一通过APNs来进行推送,且无法获取到达回执,所以,iOS基本不存在到达率这一说法,如果有,几乎也是100%,完全没有意义,所以,如果哪一天有产品或者运营跟你说,为什么Android的到达率比iOS的到达率差这么多,请毫不客气的砸它一斤苹果。 Tag\Alias Tag Tag,或者叫标签,是用户的一种属性,在给某些用户设置某类标签后就可以针对推送。比如给喜欢『编程』的人打上『编程』的标签,就可以只给他们精准推送。 通常情况下,一个设备(在一个App里)可以设置多个标签。标签与别名类似,其对应关系也是保存在推送服务器侧的。 Alias Alias,或者叫别名,是对已经安装某应用的用户取个别名进行标识,在对该用户消息推送时,就可以用此别名来进行推送。设置了别名后,推送时服务器端指定别名即可。推送服务器端来把别名转化到设备ID来找到设备。 Tag和Alias他们的共同点在于,提供对用户的精确推送。 推送原理 目前大部分的第三方推送服务,都是基于长连接的推送方案,下面将对这个方式进行详细讲解。 NAT 首先,我们需要了解下一个网络基本知识——NAT,即网络地址转换(Network Address Translation,NAT),这是因为IP地址是有限的,手机无论是通过路由器还是数据网络,都有一个内网IP地址,同时,路由器上会维护一个外网IP地址,从而形成一个NAT路由表,即内网IP地址:端口,以及对应的外网IP地址:端口。这样通过一层层封装与解封装,就达到了内网与外网交换通信的方式。 NAT超时 由于NAT路由表的大小有效,所以一般路由都有NAT有效期,WIFI下,这个NAT有效期可能会比较长,而在数据流量下,运营商一般都会尽快更新NAT路由表,淘汰无效的设备,所以,在使用数据流量时,长连接经常容易断。 那么除了NAT路由表主动淘汰过期的设备之外,切换网络环境和DHCP服务器租期到期,这些情况都有可能导致NAT路由表改变,从而造成长连接中断。 心跳包 前面我们说了,现在的推送服务一般采用的是长连接的通信方式,而长连接会因为NAT路由表的更新而中断,所以,客户端会定时向服务端发送一个心跳包,来定期告知NAT路由表,我还活着,别杀我!这就是心跳包的作用——防止NAT路由表超时,同时检测连接是否被断开。 心跳包的心跳时间 既然心跳包的作用是防止NAT超时,那么就需要将心跳包的发送频率设置为小余NAT超时的检测频率,而WIFI和数据流量下,对于NAT路由表的超时时间又是不一样的,而且不同的网络运营商的超时时间,甚至都不一样,所以,一个比较好的方法就是根据设备当前网络环境,来动态的设置心跳时间。 注意,心跳包与轮询是不一样的,心跳包建立在长连接上,只要发送数据即可,而轮询每次都是一个完整的TCP连接。 心跳包谁来发 既然需要定时任务,那么就需要使用AlarmManager来作定时唤醒了,原因我之前的文章有讲过,是关于处理器唤醒的原因,这里就不赘述了,大家可以参考我之前的文章: http://mp.weixin.qq.com/s?__biz=MzAxNzMxNzk5OQ==&mid=2649484680&idx=1&sn=bd9086a95b769af8d8644cf681ce66ec#rd 进程保活 所谓进程保活,是指App希望尽可能的保证自己的App的推送进程能够存活在后台,以保证可以收到服务端的推送消息,因此,才出现了一大批关于进程保活的方式,例如NDK层的文件锁,fork子进程、前台服务、进程优先级等等方式,然而,这些东西,实际上,都不能完全保证手机的进程管理策略放过你,特别是Android 5.0以后的系统,Android对进程的管理更加严格,还有国内的这些ROM层的修改,ROM想要杀你这个进程,你怎么做也没有办法,哦,除了白名单。所以,不要再花心思去找什么进程保活的黑科技了,好好做好应用,提供用户的使用黏性,才是最佳的保活,而对于一些产品、运营所谓的『为什么微信、QQ都可以保活』这样的问题,我建议你回答它:『如果你能把产品做到微信、QQ那样的数量级,我也能让你活!』 推送整合方案 介于各种第三方推送与ROM推送的特点,我们目前采用的推送方案,名为『UniversalPushSDK』,即整合了多个不同的推送渠道,通过模板设计模式来进行整合,并向外暴露统一的接口,这种方式的好处在于UniversalPushSDK利用的各个不同推送特点,提高推送到达率,但是坏处在于,包的体积会大一些。例如,我们现在整合了『小米推送、极光推送、华为推送』,在系统启动的时候,判断当前系统,如果是小米系统,则启用『小米推送』,如果是华为手机,则启用『华为推送』,其它的Android设备,则启用『极光推送』,通过这种方式来设计我们自己的推送SDK,可以在一定程度上,利用好各个推送平台的特性。 那么如果利用这种方式来设计SDK给到不同的App接入,就需要能够将应用的推送Key做到动态配置,这也是我们遇到的最大的一个问题,解决方法大家可以参考我之前写的一篇文章: http://blog.csdn.net/eclipsexys/article/details/51283232 虽然我极力反对这种方案,我坚持认为,做好App,提升用户使用黏性,才是提升推送到达率的关键

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Spring

Spring

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

Sublime Text

Sublime Text

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

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册