移动开发_开发板移动 - CSDN
  • 本视频教程拥有180节课程,包含iOS开发的方方面面:iOS开发基础理论知识、 视图、视图控制器、多媒体、数据处理、常用插件、信用卡卡号识别、自动化测试、网络访问、多线程、ShareSDK社会化分享、CoreImage、...
  • ... 使用列表系列标签完成常见网页中的列表结构; 熟练掌握表格,表单都系列标签,在项目中熟练使用;...了解哪些标签在项目中经常使用,哪些标签已被废除;...迈出HTML5开发的第一步,为后续课程打下基础;
  • 移动开发没人要了?

    2019-01-17 09:48:21
    作者 |梅梅本文经授权转载自100offer(ID:im100offer)对于移动互联网而言,2018 年像是球场上的一声裁判哨。哨声响起,高潮迭起的上半场结束。本该再...
        

    640?wx_fmt=gif

    640?wx_fmt=jpeg

    作者 | 梅梅

    本文经授权转载自100offer(ID:im100offer)

    对于移动互联网而言,2018 年像是球场上的一声裁判哨。哨声响起,高潮迭起的上半场结束。本该再创辉煌的下半场,还没开赛却被告之:规则改变、场地收缩、教练下课、冷板凳无限加长。

    这样前途未卜的下半场,你还敢上吗?

    作为队伍「前锋」的移动端程序员,面对这样的挑战,又有哪些不一样的表现和前景?本文将结合平台招聘数据和候选人采访,展现移动端程序员「冰火两重天」的 2018 年。

    注:本文数据除另行说明外,均取自 2018 年 1 月 1 日至 12 月 31 日,经筛选在 100offer 进行匿名展示的 1464 位移动端方向求职者。他们收到的面试邀请和薪资,普遍高于市场平均水平。


    640?wx_fmt=png

    2018:移动端上半场宣告结束


    纵观近几年的平台数据,虽然移动端市场供需从 2016 年开始呈下降趋势,但是人均面邀数一直小幅增长。然而,2018 年这一趋势被彻底打破。

    640?wx_fmt=png

    相比于 2017 年,2018 年 Android 程序员人均面邀数减少 40%,iOS 程序员降幅更高达 57%,即平均每个移动端程序员在找工作时收到的面邀数比去年减少一半。

    640?wx_fmt=png

    2018 年移动端程序员在求职人数上较 2017 年小幅上涨,面邀总数却大幅缩水,进一步加大的供需之间的矛盾。虽然从现有的比例上还没有到「供大于求」的局面,但是考虑到 100offer 的求职者均为 2 年以上经验的中高程序员,可以看出移动端市场在 2018 年走入拐点,从前「遍地开花」的移动端在 2018 年「跌入尘埃」。移动端「不愁工作不愁钱」的上半场宣告结束。

    640?wx_fmt=png

    2018年1-9月中国手机月度出货量,来源:Trustdata

    移动端市场的衰落其实早已有迹可循。根据 Trustdata《2018 年 Q3 中国移动互联网行业发展分析报告》显示,2018 年前三个季度中国手机月度出货量同比大幅下滑,智能手机的渗透率接近饱和,移动互联网用户从增量市场转向存量市场,暗示着移动互联网的红利期结束。

    640?wx_fmt=png

    2018年9月中国移动互联网用户累计使用时长,来源:Trustdata

    伴随着移动端用户增速的放缓,现有市场则被国内几大互联网巨头牢牢把控。移动端市场经过几年的大浪淘沙,沉淀下来的 APP 产品逐渐稳定,对于移动端人才需求的增速也日趋下降。虽然不乏有今日头条、拼多多、趣头条等互联网公司的加速拓张,但是更多的公司在 2018 年都处在一个相对平稳甚至「瘦身」的阶段。现有的移动端程序员就成了泡在海绵里的水,太阳一晒,「蒸发淘汰」成了不可避免的命运。


    640?wx_fmt=png

    移动端程序员:上半年的宠儿,下半年的弃儿


    「我知道这一天迟早要来,但是没想到它来得这么快。」郭昌这样评价移动端遇冷的现状。

    作为有 4 年工作经验的移动端程序员,郭昌一直有强烈的危机感。2014 年他刚入行的时候,移动端的就业市场简直可以用「火爆」两个字来形容。

    「所有的公司都在抢人,用钱砸人。一个稍微懂点安卓开发的实习生一个月都能拿七八千,更别说懂 C++ 或 JAVA 的科班生了。」

    郭昌是「半路出家」,土木工程专业毕业的他,在建筑行业「日落西山」的当口,毫不犹豫地选择「弃暗投明」,投身热火朝天的移动互联网行业。

    「移动端程序员入行其实并不难,跟在老程序员后面看三个月,基本上就摸清门道了。而且 2014、2015 年做移动端追的是速度和用户量。某一类 APP 火了,你得立马跟上,根本没有太多的精力去做更深入的开发。」

    只用了短短两年时间,郭昌的年薪就破了 25 万。但是到了 2016 年下半年,郭昌明显感觉移动端程序员的需求量大不如前。「公司挑人开始越来越严,很多大公司要求硕士学历,培训班出来的非科班生越来越不受待见。」

    2018 年下半年,郭昌的焦虑终于变成了事实,他被公司裁员了。

    「公司 APP 下架的第二天,整个技术部门就解散了。虽然拿了 2 个月工资的赔偿金,但我一点也开心不起来,因为我知道移动端的好日子是真的到头了。」

    640?wx_fmt=png

    根据对 2018 年移动端程序员的季度统计数据显示,Q1移动端程序员的平均面邀数为 3.1 个,相较 2017 年 4.4 个的人均面邀数,呈直线下降趋势。本应迎来全年求职最高峰的 Q2 也遭遇「滑铁卢」,不管是人均面邀数还是平均面邀薪资都大幅下降。接下来的 Q3、Q4 更是将这种颓势进一步加大。等到了 Q4,移动端程序员的人均面邀数仅为 1.7 个,比 Q1 减少了近一半。而人均面邀薪资也从 Q1 的 514K 直线降到了 Q4 的 413K ,降幅近 20%。

    移动端程序员早就饱和了,市场根本消化不了这么多人。之前市场好的时候,公司多招几个人好干活。2018 年下半年移动端一遇冷,不仅小公司要降薪裁人,大公司也基本上把 HC(职员人数总额)都冻结了。」资深移动端专家杨辉在接受采访时,这样说道。

    资本市场遇冷和人才供需比例失衡是造成 2018 年下半年移动端程序员「失宠」的主要原因。

    资本寒潮中,创投和私募机构的投资变得尤为谨慎,一些已融资多轮的互联网明星企业争相选择在今年上市「回血」,比如小米、爱奇艺、英语流利说、拼多多、趣头条等。而另一些公司则通过裁员瘦身「过冬」:BAT 等大厂招聘岗位冻结,京东、知乎、美团传出不同程度的「优化」消息。

    640?wx_fmt=png

    中国互联网行业中高端人才招聘报告,来源:e成科技研究院

    (供需比:岗位从业人数 /岗位数,供需比>1,表示该岗位从业人数多于岗位数)

    与大环境对应的是移动端市场的人才供需比失衡。根据 e 成科技发布的《中国互联网行业中高端人才招聘报告》统计,2018 年 9 月移动开发工程师的供需比为 1.13:1,高于软件开发、运维工程师、web 前端开发等其他技术岗位。用郭昌的话来说,就是「上半年两个岗位抢一个移动端程序员,下半年两个程序员抢一个岗位」。2018,移动端程序员从上半年的「宠儿」走向下半年的「弃儿」。


    640?wx_fmt=png

    下半场淘汰加剧,留下的都是「悍将」


    上文中提到的移动端资深专家杨辉,是国内某一线互联网大厂移动端招聘的主面试官。他这样解释目前移动端市场的招聘门槛:「根据我的了解,现在国内一线大厂基本上很少招初中级的移动端程序员了。最起码要有 4 年以上的工作经验,要对底层技术比较了解,还需要求职者有优化能力和框架设计能力。」

    对于 4 年以下的求职者,除非有互联网大厂经验,学习能力强,有着完整的项目经验,否则很难进入互联网大厂的面试环节。

    求职者晓东通过自己的面试经历,侧面证实了杨辉的言论绝非「危言耸听」。晓东有两年半的 Android 开发经验,11 月想要看新的工作机会。照以往的经验,换一份工作对于他并不是难事。但是面试了五家公司,只有一家天使轮的创业公司给他发了 offer,其他四家无一例外都拒绝了他。与面试公司的 HR 沟通之后,他才知道自己败在「不够资深」上。

    「其实也不难理解,现在互联网大环境不好,公司想招的是能帮公司打硬仗的人,而不是还要别人带教的小白。」晓东在总结失败经验时,认为自己除了工作年限的「硬件」不够,对于底层核心技术和基本原理的缺失,也是一大硬伤。

    「以前公司招移动端程序员,主要看你做过哪些项目,会不会画 UI,能不能写界面和业务逻辑。但是现在面试除了问你项目经验,还会问底层和原理的问题,甚至会延伸到公司的业务和数据。如果平时只顾埋头敲代码,肯定一问三不知。」

    640?wx_fmt=png

    2018年某司Android程序员JD岗位要求

    在 100offer 平台 2018 年的移动端程序员招聘 JD 中,大多数企业除了对求职者的语言和编码等基础能力提出要求外,越来越强调对于 Framework 层的理解和 UI 框架的掌控能力。而完整的项目经历和多端知识也成了重要的加分项。

    最后晓东打算在公司再沉淀一两年,等自己的能力达到「资深」的标准,再去寻找新的工作机会。

    640?wx_fmt=png

    640?wx_fmt=png

    通过 2017 和 2018 年不同工作年限移动端程序员的人均面邀数和面邀均薪进行比较,2018 面邀数下降幅度最大的,是工作 4-6 年的程序员。而在全年整体面邀数下滑的情况下,工作 7-9 年和 10 年以上的程序员,收到的人均面邀数却实现了小幅增长。在面邀薪资方面,工作 7-9 年和 10 年以上的求职者的面邀薪资也一路「高歌猛进」。

    「大龄」一直被视为程序员职场「催命符」。但在2018 年的经济寒冬,大龄移动端程序员却似乎迎来了久未谋面的「春天」。

    此前的文章中曾多次探讨过程序员的「中年职场危机」问题,在各类社交媒体上,关于程序员「35 岁失业危机」的讨论也从未断绝。

    「很多人认为程序员这一行吃的是青春饭,35 岁职业生涯就到头了。虽说程序员需要拼体力,但是35 岁还在拼体力的程序员,绝对不会是一个优秀的程序员,被淘汰也是理所当然的。」从 Android 工程师成长为架构师的廷轩说。

    640?wx_fmt=png

    2018年某初级Android程序员招聘JD要求

    640?wx_fmt=png

    2018年某资深Android程序员招聘JD要求

    对比企业关于初级移动端程序员和资深移动端程序员的招聘要求,很明显可以看出,初级移动端程序员的招聘要求主要是熟练的语言基础,而资深移动端程序员则需要对设计模式、深层管理机制、底层原理有足够的理解,能从全局上对产品的设计和开发进行把控。

    俗话说,姜越老越辣。对于移动端程序员而言,「辣」的不只是资历,更是「全局观」与「掌控力」。


    640?wx_fmt=png

    2019:逆风而上,方是勇士之举


    2018 年对于移动端人而言,是「兵荒马乱」的一年。中兴、华为先后遭欧美国家打压,苹果手机遭起诉,在中国的销售前景不明,中国移动端市场进入「淘汰期」。2019 年的移动端市场发展,是一个让人「忐忑不安」的未知数。

    与此同时,移动端的技术迭代从未停住脚步。谷歌推出 Flutter 框架和 Dart 语言,Facebook 大规模重构 React Native,华为确认正自主研发手机操作系统替代 Android。2019 年的移动端技术发展,注定是「只见新人笑,不闻旧人哭」的新里程。

    作为 2018 年移动端跳槽「薪资王」的杨辉,凭借自己稳扎稳打的 7 年移动端经验,成功以 65 万年薪跳槽至现在的公司。在谈及移动端技术的「变革」时,他非常坚定地认为:现有的移动端技术短期内依然「不可替代」,但是未来会和更多的新领域进行融合与合作。

    「包括智能汽车、智能电视、AI、VR 产品都和安卓系统有关联,都是在安卓系统上做出的创新。移动端音视频也能和 AI、推荐算法融合。」

    饿了么架构师 MM 也表达了同样的观点。「移动端的需求一直都在。但是未来需要移动端程序员往最底层和原理研究。对于程序员,到了一定阶段,不应该被语言和平台限制。」

    同时,他们都提出,即使有一天现有的移动端技术真的被取代,对于真正「功力深厚」的移动端程序员也造不成任何威胁。因为技术是相通的,之前的开发经历完全可以复用和迁移。

    但是对于那些「什么基础都没有,只会画UI,写界面,写业务逻辑」的移动端程序员而言,技术和语言的转变则会是「灭顶之灾」。

    在谈到当下移动端程序员普遍存在的问题时,MM 提到了以下几点:

    (1)只重视过程,不重视结果。有些移动端程序员虽然加班很多,但是产出的质量和工作时间不成正比。

    (2)不关心数据。做了技术方案却不测试数据。但其实测试数据很重要,关乎很多核心的要点。

    (3)不沟通,不交流。部分移动端程序员喜欢闷头做事,对自身的成长非常不利。只有经常参与别人的讨论才能发现自己的短板,更大程度地获得进步。

    (4)没有 owner 精神。一些移动端程序员不能把事情做到有始有终,没有负责的态度。

    (5)不学习。移动端是一个新技术更迭换代很快的行业,如果不学习,很容易被淘汰。

    想要在市场和技术双重冲击的 2019 年「逆风而上」,移动端程序员需要注意以下几点:

    (1)跨平台一站式开发将是未来趋势,要注重积累相关技术经验

    从Facebook推出的RN(ReactNative)到近期 Google 推出的 Flutter,包括很多小程序快应用,都是移动端跨平台技术应用的尝试。虽然很多跨平台方案都有优缺点,至今没有完善的替代方案,但这是未来移动端开发不可逆转的大方向。

    对于这些跨平台技术,即使在日常工作中不常使用,也需要不断学习跟进,为即将到来的改革做好充足的准备。

    (2) 对于行业的选择要更加谨慎,切勿「金钱至上」

    做程序员,一方面练技术,另一方面选行业也特别重要。因为持续的行业经验对职业发展有很大益处,也能规避过高的波动和风险。2018 年 P2P 的暴雷就给移动端程序员和全体互联网人敲响了警钟。

    不过,具体的行业选择是一个仁者见仁智者见智的问题,MM 的个人经验是:「选择一个真正能对人的生活产生价值的行业,比如出行、生活服务等等。移动端程序员要有行业风险判断意识,要重「技术」和「产品」,不能一味地看重高薪,要知道高收益也往往意味着高风险。」

    (3)做好职业规划,为自己建立良好口碑

    切记做好职业生涯规划和时间管理,要有充分的时间去和别人做交流,了解「业界大佬」的做事内容和方式。人脉对于程序员很重要,不要拘泥于自己的小圈子,要去结识更多有能力的人,寻找更多的前进动力。另外,求职者如果拥有良好的人脉和业界口碑,在开源社区和别人有过合作,或者自身拥有开源代码,得到大家的认可,很容易不经过面试就得到新的工作机会。

    (4)寒冬之下,更好地学习提升才是王道

    2019 年不是颠覆性的一年,但是新技术会不断出现,「安于现状」是移动端程序员的大忌。每年苹果、Google、Facebook 等全球领先互联网公司推出的新技术一定要关注,对于底层知识架构需要不断加深。此外,在本行业深耕细作的基础上,要不断扩展自身的技术栈,对于行业知识进行深入了解。除了阅读书籍,还可以通过老司机 iOS 周报、SwiftGG 翻译组、业界大牛的博客等途径获取相关的学习方法和内容。

    「2019 年会是过去十年中最差的一年,却是未来十年中最好的一年。」这是最近流行于网络的一个段子。但是在移动端的球场上,即使比赛会越来越艰难,但是下半场的哨声已经响起,继续踢下去的「勇士」才可能赢得胜利。

    2019 年移动端下半场,你准备好上场了吗?

    (为保护采访对象隐私,本文中的郭昌、晓东、杨辉均为化名)。

    640?wx_fmt=jpeg

     热 文 推 荐 

    ☞ 谁能真正“撬动”微信?| 畅言

    ☞ 上线 5 天获得 100 万用户,可为什么我开发的 App 最终却倒闭了?

    ☞ 程序员遇到什么样的工作状态应该果断跳槽走人?

    ☞ 吃亏的程序员,是如何拿到了9个月的年终奖?

     刚刚!程序员集体荣获2个冠军,这份2018 IT报告还说这些!

    ☞ 云头条 | 华为云发布全新Slogan;AWS推出DocumentDB;FRB信号刷屏

    AI删库,程序员背锅?

    Grin带火的MinbleWimble技术,到底是个什么鬼? 

    print_r('点个好看吧!');
    var_dump('点个好看吧!');
    NSLog(@"点个好看吧!");
    System.out.println("点个好看吧!");
    console.log("点个好看吧!");
    print("点个好看吧!");
    printf("点个好看吧!\n");
    cout << "点个好看吧!" << endl;
    Console.WriteLine("点个好看吧!");
    fmt.Println("点个好看吧!");
    Response.Write("点个好看吧!");
    alert("点个好看吧!")
    echo "点个好看吧!"

    640?wx_fmt=gif点击“阅读原文”,打开 CSDN App 阅读更贴心!

    640?wx_fmt=png喜欢就点击“好看”吧
    展开全文
  • 移动开发基础

    2018-07-04 12:31:19
    原文点击打开链接一个移动端的时代从我工作以来,开发的一直都是移动端的页面,只有偶尔去开发几个PC端的页面,现在是一个移动端的时代,移动先行已经深入骨髓,作为一个web前端开发,如果你还在为如何开发移动端...

    原文点击打开链接

    一个移动端的时代

    从我工作以来,开发的一直都是移动端的页面,只有偶尔去开发几个PC端的页面,现在是一个移动端的时代,移动先行已经深入骨髓,作为一个web前端开发,如果你还在为如何开发移动端页面而迷茫,或者你还在为开发出了一个在你手机上“完美”的移动页面而沾沾自喜却不知移动的世界有多“残酷”的时候,那你应该看看这篇文章了。希望这能给你帮助,同时也能给我帮助,有不合理的地方,欢迎评论支持,必将改正。

    移动端

    这里是基础,你了解否?

    一、像素 - 什么是像素

    像素是web页面布局的基础,那么到底什么才是一个像素呢?
    像素:一个像素就是计算机屏幕所能显示一种特定颜色的最小区域。 这是像素的概念,实际上,在web前端开发领域,像素有以下两层含义:
    1、设备像素:设备屏幕的物理像素,对于任何设备来讲物理像素的数量是固定的。
    2、CSS像素:这是一个抽象的像素概念,它是为web开发者创造的。

    如下图,是在缩放比例为1,即scale = 1的情况下,设备像素和CSS像素示意图

    设备像素和CSS像素

    现在你已经了解了,原来像素对于web前端开发来讲有这样的两层含义,那么你有没有再深入的考虑这样一个问题,当我给一个元素设置了 width: 200px; 这条样式的时候,到底放生了什么事情?
    你可能会说:“废话!元素的宽度是200px呗。”;对,并没有什么问题,但是这个200px指的是什么呢?因为我们知道,对于web前端来讲像素有两层含义,那么到底是设备像素还是CSS像素?实际上我们控制的是CSS像素,因为前面提到了,CSS像素是给我们web前端开发者创造的抽象概念。所以你要记住:当你给元素设置了 width: 200px 时,这个元素的宽度跨越了200个CSS像素。但是它并不一定跨越200个设备像素,至于会跨越多少个设备像素,就取决于手机屏幕的特性用户的缩放了,举个栗子:

    苹果手机的视网膜屏幕,是一个高密度屏幕,它的像素密度是普通屏幕的2倍,所以当我们设置 width: 200px; 时,200个CSS像素跨越了400个设备像素,如下图:

    苹果视网膜屏幕的设备像素与CSS像素的关系

    如果用户缩小页面,那么一个CSS像素会明显小于一个设备像素,这个时候 width: 200px; 这条样式中所设置的200个CSS像素跨越不了200个设备像素,如下图:

    用户缩页面时设备像素与CSS像素的关系

    让我们来做一个总结

    1、web前端领域,像素分为设备像素CSS像素
    3、一个CSS像素的大小是可变的,比如用后缩放页面的时候,实际上就是在缩小或放大CSS像素,而设备像素无论大小还是数量都是不变的。

    二、移动端的三个视口

    一看标题,你是不是蒙了?三个视口?什么三个视口?先别急,让我们慢慢来讲。
    你一定写过这样一条样式:width: 25%; 但是你有想过给一个元素加上这样一条样式之后发生了什么吗?25%是基于谁的25%?明白的同学可能知道了:一个块元素默认的宽度是其父元素的100%,是基于起父元素的,所以25%指的是父元素宽度的25%,所以,body元素的默认宽度是html元素宽度的100%,那么你有没有想过html元素的宽度是基于谁的呢?这个时候,就要引出一个概念:初始包含块和视口了

    记住一句话:视口是html的父元素,所以我们称视口为初始包含块。 这样你就明白了,html元素的百分比是基于视口的。

    第一个视口:布局视口

    首先你需要了解一个原因:浏览器厂商是希望满足用户的要求的,即在手机也能浏览为PC端设计的网站,所以浏览器厂商必须想办法来在满足~
    在PC浏览器中,视口只有一个,并且 视口的宽度 = 浏览器窗口的宽度,但是在移动端也要根据这个来设计的话,那么PC端设计的网站在移动端看起来会很丑,因为PC端的网页宽度在800 ~ 1024个CSS像素,而手机屏幕要窄的多,这个时候再PC端25%的宽度在移动端看起来会很窄。所以,布局视口的概念产生了。

    布局是口:移动端CSS布局的依据视口,即CSS布局会根据布局视口来计算。
    也就是说,在移动端,视口和浏览器窗口将不在关联,实际上,布局视口要比浏览器窗口大的多(在手机和平板中浏览器布局视口的宽度在768~1024像素之间),如下图(布局视口和窗口的关系):

    布局是口和浏览器窗口的关系

    可以通过以下JavaScript代码获取布局视口的宽度和高度:

    document.documentElement.clientWidth
    document.documentElement.clientHeight
    

    第二个视口:视觉视口

    视觉视口可能要更好理解一些,他就是用户正在看到网站的区域,如下图:

    视觉视口

    第三个视口:理想视口

    理想视口,这是我们最需要关注的视口,现在我们来回顾一下我们知道了哪些视口,有两个,分别是:布局视口,视觉视口。
    我们前面提到过,布局视口的宽度一般在 680~1024像素之间,这样可以使得PC网站在手机中不被压扁,但是这并不理想,因为手机更适合窄的网站,换句话说,布局视口并不是最理想的宽度,所以,就引入了理想视口。

    理想视口,定义了理想视口的宽度,比如对于iphone5来讲,理想视口是320*568。但是最终作用的还是布局视口,因为我们的css是依据布局视口计算的,所以你可以这样理解理想视口:理想的布局视口。下面这段代码可以告诉手机浏览器要把布局视口设为理想视口:

    <meta name="viewport" content="width=device-width" />
    

    上面那段代码告诉浏览器:将布局视口的宽度设为理想视口。所以,上面代码中的width指的是布局视口的宽 device-width 实际上就是理想视口的宽度。

    好了,移动端的三个视口介绍完了,让我们总结一下:

    1、在PC端,布局视口就是浏览器窗口
    2、在移动端,视口被分为两个:布局视口、视觉视口。
    3、移动端还有一个理想视口,它是布局视口的理想尺寸,即理想的布局视口。(注:理想视口的尺寸因设备和浏览器的不同而不同,但这对于我们来说无所谓)
    4、可以将布局视口的宽度设为理想视口

    三、设备像素比(DPR)

    下面你还需要了解一个概念,设备像素比(Device Pixel Ratio 简称:DPR)。
    下面是设备像素比的计算公式

    公式成立的大前提:(缩放比例为1)
    设备像素比(DPR) = 设备像素个数 / 理想视口CSS像素个数(device-width)

    与理想视口一样,设备像素比对于不同的设备是不同的,但是他们都是合理的,比如早起iphone的设备像素是320px,理想视口也是320px,所以早起iphone的DPR=1,而后来iphone的设备像素为640px,理想视口还是320px,所以后来iphone的DPR=2。在开发中,打开浏览器的调试工具可以看到设备像素比,如下图:

    chrome浏览器调试工具

    如上图,我们可以获得以下信息:
    iPhone5的理想视口是:320*568 <==> device-width = 320,device-height = 568
    iPhone5的设备像素比:2
    根据公式:设备像素比(DPR) = 设备像素个数 / 理想视口CSS像素个数(device-width)
    可知iPhone5的设备像素为 640*1136

    缩放

    在讲设备像素比公式的时候讲到了:

    公式成立的大前提:(缩放比例为1)
    设备像素比(DPR) = 设备像素个数 / 理想视口CSS像素个数(device-width)

    那么缩放到底是什么呢?也许这个问题让你很疑惑,如果你自己阅读了前面的内容,你会注意到CSS像素的大小是可变得,而缩放从技术实现的角度来讲,就是放大或缩小CSS像素的过程,怎么样?明白了吧,当你用双指缩放页面的时候,实际上是在放大或缩小CSS像素,至于什么是CSS像素,晕,回去从头好好看~

    也学你会觉得缩放没什么,但是你了解这个概念至关重要,因为在《一篇真正教会你开发移动端页面的文章(二)》中,会用到这里的概念。即

    缩放:缩小放大的是 CSS像素。

    meta标签

    meta视口标签存在的主要目的是为了让布局视口和理想视口的宽度匹配,meta视口标签应该放在HTML文档的head标签内,语法如下:

    <meta name="viewport" content="name=value,name=value" />
    

    其中 content 属性是一个字符串值,字符串是由逗号“,”分隔的 名/值 对组成,共有5个:

    1、width:设置布局视口的宽
    2、init-scale:设置页面的初始缩放程度
    3、minimum-scale:设置了页面最小缩放程度
    4、maximum-scale:设置了页面最大缩放程度
    5、user-scalable:是否允许用户对页面进行缩放操作

    下面是一个常用的meta标签实例

    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    

    上面代码的意思是,让布局视口的宽度等于理想视口的宽度,页面的初始缩放比例以及最大缩放比例都为1,且不允许用户对页面进行缩放操作。

    媒体查询

    媒体查询是响应式设计的基础,他有以下三点作用:

    1、检测媒体的类型,比如 screen,tv等
    2、检测布局视口的特性,比如视口的宽高分辨率等
    3、特性相关查询,比如检测浏览器是否支持某某特性(这一点不讨论,因为它被目前浏览器支持的功能对于web开发来讲很无用)

    css中使用媒体查询的语法:

    @media 媒体类型 and (视口特性阀值){
        // 满足条件的css样式代码
    
    }
    

    下面是一段在css中使用媒体查询的示例:

    @media all and (min-width: 321px) and (max-width: 400px){
        .box{
            background: red;
        }
    }
    

    上面代码中,媒体类型为all,代表任何设备,并且设备的布局视口宽度大于等于321px且小于等于400px时,让拥有box类的元素背景变红。
    这里只是简单介绍了css3的媒体查询,但是用于本系列文章(我也呵呵了,其实就两篇文章这是第一篇,第二篇会尽快更新)已经足够用了,感兴趣或者希望获得更多css3 媒体查询知识的同学可以在网上查阅相关资料。

    经过6个小时的奋战,好吧,终于整理好了 《一篇真正教会你开发移动端页面的文章》系列文章的第一篇,这篇文章主要是为第二篇文章要将到的内容打基础,同学们如果不了解可以多阅读即便,如果有问题欢迎评论,我会及时回复的,另外,下一篇文章将会带来干货,真真正正的让大家掌握移动端页面的开发。如果你已经阅读到了这里,我对你表示感谢,你的坚持一定会得到回报,共勉

    展开全文
  • 今天给大家介绍10款有关HTML5移动开发APP开发框架,这几款框架都是比较优秀的移动 Web 开发框架,能够帮助开发者更加高效的开发移动Web应用。. 十款移动APP开发框架: 1.jquery mobile框架 2.bootstrap框架 3.ionic...

    今天给大家介绍10款有关HTML5移动开发APP开发框架,这几款框架都是比较优秀的移动 Web 开发框架,能够帮助开发者更加高效的开发移动Web应用。.

      十款移动APP开发框架:

    1.jquery mobile框架

    2.bootstrap框架

    3.ionic框架

    4.Mobile Angular UI框架

    5.Intel XDK框架

    6.Appcelerator Titanium框架

    7.Sencha Touch框架

    8.Kendo UI框架

    9.PhoneGap框架

    10.mui框架

      1.jquery mobile框架

    用于HTML5移动开发的10大移动APP开发框架

      jQuery Mobile是jQuery 在手机上和平板设备上的版本。jQuery Mobile 不仅会给主流移动平台带来jQuery核心库,而且会发布一个完整统一的jQuery移动UI框架。支持全球主流的移动平台。

      2.bootstrap框架

    用于HTML5移动开发的10大移动APP开发框架

      Bootstrap 是基于 HTML、CSS、JAVASCRIPT 的,它简洁灵活,使得 Web 开发更加快捷。它由Twitter的设计师Mark Otto和Jacob Thornton合作开发,是一个CSS/HTML框架。Bootstrap提供了优雅的HTML和CSS规范,它即是由动态CSS语言Less写成。Bootstrap一经推出后颇受欢迎,一直是GitHub上的热门开源项目,包括NASA的MSNBC(微软全国广播公司)的Breaking News都使用了该项目。 国内一些移动开发者较为熟悉的框架,如WeX5前端开源框架等,也是基于Bootstrap源码进行性能优化而来。

      3.ionic框架

    用于HTML5移动开发的10大移动APP开发框架

      Ionic 是一个强大的 HTML5 应用程序开发框架,可以帮助您使用 Web 技术,比如 HTML、CSS 和 Javascript 构建接近原生体验的移动应用程序。Ionic 主要关注外观和体验,以及和你的应用程序的 UI 交互,特别适合用于基于 Hybird 模式的 HTML5 移动应用程序开发。

      4.Mobile Angular UI框架

    用于HTML5移动开发的10大移动APP开发框架

      Mobile Angular UI是使用 bootstrap 3 和 AngularJS 的响应式移动开发HTML5框架。

      Mobile Angular UI的关键字有:

      1. Bootstrap 3

      2. AngularJS

      Bootstrap 3 Mobile组件,比如switches, overlays和sidebars,这些都是bootstrap中没有的。

      AngularJS modules, 比如 angular-route, angular-touch 和 angular-animate

      响应式媒体查询是将bootstrap作为单独的文件,你只需要包含你所需要的东西。Mobile Angular UIu并不包含任何jQuery依赖,你需要做的只是通过一些AngularJS指令创建友好的用户体验。

      5.Intel XDK框架

    用于HTML5移动开发的10大移动APP开发框架

      Intel发布了其首个版本基于web的编程工具,可帮助开发者为Android和iOS开发移动应用。这款免费的软件名为Intel XDK,实际上这是今年2月份Intel收购的AppMobi软件的重新包装后的版本,所以并非新鲜事物。开发者可用此软件开发基于HTML5的应用,并 用于移动设备中。

      6.Appcelerator Titanium框架

    用于HTML5移动开发的10大移动APP开发框架

      Titanium 是一个跟手机平台无关的开发框架,用来开发具有本地应用效果的Web应用。当前主要支持 iPhone 和 Android 手机。

      主要提供的API包括:

      2D/3D animations

      Geo-location, compass, and maps

      Augmented reality features

      Social app authentication and native client support for email

      SOAP or REST API calls

      Audio, video, and image capture and playback

      Taps into local filesystem and SQL lite databases

      Accesses photo gallery or address data

      7.Sencha Touch框架

    用于HTML5移动开发的10大移动APP开发框架

      Sencha Touch框架是世界上第一个基于HTML5的Mobile App框架。Sencha Touch可以让你的Web App看起来像Native App。美丽的用户界面组件和丰富的数据管理,全部基于最新的HTML5和CSS3的 WEB标准,全面兼容Android和Apple iOS设备。提供了丰富的 WEB UI 组件,可以快速的开发出运行于移动终端的应用程序。

      8.Kendo UI框架

    用于HTML5移动开发的10大移动APP开发框架

      Kendo UI的每个方面都从底层开始构建,以提供强大的JavaScript应用程序性能。Kendo UI不是另一个jQuery UI的克隆,它的每一个决定都是从优化性能出发。从轻量级的、执行明显快于jQurey模板的内置模板库,到利用CSS3硬件加速的(如果可能)优化动画 和先进的虚拟化用户界面,Kendo UI不遗余力地提供高性能的客户端UI。

      9.PhoneGap框架

    用于HTML5移动开发的10大移动APP开发框架

      说到跨平台开发工具,很多人首先会想到PhoneGap。这样一款能够让开发者使用HTML、JS、CSS来开发跨平台移动App的开源免费框架,一直以来都深受开发者喜爱,从iOS、Android、BB10、Windows Phone到Amazon Fire OS、Tizen等,各大主流移动平台一应俱全,还能让开发者充分利用地理位置、加速器、联系人、声音等手机核心功能。

      业界很多主流的移动开发框架均源于PhoneGap。较著名的有Worklight、appMobi、WeX5等。其中WeX5为国内打造,完全Apache开源,在融合Phonegap的基础上,做了深度优化,具备接近Native app的性能,同时开发便捷性也较好。

      10.mui框架

    用于HTML5移动开发的10大移动APP开发框架

      最接近原生APP体验的高性能前端框架,具有以下特点:

      轻量

      追求性能体验,是我们开始启动MUI项目的首要目标,轻量必然是重要特征;

      MUI不依赖任何第三方JS库,压缩后的JS和CSS文件仅有100+K和60+K

      原生UI

      鉴于之前的很多前端框架(特别是响应式布局的框架),UI控件看起来太像网页,没有原生感觉,因此追求原生UI感觉也是我们的重要目标

      MUI以iOS平台UI为基础,补充部分Android平台特有的UI控件

      流畅体验

      •  下拉刷新

      为实现下拉刷新功能,大多H5框架都是通过DIV模拟下拉回弹动画,在低端android手机上,DIV动画经常出现卡顿现象(特别是图文列表的情况); mui通过双webview解决这个DIV的拖动流畅度问题;拖动时,拖动的不是div,而是一个完整的webview(子webview),回弹动画使用原生动画。

      •  侧滑导航

      mui提供了两种侧滑导航实现:webview模式和div模式,两种模式各有优劣,适用于不同的场景。每种侧滑实现模式,有不同的侧滑动画效果,主要分为四类:

      动画1:主界面移动、菜单不动

      动画2:主界面不动、菜单移动

      动画3:主界面和菜单同时移动

      动画4:缩放式侧滑(类手机QQ)

      •  滑动触发操作菜单

      在手机应用中(特别是iOS平台),很多操作菜单都是滑动触发的,比如短信界面,左滑显示“删除”按钮,点击可以删除该短信对话;邮件列表界面,左滑可以删除,右滑可以标注为”已读/未读”状态; mui的列表控件也支持滑动触发操作菜单功能,仅需按照特定格式拼装DOM结构即可;另外,滑动还支持事件触发,开发者可以通过监听滑动事件(slideleft/slideright),完成操作前的确认提醒工作。

    展开全文
  • 一,首先确定布局和基本权限二,当开始在主Activity中开始写代码的时候,首先找所需的控件,然后思考本Activity需不需要开启子线程.三,书写子线程代码示例工程activity_main.xml&lt;?xml version="...

    一,首先确定布局和基本权限

    二,当开始在主Activity中开始写代码的时候,首先找所需的控件,然后思考本Activity需不需要开启子线程.

    三,书写子线程代码






    示例工程


    activity_main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout 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"
        tools:context="com.example.mi.MainActivity">
    
        <com.handmark.pulltorefresh.library.PullToRefreshListView
            android:id="@+id/plv"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            />
    
    </LinearLayout>
    

    items.xml

    <?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">
    
        <ImageView
            android:id="@+id/img"
            android:layout_width="100dp"
            android:layout_height="100dp" />
    
        <TextView
            android:id="@+id/txt"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />
    
    </LinearLayout>

    MainActivity.java

    package com.example.mi;
    
    import android.os.Handler;
    import android.os.Message;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.widget.ListView;
    import android.widget.Toast;
    
    import com.example.mi.bean.DateBean;
    import com.example.mi.utils.JsonDao;
    import com.example.mi.utils.NetStateUtil;
    import com.google.gson.Gson;
    import com.handmark.pulltorefresh.library.LoadingLayoutProxy;
    import com.handmark.pulltorefresh.library.PullToRefreshBase;
    import com.handmark.pulltorefresh.library.PullToRefreshListView;
    
    import java.io.BufferedReader;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.net.HttpURLConnection;
    import java.net.URL;
    import java.util.ArrayList;
    import java.util.List;
    
    public class MainActivity extends AppCompatActivity {
    
        private PullToRefreshListView plv;
        private int oderType = 1;
        private int pageIndex = 1;
        private List <DateBean.NewslistBean> dataAll=new ArrayList <>();
        private MyAdapter adapter;
        private String url="https://api.tianapi.com/wxnew/?key=48a7d7193e11bd2dd4a683b6e2f90a4f&num=10&page="+pageIndex;
        private JsonDao jsonDao = new JsonDao(this);
        private Handler handler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                List <DateBean.NewslistBean> list = (List <DateBean.NewslistBean>)msg.obj;
                showData(list);
            }
        };
    
        private void showData(List <DateBean.NewslistBean> list) {
            if (oderType==1)
            {
                dataAll.clear();
            }
            dataAll.addAll(list);
            setPlvAdapter();
            plv.onRefreshComplete();
        }
    
        private void setPlvAdapter() {
            if (adapter==null)
            {
                adapter=new MyAdapter(MainActivity.this,dataAll);
                plv.setAdapter(adapter);
            }else {
                adapter.notifyDataSetChanged();
            }
        }
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            plv = findViewById(R.id.plv);
    
            initPlv();
    
            requestNetData();
    
        }
    
        private void requestNetData() {
            //判断网络是否连接
            if (NetStateUtil.isConn(this)){
                openThread();
            }else {
                NetStateUtil.showNoNetWorkDlg(this);
                //吐司提示
                Toast.makeText(this,"现在没有网络,请稍后重试!",Toast.LENGTH_SHORT).show();
                //展示本地数据
                String s = jsonDao.select(url);
                Gson gson = new Gson();
                showData(gson.fromJson(s,DateBean.class).getNewslist());
    
            }
        }
    
        public void openThread(){
            new Thread(){
                @Override
                public void run() {
                    try {
                        URL url1=new URL(url);
                        HttpURLConnection urlConnection = (HttpURLConnection)url1.openConnection();
                        urlConnection.setReadTimeout(5000);
                        urlConnection.setConnectTimeout(5000);
                        urlConnection.setRequestMethod("GET");
                        if (urlConnection.getResponseCode()==200)
                        {
                            InputStream inputStream = urlConnection.getInputStream();
                            String s = streamToString(inputStream);
                            jsonDao.insertData(url,s);
                            Gson gson = new Gson();
                            DateBean dateBean = gson.fromJson(s, DateBean.class);
                            List <DateBean.NewslistBean> newslist = dateBean.getNewslist();
                            Message mes = Message.obtain();
                            mes.obj=newslist;
                            handler.sendMessage(mes);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }.start();
        }
    
        private String streamToString(InputStream inputStream) {
            StringBuilder stringBuilder = new StringBuilder();
            String str;
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            try {
                while ((str=bufferedReader.readLine())!=null)
                {
                    stringBuilder.append(str);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return  stringBuilder.toString();
        }
    
        private void initPlv() {
            plv.setMode(PullToRefreshBase.Mode.BOTH);
            //设置下拉提示文字
            LoadingLayoutProxy layoutProxy = (LoadingLayoutProxy) plv.getLoadingLayoutProxy(true, false);
            //下拉的时候显示的文本
            layoutProxy.setPullLabel("继续拉,对,继续,拉,拉,拉");
            //放开刷新的时候显示的文本
            layoutProxy.setReleaseLabel("松开你就会发现一件神奇的事情");
            //执行刷新的时候显示的文本
            layoutProxy.setRefreshingLabel("哈哈哈哈哈,神奇不?");
    
            //设置上拉提示文字
            LoadingLayoutProxy layoutProxy1 = (LoadingLayoutProxy) plv.getLoadingLayoutProxy(false, true);
            //上拉的时候显示的文本
            layoutProxy1.setPullLabel("继续上拉,加载更多~");
            //放开刷新的时候显示的文本
            layoutProxy1.setReleaseLabel("松开加载");
            //执行刷新的时候显示的文本
            layoutProxy1.setRefreshingLabel("正在加载...");
    
    
            plv.setOnRefreshListener(new PullToRefreshBase.OnRefreshListener2 <ListView>() {
                @Override
                public void onPullDownToRefresh(PullToRefreshBase <ListView> pullToRefreshBase) {
                    oderType=1;
                    pageIndex=1;
                    url="https://api.tianapi.com/wxnew/?key=48a7d7193e11bd2dd4a683b6e2f90a4f&num=10&page="+pageIndex;
                    requestNetData();
                }
    
                @Override
                public void onPullUpToRefresh(PullToRefreshBase <ListView> pullToRefreshBase) {
                    oderType=2;
                    pageIndex++;
                    url="https://api.tianapi.com/wxnew/?key=48a7d7193e11bd2dd4a683b6e2f90a4f&num=10&page="+pageIndex;
                    requestNetData();
                }
            });
        }
    
        
    }
    

    package com.example.mi;
    
    import android.os.Handler;
    import android.os.Message;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.widget.Adapter;
    import android.widget.ListView;
    import android.widget.Toast;
    
    import com.example.mi.bean.DateBean;
    import com.example.mi.utils.JsonDao;
    import com.example.mi.utils.NetStateUtil;
    import com.google.gson.Gson;
    import com.handmark.pulltorefresh.library.PullToRefreshBase;
    import com.handmark.pulltorefresh.library.PullToRefreshListView;
    
    import java.io.BufferedReader;
    import java.io.InputStream;
    import java.io.InputStreamReader;
    import java.net.HttpURLConnection;
    import java.net.URL;
    import java.util.ArrayList;
    import java.util.List;
    
    public class MainActivity extends AppCompatActivity {
    
        private PullToRefreshListView plv;
        private int oderType = 1;
        private int pageIndex = 1;
        private List <DateBean.NewslistBean> dataAll=new ArrayList <>();
        private MyAdapter adapter;
        private String url="https://api.tianapi.com/wxnew/?key=48a7d7193e11bd2dd4a683b6e2f90a4f&num=10&page="+pageIndex;
        private JsonDao jsonDao = new JsonDao(this);
        private Handler handler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                List <DateBean.NewslistBean> list = (List <DateBean.NewslistBean>)msg.obj;
                showData(list);
            }
        };
    
        private void showData(List <DateBean.NewslistBean> list) {
            if (oderType==1)
            {
                dataAll.clear();
            }
            dataAll.addAll(list);
            setPlvAdapter();
            plv.onRefreshComplete();
        }
    
        private void setPlvAdapter() {
            if (adapter==null)
            {
                adapter=new MyAdapter(MainActivity.this,dataAll);
                plv.setAdapter(adapter);
            }else {
                adapter.notifyDataSetChanged();
            }
        }
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
    
            plv = findViewById(R.id.plv);
    
            initPlv();
    
            requestNetData();
    
        }
    
        private void requestNetData() {
            //判断网络是否连接
            if (NetStateUtil.isConn(this)){
                openThread();
            }else {
                NetStateUtil.showNoNetWorkDlg(this);
                //吐司提示
                Toast.makeText(this,"现在没有网络,请稍后重试!",Toast.LENGTH_SHORT).show();
                //展示本地数据
                String s = jsonDao.select(url);
                Gson gson = new Gson();
                showData(gson.fromJson(s,DateBean.class).getNewslist());
    
            }
        }
    
        public void openThread(){
            new Thread(){
                @Override
                public void run() {
                    try {
                        URL url1=new URL(url);
                        HttpURLConnection urlConnection = (HttpURLConnection)url1.openConnection();
                        urlConnection.setReadTimeout(5000);
                        urlConnection.setConnectTimeout(5000);
                        urlConnection.setRequestMethod("GET");
                        if (urlConnection.getResponseCode()==200)
                        {
                            InputStream inputStream = urlConnection.getInputStream();
                            String s = streamToString(inputStream);
                            jsonDao.insertData(url,s);
                            Gson gson = new Gson();
                            DateBean dateBean = gson.fromJson(s, DateBean.class);
                            List <DateBean.NewslistBean> newslist = dateBean.getNewslist();
                            Message mes = Message.obtain();
                            mes.obj=newslist;
                            handler.sendMessage(mes);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }.start();
        }
    
        private String streamToString(InputStream inputStream) {
            StringBuilder stringBuilder = new StringBuilder();
            String str;
            BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
            try {
                while ((str=bufferedReader.readLine())!=null)
                {
                    stringBuilder.append(str);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
            return  stringBuilder.toString();
        }
    
        private void initPlv() {
            plv.setMode(PullToRefreshBase.Mode.BOTH);
            plv.setOnRefreshListener(new PullToRefreshBase.OnRefreshListener2 <ListView>() {
                @Override
                public void onPullDownToRefresh(PullToRefreshBase <ListView> pullToRefreshBase) {
                    oderType=1;
                    pageIndex=1;
                    url="https://api.tianapi.com/wxnew/?key=48a7d7193e11bd2dd4a683b6e2f90a4f&num=10&page="+pageIndex;
                    requestNetData();
                }
    
                @Override
                public void onPullUpToRefresh(PullToRefreshBase <ListView> pullToRefreshBase) {
                    oderType=2;
                    pageIndex++;
                    url="https://api.tianapi.com/wxnew/?key=48a7d7193e11bd2dd4a683b6e2f90a4f&num=10&page="+pageIndex;
                    requestNetData();
                }
            });
        }
    
        
    }
    

    MyAdapter.java

    package com.example.mi;
    
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.BaseAdapter;
    import android.widget.ImageView;
    import android.widget.TextView;
    
    import com.example.mi.bean.DateBean;
    import com.nostra13.universalimageloader.core.DisplayImageOptions;
    import com.nostra13.universalimageloader.core.ImageLoader;
    import com.nostra13.universalimageloader.core.assist.ImageScaleType;
    
    import java.util.List;
    
    /**
     * Created by Administrator on 2018/3/31.
     */
    
    public class MyAdapter extends BaseAdapter {
    
        private Context context;
        private List<DateBean.NewslistBean> list;
        private DisplayImageOptions options;
    
        public MyAdapter(Context context, List <DateBean.NewslistBean> list) {
            this.context = context;
            this.list = list;
            options=new DisplayImageOptions.Builder()
                    .cacheInMemory(true)//使用内存缓存
                    .cacheOnDisk(true)//使用磁盘缓存
                    .showImageOnLoading(R.mipmap.ic_launcher_round)//设置正在下载的图片
                    .showImageForEmptyUri(R.mipmap.ic_launcher_round)//url为空或请求的资源不存在时
                    .showImageOnFail(R.mipmap.ic_launcher_round)//下载失败时显示的图片
                    .bitmapConfig(Bitmap.Config.RGB_565)//设置图片色彩模式
                    .imageScaleType(ImageScaleType.EXACTLY)//设置图片的缩放模式
                    .build();
        }
    
        @Override
        public int getCount() {
            return list.size();
        }
    
        @Override
        public Object getItem(int i) {
            return list.get(i);
        }
    
        @Override
        public long getItemId(int i) {
            return i;
        }
    
        @Override
        public View getView(int i, View view, ViewGroup viewGroup) {
    
            ViewHolder viewHolder;
            if (view==null)
            {
                view=View.inflate(context,R.layout.items,null);
                viewHolder=new ViewHolder();
                viewHolder.img = view.findViewById(R.id.img);
                viewHolder.txt = view.findViewById(R.id.txt);
                view.setTag(viewHolder);
            }else {
                viewHolder=(ViewHolder)view.getTag();
            }
    
            ImageLoader.getInstance().displayImage(list.get(i).getPicUrl(),viewHolder.img,options);
            viewHolder.txt.setText(list.get(i).getTitle());
    
            return view;
        }
    
        class ViewHolder{
            ImageView img;
            TextView txt;
        }
    }
    

    package com.example.mi;
    
    import android.content.Context;
    import android.graphics.Bitmap;
    import android.view.View;
    import android.view.ViewGroup;
    import android.widget.BaseAdapter;
    import android.widget.ImageView;
    import android.widget.TextView;
    
    import com.example.mi.bean.DateBean;
    import com.nostra13.universalimageloader.core.DisplayImageOptions;
    import com.nostra13.universalimageloader.core.ImageLoader;
    import com.nostra13.universalimageloader.core.assist.ImageScaleType;
    
    import java.util.List;
    
    /**
     * Created by Administrator on 2018/3/31.
     */
    
    public class MyAdapter extends BaseAdapter {
    
        private Context context;
        private List<DateBean.NewslistBean> list;
        private DisplayImageOptions options;
    
        public MyAdapter(Context context, List <DateBean.NewslistBean> list) {
            this.context = context;
            this.list = list;
            options=new DisplayImageOptions.Builder()
                    .cacheInMemory(true)//使用内存缓存
                    .cacheOnDisk(true)//使用磁盘缓存
                    .showImageOnLoading(R.mipmap.ic_launcher_round)//设置正在下载的图片
                    .showImageForEmptyUri(R.mipmap.ic_launcher_round)//url为空或请求的资源不存在时
                    .showImageOnFail(R.mipmap.ic_launcher_round)//下载失败时显示的图片
                    .bitmapConfig(Bitmap.Config.RGB_565)//设置图片色彩模式
                    .imageScaleType(ImageScaleType.EXACTLY)//设置图片的缩放模式
                    .build();
        }
    
        @Override
        public int getCount() {
            return list.size();
        }
    
        @Override
        public Object getItem(int i) {
            return list.get(i);
        }
    
        @Override
        public long getItemId(int i) {
            return i;
        }
    
        @Override
        public View getView(int i, View view, ViewGroup viewGroup) {
    
            ViewHolder viewHolder;
            if (view==null)
            {
                view=View.inflate(context,R.layout.items,null);
                viewHolder=new ViewHolder();
                viewHolder.img = view.findViewById(R.id.img);
                viewHolder.txt = view.findViewById(R.id.txt);
                view.setTag(viewHolder);
            }else {
                viewHolder=(ViewHolder)view.getTag();
            }
    
            ImageLoader.getInstance().displayImage(list.get(i).getPicUrl(),viewHolder.img,options);
            viewHolder.txt.setText(list.get(i).getTitle());
    
            return view;
        }
    
        class ViewHolder{
            ImageView img;
            TextView txt;
        }
    }
    

    MyApplication.java

    package com.example.mi;
    
    import android.app.Application;
    import android.os.Environment;
    
    import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiscCache;
    import com.nostra13.universalimageloader.cache.disc.naming.Md5FileNameGenerator;
    import com.nostra13.universalimageloader.core.ImageLoader;
    import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
    
    import java.io.File;
    
    /**
     * Created by Administrator on 2018/3/31.
     */
    
    public class MyApplication extends Application {
        @Override
        public void onCreate() {
            super.onCreate();
            //程序的入口 函数
    
            //自定义缓存路径  sd卡下的piccache文件夹下
            File cachefile=new File(Environment.getExternalStorageDirectory().getPath()+"/piccache");
            //File cachefile1=getExternalCacheDir();//获取系统默认的sd卡缓存路径
    
            ImageLoaderConfiguration configuration=new ImageLoaderConfiguration.Builder(this)
                    .memoryCacheExtraOptions(480, 800)//缓存图片最大的长和宽
                    .threadPoolSize(2)//线程池的数量
                    .threadPriority(4)
                    .memoryCacheSize(2*1024*1024)//设置内存缓存区大小
                    .diskCacheSize(20*1024*1024)//设置sd卡缓存区大小
                    .diskCache(new UnlimitedDiscCache(cachefile))//自定义缓存目录
                    .writeDebugLogs()//打印日志内容
                    .diskCacheFileNameGenerator(new Md5FileNameGenerator())//给缓存的文件名进行md5加密处理
                    .build();
    
            ImageLoader.getInstance().init(configuration);
    
    
        }
    }
    

    package com.example.mi;
    
    import android.app.Application;
    import android.os.Environment;
    
    import com.nostra13.universalimageloader.cache.disc.impl.UnlimitedDiscCache;
    import com.nostra13.universalimageloader.cache.disc.naming.Md5FileNameGenerator;
    import com.nostra13.universalimageloader.core.ImageLoader;
    import com.nostra13.universalimageloader.core.ImageLoaderConfiguration;
    
    import java.io.File;
    
    /**
     * Created by Administrator on 2018/3/31.
     */
    
    public class MyApplication extends Application {
        @Override
        public void onCreate() {
            super.onCreate();
            //程序的入口 函数
    
            //自定义缓存路径  sd卡下的piccache文件夹下
            File cachefile=new File(Environment.getExternalStorageDirectory().getPath()+"/piccache");
            //File cachefile1=getExternalCacheDir();//获取系统默认的sd卡缓存路径
    
            ImageLoaderConfiguration configuration=new ImageLoaderConfiguration.Builder(this)
                    .memoryCacheExtraOptions(480, 800)//缓存图片最大的长和宽
                    .threadPoolSize(2)//线程池的数量
                    .threadPriority(4)
                    .memoryCacheSize(2*1024*1024)//设置内存缓存区大小
                    .diskCacheSize(20*1024*1024)//设置sd卡缓存区大小
                    .diskCache(new UnlimitedDiscCache(cachefile))//自定义缓存目录
                    .writeDebugLogs()//打印日志内容
                    .diskCacheFileNameGenerator(new Md5FileNameGenerator())//给缓存的文件名进行md5加密处理
                    .build();
    
            ImageLoader.getInstance().init(configuration);
    
    
        }
    }
    

    DataBean.java

    package com.example.mi.bean;
    
    import java.util.List;
    
    /**
     * Created by Administrator on 2018/3/31.
     */
    
    public class DateBean {
    
        /**
         * code : 200
         * msg : success
         * newslist : [{"ctime":"2018-03-30","title":"关于红楼梦的N个念头","description":"三联生活周刊","picUrl":"https://zxpic.gtimg.com/infonew/0/wechat_pics_-62900671.jpg/640","url":"https://mp.weixin.qq.com/s?__biz=MTc5MTU3NTYyMQ==&idx=2&mid=2650651785&sn=75526e17b4b480ea510f65ec3793bf54"},{"ctime":"2018-03-30","title":"广州有座\u201c猪宾馆\u201d,里面的猪会\u201c尬舞\u201d?这是世界首例!","description":"广州日报","picUrl":"https://zxpic.gtimg.com/infonew/0/wechat_pics_-45262906.static/640","url":"https://mp.weixin.qq.com/s?__biz=MjM5MjA0MDk2MA==&idx=2&mid=2652421905&sn=0ae22141145b30c848ecf0a0ac612153"},{"ctime":"2018-03-30","title":"\u201c你不就是个服务员吗?凭什么不让我换头等舱?\u201d","description":"暴走大事件","picUrl":"https://zxpic.gtimg.com/infonew/0/wechat_pics_-62900613.jpg/640","url":"https://mp.weixin.qq.com/s?__biz=MzI4ODA1MDA2MQ==&idx=1&mid=2652647217&sn=efaa395be06b18c55b3e48a03c4a8677"},{"ctime":"2018-03-30","title":"左眼跳财,右眼跳灾?女子左眼皮连跳8年,终于出事了...","description":"FM93交通之声","picUrl":"https://zxpic.gtimg.com/infonew/0/wechat_pics_-62900601.jpg/640","url":"https://mp.weixin.qq.com/s?__biz=MTIzNDg3NzY2MA==&idx=3&mid=2653040765&sn=cafb01cf0ebcbd673ee4c4637764f0f2"},{"ctime":"2018-03-30","title":"千万别着急!又一大波重磅新车将上市,买早了吃亏!","description":"有车以后","picUrl":"https://zxpic.gtimg.com/infonew/0/wechat_pics_-62900573.jpg/640","url":"https://mp.weixin.qq.com/s?__biz=MzAxMTA0ODE3Mw==&idx=1&mid=2656904565&sn=5a75df7049ca08181ecaf18476e1f370"},{"ctime":"2018-03-30","title":"2.0T+9AT的大7座SUV,卖多少钱能让你放弃汉兰达/奥迪Q5?","description":"车买买","picUrl":"https://zxpic.gtimg.com/infonew/0/wechat_pics_-62898269.static/640","url":"https://mp.weixin.qq.com/s?__biz=MzA5NTU1MjEwNA==&idx=4&mid=2668673664&sn=197feccde9aad5f1c47772235c541e3e"},{"ctime":"2018-03-30","title":"黑人的头发养活了中国的一座城,这里藏着一段屈辱的民族史","description":"微在Wezeit","picUrl":"https://zxpic.gtimg.com/infonew/0/wechat_pics_-62900480.jpg/640","url":"https://mp.weixin.qq.com/s?__biz=MzA5MjMzNTQyNw==&idx=1&mid=2656030884&sn=9a79b276f2c66c9b2694427d19ee5c72"},{"ctime":"2018-03-30","title":"朋友养了一只猛犬,网友本来是不相信的,直到靠近狗窝后.....","description":"大爱萌狗控","picUrl":"https://zxpic.gtimg.com/infonew/0/wechat_pics_-62900520.jpg/640","url":"https://mp.weixin.qq.com/s?__biz=MjM5NjQ0MDE1OQ==&idx=2&mid=2650063440&sn=42593507b8b2f992795fb8ed6c675a5a"},{"ctime":"2018-03-30","title":"中国最美的20个旅行目的地,走过10个以上,就算超级旅行达人。","description":"带着相机去旅行","picUrl":"https://zxpic.gtimg.com/infonew/0/wechat_pics_-62900363.jpg/640","url":"https://mp.weixin.qq.com/s?__biz=MzAxNjI1MzUwOA==&idx=3&mid=2247521649&sn=9c9c6d637348d975baa2c4352039f286"},{"ctime":"2018-03-30","title":"【入流】网红食物打造指南","description":"腾讯时尚","picUrl":"https://zxpic.gtimg.com/infonew/0/wechat_pics_-61887411.static/640","url":"https://mp.weixin.qq.com/s?__biz=MjM5MTIxOTEyMA==&idx=2&mid=2650591720&sn=e7e246e4bdf3c2659fd26f36b88697fa"}]
         */
    
        private int code;
        private String msg;
        private List <NewslistBean> newslist;
    
        public int getCode() {
            return code;
        }
    
        public void setCode(int code) {
            this.code = code;
        }
    
        public String getMsg() {
            return msg;
        }
    
        public void setMsg(String msg) {
            this.msg = msg;
        }
    
        public List <NewslistBean> getNewslist() {
            return newslist;
        }
    
        public void setNewslist(List <NewslistBean> newslist) {
            this.newslist = newslist;
        }
    
        public static class NewslistBean {
            /**
             * ctime : 2018-03-30
             * title : 关于红楼梦的N个念头
             * description : 三联生活周刊
             * picUrl : https://zxpic.gtimg.com/infonew/0/wechat_pics_-62900671.jpg/640
             * url : https://mp.weixin.qq.com/s?__biz=MTc5MTU3NTYyMQ==&idx=2&mid=2650651785&sn=75526e17b4b480ea510f65ec3793bf54
             */
    
            private String ctime;
            private String title;
            private String description;
            private String picUrl;
            private String url;
    
            public String getCtime() {
                return ctime;
            }
    
            public void setCtime(String ctime) {
                this.ctime = ctime;
            }
    
            public String getTitle() {
                return title;
            }
    
            public void setTitle(String title) {
                this.title = title;
            }
    
            public String getDescription() {
                return description;
            }
    
            public void setDescription(String description) {
                this.description = description;
            }
    
            public String getPicUrl() {
                return picUrl;
            }
    
            public void setPicUrl(String picUrl) {
                this.picUrl = picUrl;
            }
    
            public String getUrl() {
                return url;
            }
    
            public void setUrl(String url) {
                this.url = url;
            }
        }
    }
    

    package com.example.mi.bean;
    
    import java.util.List;
    
    /**
     * Created by Administrator on 2018/3/31.
     */
    
    public class DateBean {
    
        /**
         * code : 200
         * msg : success
         * newslist : [{"ctime":"2018-03-30","title":"关于红楼梦的N个念头","description":"三联生活周刊","picUrl":"https://zxpic.gtimg.com/infonew/0/wechat_pics_-62900671.jpg/640","url":"https://mp.weixin.qq.com/s?__biz=MTc5MTU3NTYyMQ==&idx=2&mid=2650651785&sn=75526e17b4b480ea510f65ec3793bf54"},{"ctime":"2018-03-30","title":"广州有座\u201c猪宾馆\u201d,里面的猪会\u201c尬舞\u201d?这是世界首例!","description":"广州日报","picUrl":"https://zxpic.gtimg.com/infonew/0/wechat_pics_-45262906.static/640","url":"https://mp.weixin.qq.com/s?__biz=MjM5MjA0MDk2MA==&idx=2&mid=2652421905&sn=0ae22141145b30c848ecf0a0ac612153"},{"ctime":"2018-03-30","title":"\u201c你不就是个服务员吗?凭什么不让我换头等舱?\u201d","description":"暴走大事件","picUrl":"https://zxpic.gtimg.com/infonew/0/wechat_pics_-62900613.jpg/640","url":"https://mp.weixin.qq.com/s?__biz=MzI4ODA1MDA2MQ==&idx=1&mid=2652647217&sn=efaa395be06b18c55b3e48a03c4a8677"},{"ctime":"2018-03-30","title":"左眼跳财,右眼跳灾?女子左眼皮连跳8年,终于出事了...","description":"FM93交通之声","picUrl":"https://zxpic.gtimg.com/infonew/0/wechat_pics_-62900601.jpg/640","url":"https://mp.weixin.qq.com/s?__biz=MTIzNDg3NzY2MA==&idx=3&mid=2653040765&sn=cafb01cf0ebcbd673ee4c4637764f0f2"},{"ctime":"2018-03-30","title":"千万别着急!又一大波重磅新车将上市,买早了吃亏!","description":"有车以后","picUrl":"https://zxpic.gtimg.com/infonew/0/wechat_pics_-62900573.jpg/640","url":"https://mp.weixin.qq.com/s?__biz=MzAxMTA0ODE3Mw==&idx=1&mid=2656904565&sn=5a75df7049ca08181ecaf18476e1f370"},{"ctime":"2018-03-30","title":"2.0T+9AT的大7座SUV,卖多少钱能让你放弃汉兰达/奥迪Q5?","description":"车买买","picUrl":"https://zxpic.gtimg.com/infonew/0/wechat_pics_-62898269.static/640","url":"https://mp.weixin.qq.com/s?__biz=MzA5NTU1MjEwNA==&idx=4&mid=2668673664&sn=197feccde9aad5f1c47772235c541e3e"},{"ctime":"2018-03-30","title":"黑人的头发养活了中国的一座城,这里藏着一段屈辱的民族史","description":"微在Wezeit","picUrl":"https://zxpic.gtimg.com/infonew/0/wechat_pics_-62900480.jpg/640","url":"https://mp.weixin.qq.com/s?__biz=MzA5MjMzNTQyNw==&idx=1&mid=2656030884&sn=9a79b276f2c66c9b2694427d19ee5c72"},{"ctime":"2018-03-30","title":"朋友养了一只猛犬,网友本来是不相信的,直到靠近狗窝后.....","description":"大爱萌狗控","picUrl":"https://zxpic.gtimg.com/infonew/0/wechat_pics_-62900520.jpg/640","url":"https://mp.weixin.qq.com/s?__biz=MjM5NjQ0MDE1OQ==&idx=2&mid=2650063440&sn=42593507b8b2f992795fb8ed6c675a5a"},{"ctime":"2018-03-30","title":"中国最美的20个旅行目的地,走过10个以上,就算超级旅行达人。","description":"带着相机去旅行","picUrl":"https://zxpic.gtimg.com/infonew/0/wechat_pics_-62900363.jpg/640","url":"https://mp.weixin.qq.com/s?__biz=MzAxNjI1MzUwOA==&idx=3&mid=2247521649&sn=9c9c6d637348d975baa2c4352039f286"},{"ctime":"2018-03-30","title":"【入流】网红食物打造指南","description":"腾讯时尚","picUrl":"https://zxpic.gtimg.com/infonew/0/wechat_pics_-61887411.static/640","url":"https://mp.weixin.qq.com/s?__biz=MjM5MTIxOTEyMA==&idx=2&mid=2650591720&sn=e7e246e4bdf3c2659fd26f36b88697fa"}]
         */
    
        private int code;
        private String msg;
        private List <NewslistBean> newslist;
    
        public int getCode() {
            return code;
        }
    
        public void setCode(int code) {
            this.code = code;
        }
    
        public String getMsg() {
            return msg;
        }
    
        public void setMsg(String msg) {
            this.msg = msg;
        }
    
        public List <NewslistBean> getNewslist() {
            return newslist;
        }
    
        public void setNewslist(List <NewslistBean> newslist) {
            this.newslist = newslist;
        }
    
        public static class NewslistBean {
            /**
             * ctime : 2018-03-30
             * title : 关于红楼梦的N个念头
             * description : 三联生活周刊
             * picUrl : https://zxpic.gtimg.com/infonew/0/wechat_pics_-62900671.jpg/640
             * url : https://mp.weixin.qq.com/s?__biz=MTc5MTU3NTYyMQ==&idx=2&mid=2650651785&sn=75526e17b4b480ea510f65ec3793bf54
             */
    
            private String ctime;
            private String title;
            private String description;
            private String picUrl;
            private String url;
    
            public String getCtime() {
                return ctime;
            }
    
            public void setCtime(String ctime) {
                this.ctime = ctime;
            }
    
            public String getTitle() {
                return title;
            }
    
            public void setTitle(String title) {
                this.title = title;
            }
    
            public String getDescription() {
                return description;
            }
    
            public void setDescription(String description) {
                this.description = description;
            }
    
            public String getPicUrl() {
                return picUrl;
            }
    
            public void setPicUrl(String picUrl) {
                this.picUrl = picUrl;
            }
    
            public String getUrl() {
                return url;
            }
    
            public void setUrl(String url) {
                this.url = url;
            }
        }
    }

    MyDatabaseHelper.java

    package com.example.mi.dateBase;
    
    import android.content.Context;
    import android.database.sqlite.SQLiteDatabase;
    import android.database.sqlite.SQLiteOpenHelper;
    
    /**
     * Created by Administrator on 2018/4/1.
     */
    
    public class MyDatebaseHelper extends SQLiteOpenHelper {
    
        //构造方法,用于确定数据库的名称,版本号等
        public MyDatebaseHelper(Context context) {
            super(context, "mydb",null,1);
        }
    
        //创建数据库时调用一次,初始化表中数据
        @Override
        public void onCreate(SQLiteDatabase sqLiteDatabase) {
            sqLiteDatabase.execSQL("create table users(id integer primary key autoincrement,urlPath text,jsonData text)");
        }
    
        //数据库版本更新时回调
        @Override
        public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
    
        }
    }
    

    package com.example.mi.dateBase;
    
    import android.content.Context;
    import android.database.sqlite.SQLiteDatabase;
    import android.database.sqlite.SQLiteOpenHelper;
    
    /**
     * Created by Administrator on 2018/4/1.
     */
    
    public class MyDatebaseHelper extends SQLiteOpenHelper {
    
        //构造方法,用于确定数据库的名称,版本号等
        public MyDatebaseHelper(Context context) {
            super(context, "mydb",null,1);
        }
    
        //创建数据库时调用一次,初始化表中数据
        @Override
        public void onCreate(SQLiteDatabase sqLiteDatabase) {
            sqLiteDatabase.execSQL("create table users(id integer primary key autoincrement,urlPath text,jsonData text)");
        }
    
        //数据库版本更新时回调
        @Override
        public void onUpgrade(SQLiteDatabase sqLiteDatabase, int i, int i1) {
    
        }
    }
    

    JsonDao.java

    package com.example.mi.utils;
    
    import android.content.ContentValues;
    import android.content.Context;
    import android.database.Cursor;
    import android.database.sqlite.SQLiteDatabase;
    
    import com.example.mi.dateBase.MyDatebaseHelper;
    
    /**
     * Created by Administrator on 2018/4/2.
     */
    
    public class JsonDao {
    
        private final MyDatebaseHelper myDatebaseHelper;
    
        //构造方法,便于别类中调用
        public JsonDao(Context context){
            myDatebaseHelper = new MyDatebaseHelper(context);
        }
    
        //插入方法
        public void insertData(String urlpath,String jsondata){
            //1.得到数据库的可写权限
            SQLiteDatabase writableDatabase =myDatebaseHelper.getWritableDatabase();
            //2.先清空表数据
            writableDatabase.delete("users","urlPath=?",new String[]{urlpath});
    
            //3.新建数据对象,作为插入语句参数
            ContentValues contentValues = new ContentValues();
            //4.将要插入的数据存到对象中
            contentValues.put("urlPath",urlpath);
            contentValues.put("jsonData",jsondata);
    
            //5.插入数据,
            long users = writableDatabase.insert("users", null, contentValues);
        }
    
        public String select(String urlpath){
            //1.得到数据库的可写权限
            SQLiteDatabase writableDatabase =myDatebaseHelper.getWritableDatabase();
            //2.按条件查询
            Cursor userss = writableDatabase.query("users", null, "urlPath=?", new String[]{urlpath}, null, null, null);
            //4.创建一个字符串变量,用来储存结果
            String data="";
            //3.获得数据结果
            while (userss.moveToNext()){
                data=userss.getString(userss.getColumnIndex("jsonData"));
            }
            //返回结果
            return data;
        }
    
    }
    

    package com.example.mi.utils;
    
    import android.content.ContentValues;
    import android.content.Context;
    import android.database.Cursor;
    import android.database.sqlite.SQLiteDatabase;
    
    import com.example.mi.dateBase.MyDatebaseHelper;
    
    /**
     * Created by Administrator on 2018/4/2.
     */
    
    public class JsonDao {
    
        private final MyDatebaseHelper myDatebaseHelper;
    
        //构造方法,便于别类中调用
        public JsonDao(Context context){
            myDatebaseHelper = new MyDatebaseHelper(context);
        }
    
        //插入方法
        public void insertData(String urlpath,String jsondata){
            //1.得到数据库的可写权限
            SQLiteDatabase writableDatabase =myDatebaseHelper.getWritableDatabase();
            //2.先清空表数据
            writableDatabase.delete("users","urlPath=?",new String[]{urlpath});
    
            //3.新建数据对象,作为插入语句参数
            ContentValues contentValues = new ContentValues();
            //4.将要插入的数据存到对象中
            contentValues.put("urlPath",urlpath);
            contentValues.put("jsonData",jsondata);
    
            //5.插入数据,
            long users = writableDatabase.insert("users", null, contentValues);
        }
    
        public String select(String urlpath){
            //1.得到数据库的可写权限
            SQLiteDatabase writableDatabase =myDatebaseHelper.getWritableDatabase();
            //2.按条件查询
            Cursor userss = writableDatabase.query("users", null, "urlPath=?", new String[]{urlpath}, null, null, null);
            //4.创建一个字符串变量,用来储存结果
            String data="";
            //3.获得数据结果
            while (userss.moveToNext()){
                data=userss.getString(userss.getColumnIndex("jsonData"));
            }
            //返回结果
            return data;
        }
    
    }

    NetStateUtil.java

    package com.example.mi.utils;
    
    import android.app.AlertDialog;
    import android.content.Context;
    import android.content.DialogInterface;
    import android.content.Intent;
    import android.net.ConnectivityManager;
    import android.net.NetworkInfo;
    
    import com.example.mi.R;
    
    /**
     * Created by Administrator on 2018/4/2.
     */
    
    public class NetStateUtil {
    
        //判断网络是否打开
        public static boolean isConn(Context context){
            //1.设置网络状态变量,默认false(false:关闭,true:打开)
            boolean isConnFlag=false;
            //2.获得系统权限
            ConnectivityManager conManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
            //3.获得网络管理权限
            NetworkInfo network = conManager.getActiveNetworkInfo();
            //4.判断是否获得权限
            if(network!=null){
                //5.获得网络连接状态
                isConnFlag=network.isAvailable();
            }
            //返回链接状态结果
            return isConnFlag;
        }
    
        //当没有网络时选择是否打开网络设置
        public static void showNoNetWorkDlg(final Context context){
            //1.创建弹出式对话框对象
            AlertDialog.Builder builder = new AlertDialog.Builder(context);
            builder.setIcon(R.mipmap.ic_launcher)//设置提示图片
                    .setTitle(R.string.app_name)//设置提示标题(通常是应用名)
                    .setMessage("当前没有网络连接!")//设置提示信息
                    .setPositiveButton("设置", new DialogInterface.OnClickListener() {//设置确定按钮样式
                        @Override
                        public void onClick(DialogInterface dialogInterface, int i) {
                            // 跳转到系统的网络设置界面
                            Intent intent = null;
                            // 先判断当前系统版本
                            if(android.os.Build.VERSION.SDK_INT > 10){  // 3.0以上
                                intent = new Intent(android.provider.Settings.ACTION_WIRELESS_SETTINGS);
                            }else{
                                intent = new Intent();
                                intent.setClassName("com.android.settings", "com.android.settings.WirelessSettings");
                            }
                            //开启设置页面
                            context.startActivity(intent);
                        }
                    })
                    .setNegativeButton("知道了", null)//设置取消按钮样式
                    .show();
        }
    }
    package com.example.mi.utils;
    
    import android.app.AlertDialog;
    import android.content.Context;
    import android.content.DialogInterface;
    import android.content.Intent;
    import android.net.ConnectivityManager;
    import android.net.NetworkInfo;
    
    import com.example.mi.R;
    
    /**
     * Created by Administrator on 2018/4/2.
     */
    
    public class NetStateUtil {
    
        //判断网络是否打开
        public static boolean isConn(Context context){
            //1.设置网络状态变量,默认false(false:关闭,true:打开)
            boolean isConnFlag=false;
            //2.获得系统权限
            ConnectivityManager conManager = (ConnectivityManager)context.getSystemService(Context.CONNECTIVITY_SERVICE);
            //3.获得网络管理权限
            NetworkInfo network = conManager.getActiveNetworkInfo();
            //4.判断是否获得权限
            if(network!=null){
                //5.获得网络连接状态
                isConnFlag=network.isAvailable();
            }
            //返回链接状态结果
            return isConnFlag;
        }
    
        //当没有网络时选择是否打开网络设置
        public static void showNoNetWorkDlg(final Context context){
            //1.创建弹出式对话框对象
            AlertDialog.Builder builder = new AlertDialog.Builder(context);
            builder.setIcon(R.mipmap.ic_launcher)//设置提示图片
                    .setTitle(R.string.app_name)//设置提示标题(通常是应用名)
                    .setMessage("当前没有网络连接!")//设置提示信息
                    .setPositiveButton("设置", new DialogInterface.OnClickListener() {//设置确定按钮样式
                        @Override
                        public void onClick(DialogInterface dialogInterface, int i) {
                            // 跳转到系统的网络设置界面
                            Intent intent = null;
                            // 先判断当前系统版本
                            if(android.os.Build.VERSION.SDK_INT > 10){  // 3.0以上
                                intent = new Intent(android.provider.Settings.ACTION_WIRELESS_SETTINGS);
                            }else{
                                intent = new Intent();
                                intent.setClassName("com.android.settings", "com.android.settings.WirelessSettings");
                            }
                            //开启设置页面
                            context.startActivity(intent);
                        }
                    })
                    .setNegativeButton("知道了", null)//设置取消按钮样式
                    .show();
        }
    }
    

    AndroidManifest.xml

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.mi">
    
        <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
        <uses-permission android:name="android.permission.INTERNET"/>
        <application
            android:allowBackup="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/AppTheme"
            android:name=".MyApplication">
            <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>

    展开全文
  • 作者 | 曹立成本文经授权转自InterestDriven(ID:hello123android) 2019年人工智能系统学: ...从2017年下半年开始,就开始听到各种言论,例如 “Android 开发凉凉”、“移动端开发没出路了赶紧转行”、“要被...
  • 目前来说主流的App开发方式有三种:Native App 、Web App、Hybird App。下面我们来分析一下这三种App开发方式的优劣对比: 一 :Native App 即 原生App开发 优点: (1)打造完美的用户体验 (2)性能稳定 (3)操作...
  • 十大移动开发平台

    2018-12-28 19:51:35
    基于浏览器的集成开发环境,可视化和智能化的设计,能轻松完成常规应用和面向手机的移动应用开发;高效、稳定和可扩展的特点,适合复杂企业级应用的运行;跨平台、数据库和浏览器的架构,适应复杂的服务器和客户端...
  • 正在开发app的同志们注意了说到APP开发,大家会想到以IOS、Android的纯原生开发;而在这个app横飞的年代,对于整个产品研发团队或个人来讲,高速的迭代,爆炸式的功能追加已经成为互联网行业的时代标签,常常以小时...
  • 一、移动端开发分为以下几个方向: 1、native app开发(原生app开发)-所有在应用商店中下载安装的程序都是原生app(都是安卓和ios开发的) --安卓(Java-Native); --IOS(Object-C/swift); 优势:直接安装...
  • 选择合适的技术栈是移动开发领域最关键的决策之一。你选择的技术栈将为你开发的移动应用提供基本的功能、可拓展和维护性。选择技术栈时应该注意项目的类型、预期投入市场的时间和创意的可行性。 原则上来说,选择何...
  • 很难说,因为Java、object-C在原生开发界已大行其道这么多年,C#这么多年固步自封,很难说在移动开发领域能重新有所建树。   目前国内有一个基于VB/C#的APP开发平台,叫Smobiler,它主打的就是.Net移动开发,使用...
  • 什么是移动开发

    2014-04-16 10:29:35
    移动开发[1]也称为手机开发,或叫做移动互联网开发[2]。是指以手机、PDA、UMPC等便携终端为基础,进行相应的开发工作,由于这些随身设备基本都采用无线上网的方式,因此,业内也称作为无线开发。 移动应用开发是为...
  • CSDN博客第一期移动开发排行榜圆满结束,恭喜所有上榜用户,为继续展示移动开发方向优秀博主,发掘潜力新星,为想了解移动开发方向的博客用户提供平台,CSDN博客第二期移动开发排行榜开始。我们将邀请CSDN博客频道...
  • 网页开发要面对各种各样的浏览器,让人很头疼,而移动开发中,你不但要面对浏览器,还要面对各种版本的手机,ios好一点,而安卓就五花八门了,你可能在开发中也被它们折磨过,或者正在被它们折磨,我在这里说几个我...
  • Asp.net 移动开发

    2015-06-23 17:09:10
    Asp.net能进行移动开发移动开发是手机运用,而asp.net是网页开发,能合在一起吗?答案是能的,随着科技的发展,现在asp.net也能进行移动开发移动开发也称为手机开发,或叫做移动互联网开发。是指以手机、PDA...
  • 今天给大家介绍10款有关HTML5移动开发APP开发框架,这几款框架都是比较优秀的移动 Web 开发框架,能够帮助开发者更加高效的开发移动Web应用。.  十款移动APP开发框架: 1.jquery mobile框架 2.bootstrap框架 3....
  • 一、2019新版前端与移动开发学习路线图---每阶段可掌握的能力及各阶段覆盖的关键字 二、2019新版前端与移动开发学习路线图---学习大纲及各阶段知识点 三、2019新版前端与移动开发学习路线图--升级后新增...
  • 为充分展示移动开发方向优秀博主,发掘潜力新星,为想更多了解移动开发方向的博客用户提供平台,CSDN博客频道推出“移动开发排行榜”活动,每月一期。我们将邀请CSDN博客频道活跃的资深专家参与评选。同时,获奖者有...
1 2 3 4 5 ... 20
收藏数 746,454
精华内容 298,581
热门标签
关键字:

移动开发