- 浏览: 99627 次
- 性别:
- 来自: 上海
文章分类
- 全部博客 (50)
- druid (1)
- java (7)
- database (1)
- 源码 (6)
- dubbo (4)
- jetty (1)
- protocol (1)
- 工作流 (3)
- 电商 (1)
- 支付平台 (1)
- 大数据 (0)
- 微信小程序 (1)
- 短信平台 (1)
- jms (1)
- jndi (1)
- spi (1)
- FileUpload (0)
- concurrent (1)
- 统计业务 (0)
- 业务 (3)
- sql (2)
- andriod (1)
- maven (1)
- OAuth (1)
- ws (1)
- spring (6)
- mybatis (1)
- java rocketmq (0)
- rocketmq (1)
- RxJava (1)
- java模式 (1)
- AI (0)
- 机器学习 (1)
- springboot (1)
- tomcat (1)
- 协议 (1)
- springcloud (1)
- stream (1)
- 技术管理 (1)
- k8s (1)
- ser (0)
- istio (1)
- ddd (1)
- 微服务 (1)
- 操作笔记 (1)
最新评论
-
herman_liu76:
luozhen89 写道讲得很好。知识后面的KAFKA跟OAu ...
尽量把OAuth2.0的原理讲透透的 -
luozhen89:
讲得很好。知识后面的KAFKA跟OAuth有什么关系,没看懂。 ...
尽量把OAuth2.0的原理讲透透的 -
herman_liu76:
ZHENFENGSHISAN 写道太累了啊,哥唉~ 我也觉得很 ...
代码快看哭了-吐槽与感悟汇总 -
ZHENFENGSHISAN:
太累了啊,哥
代码快看哭了-吐槽与感悟汇总 -
herman_liu76:
1126481146 写道厉害啊,有联系方式吗,学习学习,我现 ...
druid 源码分析与学习(含详细监控设计思路的彩蛋)
最近终于实战了...后面有记录经历
做java的web项目很久了,虽然看了几篇入门的文章,却从没有真正研究过安卓的开发。可能以后会有手机端开发,毕竟手机应用火。碰巧有机会找来一个应用宝中的一个项目的源码,从0开发研究。一方面看看自己迅速总体掌握陌生安卓项目的能力,另一方面也是储备,掌控未来手机端开发进度。还有一方面,估计不会做app,工作有明确范围,但知识应该跨越边境,整体考虑,才能做到更好。
大家看网上的资料有没有这样的感觉,一般的文章看再多都难以形成一个完整的安卓开发概念。多是简单入门,或者专注于某一要点,而我需要的是一个真正的完整项目,通过研究有一个整体的把握。
这个项目包含一般复杂的页面功能,还有微信登录,分享,支付等功能,相当完备,直接从0到实用工程级项目。防止泄密,以文字和简单图片为主,才学习了几个业余晚上时间,许多说法可能不对,欢迎指正。
一、基础入门
开发工具,打包测试我都不管了,重点是理解结构、代码与整体设计。我就用eclipse导入工程,以看代码为主。首先是配合BAIDU的简单知识,了解项目的文件层次与主要文件的作用。
1.AndroidManifest.xml 总的软件配置文件,各种权限说明,还有很多activity(这就当是主活动页面吧)。
2.res文件夹比较重要,名字叫资源,主要有layout是各种布局文件,各种常量值,还有图片啥的。有些文件夹名字-后缀,是不同屏幕用的。layout比较重要,是界面布局,做过其它窗口程序开发的就知道,窗口会有几个文件,有的文件就只是布局。
3.src是核心java源代码。有ui相关的,app相关的,activity相关的,fragment相关的,widge相关的。上面提到一些布局XML文件,会与这里的有些界面处理类相关联着。比如activity类就会加载自己对应的布局文件。
这里就会想到,之前用过vb什么的,dephi什么的语言进行可视化编程,也会产生代码文件与界面文件。
4.查了点app主线程资料,一般的语言都是事件发生后,产生消息来驱动的。比如在手机上点击按钮,主线程就会处理这个动作。这里的UI线程就是APP的主线程,主线程是循环处理消息,但可以阻塞,并被唤醒,具体的消息驱动会在后面介绍。主线程一般不会用多线程处理消息,比如js就是单线程处理,node.js也是,nio也是单线程,非阻塞的IO的方式。后面再仔细品味,会发现这几乎是相似的模式:单线程处理所有的事情,如果有耗时的事情,等于是拆分两件事了。
二、主activity界面内容
先简单说一下这个应用,启动APP后,先出现一个启动画面,之后如果已经登录了就进入主界面,没有登录进入登录界面。先选择主界面开始,具体分析。
主页面下面是一些模块按钮,点不同的按钮出现不同的界面,下面是不动的。比如第1个按钮看到的是【文章列表】,后面有一个搜索的小图标。
下面是一个左右可以滑动的热门文章,显示图片与标题。
再下面是一个列表的文章,按时间一行行显示出来,每一行有文章图片,标题,主要内容,发布时间等。
三、主activity界面设计
既然说界面,界面是一种res,所以下面说的都在res的layout中,是xml文件。主activity里有三大模块内容,有点类似微信下面的四块内容。上面部分用的是FrameLayout,下面是LinearLayout,LinearLayout里面又是三块LinearLayout,每块里面才是文字与图片。下面比较简单,上面那么复杂的东西只放了一个FrameLayout,看来是要嵌入其它东西了。
里面确实是放三个fragment,而且重点工作都是在fragment中,那么先介绍一下fragment的界面,如图三。上面一块是文字与图片,下面是一个AbPullToRefreshView,里面嵌入一个ListView。最下面还有二块,分别是等待与出错块。从名字可能看到,PullToRefresh是下拉会刷新的东东,list当然是列表了。
刚才介绍主体内容上面是轮播,下面是列表,没看到轮播块?事实上轮播是动态放入的,后面再说,还是先把界面有啥介绍完。轮播又是一个xml,里面只有一个InfiniteViewPager。就当成轮播的框架吧,架子里才是真正的内容,又是一个xml。这个xml才是最终内容,有SimpleDraweeView和一个文本View。说完了轮播,还有列表。列表里的内容也是一个xml,里面有SimpleDraweeView,还有好几个文本View,比如标题什么的。
界面看来是一层层嵌套的关系。主Actity界面(1),其中一个fragment界面(2),里面又会动态加一个轮播界面(3)与列表内容界面(4),轮播里又是一个轮播内容界面(5)。一共5个xml文件。与上图示意图的后五个图对应。这里想想这界面真是蛮麻烦的事情。
界面心得:都是一种layout(布局)里面放置其它控件或者子layout,如果有子layout,那里面还有控件。为何不把上面这么多放在一个大的布局文件中?我也不知道,只是后面看代码发现是动态加载,这样算组件复用吧。比如轮播里的内容个数,列表中的个数都是不定的。主界面中的fragment的个数也可以说是多个的,所以不定的,多个切换的内容要分开一个界面文件。
四,从主界面相关代码开始分析
1.主界面activity的类,应该是这个类会加载主界面。
这个类的变量有这么几类:
2.主界面类的方法
onCreate():先是加载界面文件,res文件夹中的layout文件夹中的特定界面文件。还包括下面几个子方法。
initData();初始化一些数据,可以从远程去获取
initView();new出上面定义的属性,这里特别指fragment类,new会产生什么要看后面fragment里了。
initListener();监听一些用户操作,这里是指下面三大块的按钮,里面的界面上的操作由里面负责的。主要是三大块fragment的切换。
这个类回头看了再细说。
3.重要是fragment这具类代码
主界面有三个fragment界面切换,主界面类有三个fragment类,可以说是动态加载进去的。很多操作在这个里面。
与主界面activity类相似,先说说它的属性,包括界面上的控件,直接绑定了ID,就是实例了。还有界面上的个别layout布局实例,也是直接绑定ID,一般只有显示,隐藏这样的操作。还有一个动态view类,就是轮播view。还有放数据的两个ArrayList。还有些其它的回头说。
说明:一个界面类上明确的控件,直接用ID绑定了,不定个数的控件会new出来,同时加载界面文件,产生实例。
而方法中首先是onCreateView()方法。同样先是加载自己的界面,inflater.inflate(),同样是res/layout/***.xml。
之后还是initData();初始化一些数据和对象。
initView();初始化一些参数,比如给可下拉对象设置属性,以及设置监听操作。再是重点动态加载界面了。属性里只有一个动态view对象,用getLayoutInflater().inflate()加载动态对象的界面,前面加载的是自己的。
需要监听用户操作的控件在这个初始化View过程中设置,比如设置setOnClickListener。
这个动态加载的界面对象里有一个控件,里面会放一堆不定个数的轮播画面。而自己本身还有一个非动态加载的listview控件,里面也会放一堆不定个数的列表画面。处理方面是控件里放个适配器。发现listView可以直接放适配器,可是动态的界面对象里的控件对象才能放适配器,并不是界面对象本身放适配器。说明:从界面文件加载的layout/view不能放适配器,必须是一个控件对象,想想也蛮合理的。把轮播layout/view动态加载给listView。
整理一下总的结构:fragment对象里有一个列表对象,还会动态加载一个外部界面对象,动态加一个适配器,而外部界面对象里的一个控件,也动态加了一个适配器。貌似与通常的想法不一样,这个象是控件里加了一个布局。控件里怎么可以加布局呢?通常界面XML中是布局包含控件与布局。控件是叶子结点,布局是中间结点。当然控件里放适配器这一点没有问题。先不管细节了,就当特殊时候可以这么用吧。
4.再看一下适配器里是什么东东
这里的适配器是fragment类中的一个内部类。里面有一个重要的getView()方法,想想也对,控件里面具体的个数不确定,或者要切换,当然要适配一下了,产生里面的view。getView的参数有具体数据,所以通过一个ViewHolder把数据与不定个数界面的控件关联起来。同时赋予这个界面响应点击事件,跳转到其它界面activity。
5.界面都好了,最后是加载数据。
startGetDataTask();//这个是执行加载数据的任务。
这个方法包括:new 一个异步任务AsyncTask,并执行它,后面会详细介绍几个异步线程操作。
AsyncTask对象固定有一些方法要重载的,都是生命周期不同时候触发的。主要是执行前的清理与准备onPreExecute。执行中doInBackground,去请求后台数据。执行后onPostExecute,把返回的数据置入界面类的ArrayList对象中,再由适配器执行Adapter.notifyDataSetChanged();表示告诉适配器我的数据发生了变化。
适配器是什么?包括了数据,也有getView方法从界面XML中加载界面的功能,通过holder把数据与界面中的控件关联起来。所以设计这个东西,是能感知数据变化,产生变化的,不定个数的界面的。这个就理解通了。
五、回顾一下前面学习的内容
1.界面上都是layout与控件,但不定个数的界面都分成一个个子界面,都是独立XML文件
2.界面类属性有自己的控件并绑定实例化,还有动态要生成的界面类init的加载。
3.界面类init的时候,加载自已的界面文件,而其中的动态界面实例化时,实例化同时加载子界面文件。同时对这个动态子界面中的控件设置响应用户操作的动作。
4.界面类的有的控件类可以包含界面类中的子界面类。
5.界面类的有的控件类可以包含不定个数的界面,或者切换的界面时,这时候要到适配器。
6.适配器把数据与不定个数的子子界面对象关联起来。可以生成一个个子子界面,可以响应数据的变化而自己变化。
7.一个异步任务可以与后台服务器交互,拿出来数据后,让适配器变化。如果需要简单的操作Ui,AsyncTask固定实现的一些方法非常清晰好用。
8.控件或者view可以设置来响应用户的操作,比如点击什么的。
理解下来,这些都还蛮顺的。除了那个List控件加载了一个layout对象,与界面xml中控件都是叶子结点的思路有点冲突之外。有的控件当然也是容器控件。
补充:界面文件中AbPullToRefreshView可刷新控件里包含了listView控件,listView要动态加载一个界面XML文件当头部。为什么listView里不直接在界面xml文件里放置另一界面文件中的InfiniteViewPager控件呢?现在是用addHeaderView加进来的。也许listView就这么设计的,一些控件之间就是固定的套路。但为什么不在AbPullToRefreshView可刷新控件中直接包含InfiniteViewPager与listView呢?不知道会是什么效果。
六、微信相关的登录、分享。
1.登录的界面(含微信登录)设计
一般来说,登录界面与注册界面都在一个activity中,而且是可以切换的。按照上面的理解。activity的界面xml中应该有一个容器ViewPager,而登录与注册又是动态加载进去的。必然有一个适配器Adaptor来处理登录与注册对象,并且赋给ViewPager对象。
在登录的xml界面中,有一个ImageView用于微信登录。
activity的类中,主要是onCreate中加载自己的界面文件。另外有初始化数据与对象,初始化界面与操作两类。初始化界面与操作是重点介绍的。里面主要是动态加载注册与登录两个切换的部分以及适配器的配置。
2.登录注册中的适配器Adaptor
Adaptor中最主要的是instantiateItem()方法,切换操作时返回选择的view,这个过程中对动态加载的登录view或者注册view进行选择,并从动态界面中获取控件,再配置控件响应用户的各种操作。
对于登录view中的操作,除了校验外,产生一个new Thread()来处理登录提交,正常登录后进入最上面提到的主页activity。上面讲过一个异步任务,这里不操作ui,是普通线程。登录后以后,再用LoginActivity.this.runOnUiThread(Runnable)来更新主线程,主线程登录成功跳转,或者显示出错信息。这个机制好象是把耗时的动作让另一个线程做,好了以后还可以通知ui主线程做事。
3.微信登录
对于微信那个imageView,可以加上setOnClickListener操作内容。里面的重点是用com.umeng.socialize.UMShareAPI对象的实例,做doOauthVerify与getPlatformInfo操作。从名字看一个是用户验证,一个是获取微信平台的信息。我们知道微信等于是一个外部的对象了,这里是用友盟的接口来做。从经验来说,两个对象要想发生关系,其中一个把自己注册给对方,并实现一个通知接口回调。从方法:doOauthVerify(LoginActivity.this, SHARE_MEDIA.WEIXIN, umListener);可以看到,传入了自己,并传入了一个监听器进去,监听器最主要的是onComplete方法,里面得到本机微信的数据后,再用loginWechat(id, name, image);来正式登录微信后台。
现在loginWechat登录的过程与标准登录差不多了,只不过请求的不是自己的后台了。过程为:另外启动一个线程来登录微信后台,根据登录成功的结果,再利用Activity.runOnUiThread(Runnable)来更新ui主线程。在主线程中给用户显示出登录成功,并跳转到主activity。
简单理一下:点击微信时,主界面把一个监听器给友盟接口,友盟拿到手机上微信的信息后会回调监听中的方法,这个方法用这些信息,另启一个线程登录微信后台。标准登录是用用户名密码登录自己的后台。这里借助外部力量,一般都要回调,另启一个线程不是太明白,更新ui主线程不知道是什么机制呢?(后面知道,只能主线程更新UI界面,方式有几个)友盟的作用就是拿到手机上友商的信息吧!
4.微信分享
一般我们点分享时,会出现半个窗口,里面有分享到微信好友,朋友圈之类的,这是通过fragment来实现的。fragment上面说到,是一个粗粒度的界面组件。接近activity,大于view。
首先说说fragment对应的界面,就是res/layout里的一个界面xml,里面就是几个图标,比如有微信好友。
用户主activity中点击分享时,在onClick中就要动态生成这个fragment组件。重点就是要看组件的类代码,其中onCreateView就是加载界面xml,这个都一样。不过加载里面的控件就放在onViewCreated里了,因为分享肯定是接收分享内容的参数了,onViewCreated是可以有参数的。这个过程中要给里面的具体分享图片view设置响应点击操作了。在点击时,会组装好分享内容的参数,用友盟的ShareAction来做了。我们前面登录分析了,就知道用友盟与外部打交道,要传入自己(父级activity)和一个监听器。监听器根据外部分享的情况,指挥自己内部如何处理,比如Toast.makeText显示分享成功或者失败之类的。
发现在分享QQZone时,要ActivityCompat.requestPermissions,就是动态请求权限。还要根据用户选择允许或者不允许时的onRequestPermissionsResult,才确定如何响应用户的判断。
七、微信支付
1.这里采用handler消息机制来做
handler消息机制,大概了解了一下,就是把消息体与处理方法包在一起放进一个队列里,有一个loop()过程进行死循环,拿出这个包装体,用包装体中的方法来处理消息体。主要是消息处理不影响主线程,主ui线程天生自带looper和队列。
开始有一点没看懂,那个loop()不是单独开一个线程来处理吗?这样主线程才顺畅啊。事实上loop()是主线程中循环,有一个唤醒机制。比如我点击一个按钮后,过程中会用handle产生一个新消息(或者从消息池中拿一个空的消息),给消息设置好相关数据后。这时主UI线程唤醒looper(),拿出消息,并用这个消息关联的handle处理这个消息。
前面登录用了普通线程,里面用到LoginActivity.this.runOnUiThread来让主线程显示跳转。适配器用了异步任务,要重写一些方法,算是调用UI线程中的onPostExecute()执行后续UI操作。这里又是一种消息机制。
2.从点击确认支付开始
假如支付确定的imgview上有onClick方法,那这个方法的主要步骤有:
八、UI线程与消息handler机制
既然做了那么多J2EE开发,是时候比较一下此刻我眼中的android开发了。手上工作比较多,周末正好参加马拉松参加,时间紧比较仓促,看的比较粗。
android开发也是要画界面,写每一个控件的操作,貌似与一些其它开发是相通的。UI线程是单线程,是用来响应用户操作的,真正耗费时候的都要用其它线程来做,而且UI不是线程安全的,所以其它线程不要操作UI上的控件,所有的ui操作都通过handler来发消息操作。JS也是单线程,node.js也是,我们知道tcp用的nio也是一个线程分发的,所以有很多相似的地方。
主UI线程应该是一个不断循环处理的线程,处理各种消息。把界面上各种操作都放在一个消息池中,主UI一个个来处理。主UI我查了一下,虽然是循环处理,但没消息时是阻塞状态,也不是空转,但有一个唤醒机制,是pipe/epoll,这个机制恰好我在看基于nio的netty通讯框架时有查过这方面的资料,是IO相关的FD来唤醒的。
了解大致原理,有助于我们用新的知识或者功能时不犯原则性的错误。
先想到了handle机制处理异步操作,为何主ui中默认就有looper呢?也许就是上面的道理吧。你自己弄的线程需要消息循环处理时,就要自己写looper.prepare之类的代码了。主UI当然必须有。handle的生成一定要是looper线程中,而handle的发送消息一定要在另一个线程中。
主线程UI中的各个控件,也是设置了好多处理方案,之后扔在屏幕上让控件接受外面的使用而产生消息。主UI根据这些消息就按设置好的处理方案来处理事件。所以handle机制是个原始机制,上面在微信支付时就是这个方式,但原码中还支付其它的方式,产生的msg是不同的,是否抽象msg方案与具体支付方式的不同,是不用其它异步方式的原因?
我用一种通俗的方式理解一下这个机制。家长与孩子有一个协定,如果是好事,孩子可以吃糖,如果是坏事就罚站,这是主线程。家长把孩子送出家门,进另一个线程。在外面可能被发奖状消息,孩子回来后,家长时刻检查这些消息,如果是好事孩子就会吃糖。
九、其它异步机制
当你点击控件,产生一个动作的时候,你可以产生另一个线程做事,根据做事中的结果,你就可以执行Activity.runOnUIThread(Runnable),在参数的Runable中操作控件。
如果特定让哪个控件变化,就用View.Post(Runnable)。
AsyncTask看不到具体的线程,AsyncTask类主要有三个操作:
doInBackground()后台做的操作;onProgressUpdate()任务开始时的操作;onPostExecute()任务完成时的操作;
使用方法:
new PostTask().execute(status);传递参数到doInBackground(),在其中可以执行后台操作,比如获取服务器数据;doInBackground()的操作会返回数据,而这个数据又是onPostExecute()的参数,可以把参数置给activity中的数据变量,并让控件来用这个数据变量;
注意:doInBackground()是在其他线程运行的方法,不能调用UI;onPostExecute是在主UI运行的方法,可以更新界面。
其实四种方法都是基于handler方法的包装。在一般的情形下后面的似乎更值得推荐。但是当情形比较复杂,还是推荐使用handler。
十、其它一些小内容
介绍了那么多,只能是有些概念了,但如果具体要开发一个商用级,还需要很多知识。
0.数据库
一个应用通常少不了数据库,总不能都记录在后台吧。这里使用SQLite。
一般用SQLiteOpenHelper的子类管理数据库的生成与版本。
自己写一个DBManager,使用SQLiteOpenHelper来获取数据库,并用来管理业务。数据库的初始化,可以放在app的onCreate()里来做。后面讲的共享数据与业务初始数据也是各自有管理类,也在这个方法里。这个好理解,app初始化应该把应用级的事情都做好,准备好。
分析类比一下:一般j2ee习惯是用一个数据库服务器,应用有应用服务器,分为管理数据库与使用数据库两个方面。
这里相似:helper首先是用来管理数据库文件的,可以新建一个db,以及初始化db表,版本变化时也重置数据库。另外一方面就是给应用获取数据库实例,或者叫连接吧。
另外注意的是:Cursor。一般在业务封装中打开与关闭,但查资料也可以在activity里,让activity来管理cursor的生命同期。个人觉得,一般不用放在activity里。
还有就是数据库里放什么?这方面从我使用其它APP感觉一下。APP可以清除数据,这时登录后从服务器上再获取,最新的数据离线时可以本地查看。比如我收藏的股票,可以本地读,本地没有从服务器上读。我一天的运动数据,可以从本地读,但汇总数据从服务器上读。
1.全局变量
平台的配置,建议放在全局Application或者程序入口。
PlatformConfig.setWeixin(appid,secret)这些用友盟的三方的配置都放在这里。这里还没太懂?整个机制不知是什么样的。
写一个baseActivity。activity中要使用远程请求,在baseActivity中产生一个请求对象,每个页面就都有了,具体在下面说。
baseActivitycom.johnson.commonlibs.common_utils.utils.HttpUtils也在baseActivity中,用isNetworkAvailable来得到网格情况。
2.用户账号与自动登录
3.远程请求
这个用Retrofit2框架,Retrofit 是安卓上最流行的HTTP Client库之一。写一个接口ApiService,把APP中所有的请求放进来。比如:
@GET("orderShow.do")
Call<JsonObject> orderShow(@Query("inputStr") String inputStr);
使用时,先产生接口的实例。
apiService = ServiceGenerator.generate(Application.getInstance()).setEndpoint(BaseApiUrl.class).getApiService(ApiService.class);
再使用实例的方法,方法就是接口中的了。
apiService.orderShow(inputStr).enqueue(new Callback<JsonObject>() {..}
上面的括号里就是一个回调方法,自己实现onResponse与onFailure两个方法。
思考:ServiceGenerator估计是代理工厂,产生一个实现接口的代理对象,动态代理吧?里面可能是真正的httpClient来处理请求。
4.验证码
5.可惜没有地图使用方面的代码
6.SharedPreferences
看到系统登录后保存了用户信息,发现是存在SharedPreferences中,也是差不多key-value的方式。查了下资料:
调用Context对象的getSharedPreferences()方法获得的SharedPreferences对象可以被同一应用程序下的其他组件共享.调用Activity对象的getPreferences()方法获得的SharedPreferences对象只能在该Activity中使用.
SharedPreferences是Android平台上一个轻量级的存储类,用来保存应用的一些常用配置,比如Activity状态,Activity暂停时,将此activity的状态保存到SharedPereferences中;当Activity重载,系统回调方法onSaveInstanceState时,再从SharedPreferences中将值取出。
SharedPreferences提供了java常规的Long、Int、String等类型数据的保存接口。 [1]
SharedPreferences类似过去Windows系统上的ini配置文件,但是它分为多种权限,可以全局共享访问。
提示最终是以xml方式来保存,整体效率来看不是特别的高,对于常规的轻量级而言比SQLite要好不少,如果真的存储量不大可以考虑自己定义文件格式。xml处理时Dalvik会通过自带底层的本地XML Parser解析,比如XMLpull方式,这样对于内存资源占用比较好。
SharedPreferences 可以用来进行数据的共享,包括应用程序之间,或者同一个应用程序中的不同组件。比如两个activity除了通过Intent传递数据之外,也可以通过SharedPreferences来共享数据。
从使用上说,一般用单例对象处理SharedPreferences。app应用当然与共享数据实例对象的生存周期一样,同时需要一个context当参数(context.getApplicationContext()比较保险)。在app的onCreate中产生这个单例对象,并把app自己当参数传进去,所谓同生共死。这里我们有个共享数据管理类。
7.初始化数据
app启动时,可能有一些初始化数据。比如一些行政区划数据,我们在j2ee中通常从后台获取,在app中看到是从res中读取jason的文件。这里我还不知道如果有变化怎么更新资源文件?难道是app升级吗?
我们让一个类中持有这些数据,怎么获取res中数据呢?new InputStreamReader( context.getResources().openRawResource(fileResId));用流的方式,这里有一个context,也是app的onCreate()的时候,把app自己传进来就行了。这里我们有一个初始数据管理类。
十一、深入理解一些机制
1.Activity与进程,线程的关系
4大组件组成:Activity,Service,ContentProvider,BroadcastReceiver。应用第一次启动时,会启动一个新进程。该进程会启动主线程ActivityThread,也叫做UI线程,UI的绘制都在该线程里完成。
个人理解:一个APP进程中只能有一个ui主线程。Activity的切换都不会另开线程,都是在一个线程里运行。我猜测一个app里的activity对主线程来说,也都是动态加载进来的。如同activity动态加载view之类的一样。主线程里应该有一个List<activity>这样的东东。前面说过UI线程中默认有消息处理looper,是处理任何activity里的界面响应,也处理自定义的handle的消息。消息交给activity本身的回调,再一层层回调activity里的东东。很有层次感。
2.不同app之间相互调用activity,以及与task的关系。
task是一个具有栈结构的容器,可以放置多个Activity实例。启动一个应用,系统就会为之创建一个task,来放置根Activity;默认情况下,一个Activity启动另一个Activity时,两个Activity是放置在同一个task中的,后者被压入前者所在的task栈,当用户按下后退键,后者从task被弹出,前者又显示在幕前,特别是启动其他应用中的Activity时,两个Activity对用户来说就好像是属于同一个应用;
个人理解:app相当于学校里的班级,学生相当于activity。task相当于运动会的项目。task在栈中记录activity的引用(项目中记录着学生),那当然班级与学生也引用着。也许项目是以班级为单位的,班级有个默认项目,还都是一个班的学生。也许同一项目是不同班级的学生。我们的镜头切换不同的项目时,比如从桌面启动时,情况就比较复杂。Intent也许就是配合activity切换与task的分组管理的。估计其它app应用调用微信什么的,都是调用里面的具体一个activity,在一个task中,还相互传递参数。
十、使用vebview显示远程页面
现在很多app上都用h5页面取代制作复杂的activity页面了。我猜想,毕竟相对简单,而且适应手机浏览器的共用,app变化也小,页面更容易开发。
我们的webView控件,主要有这么几个设置:
后面就可以加载远程的h5页面了。
....(to be continued!)
发现一个系列的andriod studio教材,实践中...
http://blog.csdn.net/kmyhy/article/details/54929222
两周前开始正式实战,昨天终于实现了launch页,进主fragment页,远程获取数据,listview显示数据与图片。所以本篇开始继续下篇的内容:
过程比较艰辛,主要是电脑是用了i3350,4年多以前的宏基的Aspire4741。内存4G,经常是内存95%,WIN10硬盘100%读写。简单优化了一下电脑,所以avd什么都用不了,安装到我手机上用。
一、安装android studio,基本使用。
二、下载了一个Memeify的例子,体现了intent等使用,手机内图片的生成与使用。
三、考虑到找到的项目太大了,但缺少地图功能,于是先研究地图
先是网上找例子,想用google的地图,装手机上闪退。只好研究百度地图,也是闪退,后来发现是权限问题。手机上设置就OK了,于是改动态获取。
这个过程上,尝试很多版本设置,太麻烦了。什么glade版本tools版本,编译版本,最低版本。还研究了百度地图申请key,加了service对象,研究了jks签名apk包。
四、真正启动android项目开发
原项目中的一堆问题也不想处理了,也无法生成apk用,于是新建一个项目,一个个要的功能往过来搬家。先把展示页弄出来,可以跳转到一个主页面。
实现一个小功能,实际的基础工作非常多,参考系统中一大堆util,还有一个公共模块都搬过来。太多了怕无法运行成功,少了就要一个个分析才行。
展示页根据有没有用户产生登录或者主页面。我先让他转到我新弄的地图页面。简单的一个apk就20M了,每次传手机上安装,测试非常耗时,但我不想暂时去除地图功能。
闪退是最头大的,没有任何信息,在加法与减法中徘徊,用toast产生我想看的信息,就这么调试。
主页面是非常复杂的,有5个fragment,有的里面还有一层层嵌套的view,如上面分析,我的目标是frament出来,可以切换,先把里面具体的都去除。好在frament都出来了。
下一步就是先弄最常用的listview,但它还有一个轮播头。这里面碰到很大的问题,先临时弄了一个后台的.do请求给手机用,手机上还要转jason到VO,还有asyncTask写入list给adaptor用,还要触发holder产生view,页面上还有fasco加载图片。
几天都被这个fragment折磨着,要么是list没数据,要么是闪退,一个个写toast解决,简化。但怎么也出来来列表,又研究页面布局问题。最后发现是Fasco在基类中没有init()。因为我是一个全新的项目,把分析的项目copy过来的,还注销了很多感觉不用的功能,比如各种平台的分析,计数等额外功能,现在不需要,代码太多了。这里就出问题。
因为listview有个头,我还去掉头测试,还不知道是不是一定要头,也不知道是布局的问题不。或者是数据转化的exception,但我没办法在as中调试,打出日志,一遍遍安装到手机上。以至于微信说当天发送达到上限了。我只好研究autopull效果与Fasco的使用,无意中看到init()要用到。当页面来来的那一刻,突然一种快感袭来,几天的折磨一哄而散。
四,接下来研究登录,录入正式的数据,多弄几个页面。另外把地理位置记库里,把数据点显示在地图上。
五、登录已经成功。后面是显示listview里的详情页面,而且可以评论。先不玩自定义的,来标准的。
参考:
http://blog.csdn.net/zgljl2012/article/details/44553469
AlertDialog ad = builder.create(); //创建对话框
ad.show(); //需先显示,然后才能查找控件
start =(TimePicker)ad.findViewById(R.id.timepicker_start);
end = (TimePicker)ad.findViewById(R.id.timepicker_end);
text = (EditText)ad.findViewById(R.id.editText_content);
webview处理:
http://neilj.github.io/Squire/
http://blog.csdn.net/carson_ho/article/details/52693322
目前已经在阿里云上运行了一个多月了,有些朋友使用。
一、lanuch页面
二、公告页
三、GPS点信息(百度地图)
四、生活故事
android项目的初接触
做java的web项目很久了,虽然看了几篇入门的文章,却从没有真正研究过安卓的开发。可能以后会有手机端开发,毕竟手机应用火。碰巧有机会找来一个应用宝中的一个项目的源码,从0开发研究。一方面看看自己迅速总体掌握陌生安卓项目的能力,另一方面也是储备,掌控未来手机端开发进度。还有一方面,估计不会做app,工作有明确范围,但知识应该跨越边境,整体考虑,才能做到更好。
大家看网上的资料有没有这样的感觉,一般的文章看再多都难以形成一个完整的安卓开发概念。多是简单入门,或者专注于某一要点,而我需要的是一个真正的完整项目,通过研究有一个整体的把握。
这个项目包含一般复杂的页面功能,还有微信登录,分享,支付等功能,相当完备,直接从0到实用工程级项目。防止泄密,以文字和简单图片为主,才学习了几个业余晚上时间,许多说法可能不对,欢迎指正。
一、基础入门
开发工具,打包测试我都不管了,重点是理解结构、代码与整体设计。我就用eclipse导入工程,以看代码为主。首先是配合BAIDU的简单知识,了解项目的文件层次与主要文件的作用。
1.AndroidManifest.xml 总的软件配置文件,各种权限说明,还有很多activity(这就当是主活动页面吧)。
2.res文件夹比较重要,名字叫资源,主要有layout是各种布局文件,各种常量值,还有图片啥的。有些文件夹名字-后缀,是不同屏幕用的。layout比较重要,是界面布局,做过其它窗口程序开发的就知道,窗口会有几个文件,有的文件就只是布局。
3.src是核心java源代码。有ui相关的,app相关的,activity相关的,fragment相关的,widge相关的。上面提到一些布局XML文件,会与这里的有些界面处理类相关联着。比如activity类就会加载自己对应的布局文件。
这里就会想到,之前用过vb什么的,dephi什么的语言进行可视化编程,也会产生代码文件与界面文件。
4.查了点app主线程资料,一般的语言都是事件发生后,产生消息来驱动的。比如在手机上点击按钮,主线程就会处理这个动作。这里的UI线程就是APP的主线程,主线程是循环处理消息,但可以阻塞,并被唤醒,具体的消息驱动会在后面介绍。主线程一般不会用多线程处理消息,比如js就是单线程处理,node.js也是,nio也是单线程,非阻塞的IO的方式。后面再仔细品味,会发现这几乎是相似的模式:单线程处理所有的事情,如果有耗时的事情,等于是拆分两件事了。
二、主activity界面内容
先简单说一下这个应用,启动APP后,先出现一个启动画面,之后如果已经登录了就进入主界面,没有登录进入登录界面。先选择主界面开始,具体分析。
主页面下面是一些模块按钮,点不同的按钮出现不同的界面,下面是不动的。比如第1个按钮看到的是【文章列表】,后面有一个搜索的小图标。
下面是一个左右可以滑动的热门文章,显示图片与标题。
再下面是一个列表的文章,按时间一行行显示出来,每一行有文章图片,标题,主要内容,发布时间等。
三、主activity界面设计
既然说界面,界面是一种res,所以下面说的都在res的layout中,是xml文件。主activity里有三大模块内容,有点类似微信下面的四块内容。上面部分用的是FrameLayout,下面是LinearLayout,LinearLayout里面又是三块LinearLayout,每块里面才是文字与图片。下面比较简单,上面那么复杂的东西只放了一个FrameLayout,看来是要嵌入其它东西了。
里面确实是放三个fragment,而且重点工作都是在fragment中,那么先介绍一下fragment的界面,如图三。上面一块是文字与图片,下面是一个AbPullToRefreshView,里面嵌入一个ListView。最下面还有二块,分别是等待与出错块。从名字可能看到,PullToRefresh是下拉会刷新的东东,list当然是列表了。
刚才介绍主体内容上面是轮播,下面是列表,没看到轮播块?事实上轮播是动态放入的,后面再说,还是先把界面有啥介绍完。轮播又是一个xml,里面只有一个InfiniteViewPager。就当成轮播的框架吧,架子里才是真正的内容,又是一个xml。这个xml才是最终内容,有SimpleDraweeView和一个文本View。说完了轮播,还有列表。列表里的内容也是一个xml,里面有SimpleDraweeView,还有好几个文本View,比如标题什么的。
界面看来是一层层嵌套的关系。主Actity界面(1),其中一个fragment界面(2),里面又会动态加一个轮播界面(3)与列表内容界面(4),轮播里又是一个轮播内容界面(5)。一共5个xml文件。与上图示意图的后五个图对应。这里想想这界面真是蛮麻烦的事情。
界面心得:都是一种layout(布局)里面放置其它控件或者子layout,如果有子layout,那里面还有控件。为何不把上面这么多放在一个大的布局文件中?我也不知道,只是后面看代码发现是动态加载,这样算组件复用吧。比如轮播里的内容个数,列表中的个数都是不定的。主界面中的fragment的个数也可以说是多个的,所以不定的,多个切换的内容要分开一个界面文件。
四,从主界面相关代码开始分析
1.主界面activity的类,应该是这个类会加载主界面。
这个类的变量有这么几类:
- 界面上的控件类,个别有ID的布局类,直接与界面上的ID绑定,就当是实例了。
- 主界面中的fragment类属性,只是定义了,并没有马上实例化。想想前面说是动态加载了,因为数量多个切换,所以这里不实例化是正常的。
- 另外一些API啊之类的,先不关心这个。
2.主界面类的方法
onCreate():先是加载界面文件,res文件夹中的layout文件夹中的特定界面文件。还包括下面几个子方法。
initData();初始化一些数据,可以从远程去获取
initView();new出上面定义的属性,这里特别指fragment类,new会产生什么要看后面fragment里了。
initListener();监听一些用户操作,这里是指下面三大块的按钮,里面的界面上的操作由里面负责的。主要是三大块fragment的切换。
这个类回头看了再细说。
3.重要是fragment这具类代码
主界面有三个fragment界面切换,主界面类有三个fragment类,可以说是动态加载进去的。很多操作在这个里面。
与主界面activity类相似,先说说它的属性,包括界面上的控件,直接绑定了ID,就是实例了。还有界面上的个别layout布局实例,也是直接绑定ID,一般只有显示,隐藏这样的操作。还有一个动态view类,就是轮播view。还有放数据的两个ArrayList。还有些其它的回头说。
说明:一个界面类上明确的控件,直接用ID绑定了,不定个数的控件会new出来,同时加载界面文件,产生实例。
而方法中首先是onCreateView()方法。同样先是加载自己的界面,inflater.inflate(),同样是res/layout/***.xml。
之后还是initData();初始化一些数据和对象。
initView();初始化一些参数,比如给可下拉对象设置属性,以及设置监听操作。再是重点动态加载界面了。属性里只有一个动态view对象,用getLayoutInflater().inflate()加载动态对象的界面,前面加载的是自己的。
需要监听用户操作的控件在这个初始化View过程中设置,比如设置setOnClickListener。
这个动态加载的界面对象里有一个控件,里面会放一堆不定个数的轮播画面。而自己本身还有一个非动态加载的listview控件,里面也会放一堆不定个数的列表画面。处理方面是控件里放个适配器。发现listView可以直接放适配器,可是动态的界面对象里的控件对象才能放适配器,并不是界面对象本身放适配器。说明:从界面文件加载的layout/view不能放适配器,必须是一个控件对象,想想也蛮合理的。把轮播layout/view动态加载给listView。
整理一下总的结构:fragment对象里有一个列表对象,还会动态加载一个外部界面对象,动态加一个适配器,而外部界面对象里的一个控件,也动态加了一个适配器。貌似与通常的想法不一样,这个象是控件里加了一个布局。控件里怎么可以加布局呢?通常界面XML中是布局包含控件与布局。控件是叶子结点,布局是中间结点。当然控件里放适配器这一点没有问题。先不管细节了,就当特殊时候可以这么用吧。
4.再看一下适配器里是什么东东
这里的适配器是fragment类中的一个内部类。里面有一个重要的getView()方法,想想也对,控件里面具体的个数不确定,或者要切换,当然要适配一下了,产生里面的view。getView的参数有具体数据,所以通过一个ViewHolder把数据与不定个数界面的控件关联起来。同时赋予这个界面响应点击事件,跳转到其它界面activity。
5.界面都好了,最后是加载数据。
startGetDataTask();//这个是执行加载数据的任务。
这个方法包括:new 一个异步任务AsyncTask,并执行它,后面会详细介绍几个异步线程操作。
AsyncTask对象固定有一些方法要重载的,都是生命周期不同时候触发的。主要是执行前的清理与准备onPreExecute。执行中doInBackground,去请求后台数据。执行后onPostExecute,把返回的数据置入界面类的ArrayList对象中,再由适配器执行Adapter.notifyDataSetChanged();表示告诉适配器我的数据发生了变化。
适配器是什么?包括了数据,也有getView方法从界面XML中加载界面的功能,通过holder把数据与界面中的控件关联起来。所以设计这个东西,是能感知数据变化,产生变化的,不定个数的界面的。这个就理解通了。
五、回顾一下前面学习的内容
1.界面上都是layout与控件,但不定个数的界面都分成一个个子界面,都是独立XML文件
2.界面类属性有自己的控件并绑定实例化,还有动态要生成的界面类init的加载。
3.界面类init的时候,加载自已的界面文件,而其中的动态界面实例化时,实例化同时加载子界面文件。同时对这个动态子界面中的控件设置响应用户操作的动作。
4.界面类的有的控件类可以包含界面类中的子界面类。
5.界面类的有的控件类可以包含不定个数的界面,或者切换的界面时,这时候要到适配器。
6.适配器把数据与不定个数的子子界面对象关联起来。可以生成一个个子子界面,可以响应数据的变化而自己变化。
7.一个异步任务可以与后台服务器交互,拿出来数据后,让适配器变化。如果需要简单的操作Ui,AsyncTask固定实现的一些方法非常清晰好用。
8.控件或者view可以设置来响应用户的操作,比如点击什么的。
理解下来,这些都还蛮顺的。除了那个List控件加载了一个layout对象,与界面xml中控件都是叶子结点的思路有点冲突之外。有的控件当然也是容器控件。
补充:界面文件中AbPullToRefreshView可刷新控件里包含了listView控件,listView要动态加载一个界面XML文件当头部。为什么listView里不直接在界面xml文件里放置另一界面文件中的InfiniteViewPager控件呢?现在是用addHeaderView加进来的。也许listView就这么设计的,一些控件之间就是固定的套路。但为什么不在AbPullToRefreshView可刷新控件中直接包含InfiniteViewPager与listView呢?不知道会是什么效果。
六、微信相关的登录、分享。
1.登录的界面(含微信登录)设计
一般来说,登录界面与注册界面都在一个activity中,而且是可以切换的。按照上面的理解。activity的界面xml中应该有一个容器ViewPager,而登录与注册又是动态加载进去的。必然有一个适配器Adaptor来处理登录与注册对象,并且赋给ViewPager对象。
在登录的xml界面中,有一个ImageView用于微信登录。
activity的类中,主要是onCreate中加载自己的界面文件。另外有初始化数据与对象,初始化界面与操作两类。初始化界面与操作是重点介绍的。里面主要是动态加载注册与登录两个切换的部分以及适配器的配置。
2.登录注册中的适配器Adaptor
Adaptor中最主要的是instantiateItem()方法,切换操作时返回选择的view,这个过程中对动态加载的登录view或者注册view进行选择,并从动态界面中获取控件,再配置控件响应用户的各种操作。
对于登录view中的操作,除了校验外,产生一个new Thread()来处理登录提交,正常登录后进入最上面提到的主页activity。上面讲过一个异步任务,这里不操作ui,是普通线程。登录后以后,再用LoginActivity.this.runOnUiThread(Runnable)来更新主线程,主线程登录成功跳转,或者显示出错信息。这个机制好象是把耗时的动作让另一个线程做,好了以后还可以通知ui主线程做事。
3.微信登录
对于微信那个imageView,可以加上setOnClickListener操作内容。里面的重点是用com.umeng.socialize.UMShareAPI对象的实例,做doOauthVerify与getPlatformInfo操作。从名字看一个是用户验证,一个是获取微信平台的信息。我们知道微信等于是一个外部的对象了,这里是用友盟的接口来做。从经验来说,两个对象要想发生关系,其中一个把自己注册给对方,并实现一个通知接口回调。从方法:doOauthVerify(LoginActivity.this, SHARE_MEDIA.WEIXIN, umListener);可以看到,传入了自己,并传入了一个监听器进去,监听器最主要的是onComplete方法,里面得到本机微信的数据后,再用loginWechat(id, name, image);来正式登录微信后台。
现在loginWechat登录的过程与标准登录差不多了,只不过请求的不是自己的后台了。过程为:另外启动一个线程来登录微信后台,根据登录成功的结果,再利用Activity.runOnUiThread(Runnable)来更新ui主线程。在主线程中给用户显示出登录成功,并跳转到主activity。
简单理一下:点击微信时,主界面把一个监听器给友盟接口,友盟拿到手机上微信的信息后会回调监听中的方法,这个方法用这些信息,另启一个线程登录微信后台。标准登录是用用户名密码登录自己的后台。这里借助外部力量,一般都要回调,另启一个线程不是太明白,更新ui主线程不知道是什么机制呢?(后面知道,只能主线程更新UI界面,方式有几个)友盟的作用就是拿到手机上友商的信息吧!
4.微信分享
一般我们点分享时,会出现半个窗口,里面有分享到微信好友,朋友圈之类的,这是通过fragment来实现的。fragment上面说到,是一个粗粒度的界面组件。接近activity,大于view。
首先说说fragment对应的界面,就是res/layout里的一个界面xml,里面就是几个图标,比如有微信好友。
用户主activity中点击分享时,在onClick中就要动态生成这个fragment组件。重点就是要看组件的类代码,其中onCreateView就是加载界面xml,这个都一样。不过加载里面的控件就放在onViewCreated里了,因为分享肯定是接收分享内容的参数了,onViewCreated是可以有参数的。这个过程中要给里面的具体分享图片view设置响应点击操作了。在点击时,会组装好分享内容的参数,用友盟的ShareAction来做了。我们前面登录分析了,就知道用友盟与外部打交道,要传入自己(父级activity)和一个监听器。监听器根据外部分享的情况,指挥自己内部如何处理,比如Toast.makeText显示分享成功或者失败之类的。
发现在分享QQZone时,要ActivityCompat.requestPermissions,就是动态请求权限。还要根据用户选择允许或者不允许时的onRequestPermissionsResult,才确定如何响应用户的判断。
七、微信支付
1.这里采用handler消息机制来做
handler消息机制,大概了解了一下,就是把消息体与处理方法包在一起放进一个队列里,有一个loop()过程进行死循环,拿出这个包装体,用包装体中的方法来处理消息体。主要是消息处理不影响主线程,主ui线程天生自带looper和队列。
开始有一点没看懂,那个loop()不是单独开一个线程来处理吗?这样主线程才顺畅啊。事实上loop()是主线程中循环,有一个唤醒机制。比如我点击一个按钮后,过程中会用handle产生一个新消息(或者从消息池中拿一个空的消息),给消息设置好相关数据后。这时主UI线程唤醒looper(),拿出消息,并用这个消息关联的handle处理这个消息。
前面登录用了普通线程,里面用到LoginActivity.this.runOnUiThread来让主线程显示跳转。适配器用了异步任务,要重写一些方法,算是调用UI线程中的onPostExecute()执行后续UI操作。这里又是一种消息机制。
2.从点击确认支付开始
假如支付确定的imgview上有onClick方法,那这个方法的主要步骤有:
- 组装支付参数
- 提交订单给自己服务器的后台,记录下订单信息,回调APP的onResponse中根据提交情况,如果正常,APP就开始微信支付。
- 再发起调用以获取微信支付key,提交的参数,包括appid,secret,在回调中再进一步处理。
- 回调中会开启一个线程,用相关参数正式调用微信后台,再得到一个msg,把微信后台返回后的值放在msg中,再用handle发送这个msg。
- 唤醒主UI线程中隐含的looper()处理msg,用msg关联的handle处理msg,handle中可以用吐司显示支付结果。
八、UI线程与消息handler机制
既然做了那么多J2EE开发,是时候比较一下此刻我眼中的android开发了。手上工作比较多,周末正好参加马拉松参加,时间紧比较仓促,看的比较粗。
android开发也是要画界面,写每一个控件的操作,貌似与一些其它开发是相通的。UI线程是单线程,是用来响应用户操作的,真正耗费时候的都要用其它线程来做,而且UI不是线程安全的,所以其它线程不要操作UI上的控件,所有的ui操作都通过handler来发消息操作。JS也是单线程,node.js也是,我们知道tcp用的nio也是一个线程分发的,所以有很多相似的地方。
主UI线程应该是一个不断循环处理的线程,处理各种消息。把界面上各种操作都放在一个消息池中,主UI一个个来处理。主UI我查了一下,虽然是循环处理,但没消息时是阻塞状态,也不是空转,但有一个唤醒机制,是pipe/epoll,这个机制恰好我在看基于nio的netty通讯框架时有查过这方面的资料,是IO相关的FD来唤醒的。
了解大致原理,有助于我们用新的知识或者功能时不犯原则性的错误。
先想到了handle机制处理异步操作,为何主ui中默认就有looper呢?也许就是上面的道理吧。你自己弄的线程需要消息循环处理时,就要自己写looper.prepare之类的代码了。主UI当然必须有。handle的生成一定要是looper线程中,而handle的发送消息一定要在另一个线程中。
主线程UI中的各个控件,也是设置了好多处理方案,之后扔在屏幕上让控件接受外面的使用而产生消息。主UI根据这些消息就按设置好的处理方案来处理事件。所以handle机制是个原始机制,上面在微信支付时就是这个方式,但原码中还支付其它的方式,产生的msg是不同的,是否抽象msg方案与具体支付方式的不同,是不用其它异步方式的原因?
我用一种通俗的方式理解一下这个机制。家长与孩子有一个协定,如果是好事,孩子可以吃糖,如果是坏事就罚站,这是主线程。家长把孩子送出家门,进另一个线程。在外面可能被发奖状消息,孩子回来后,家长时刻检查这些消息,如果是好事孩子就会吃糖。
九、其它异步机制
- Activity.runOnUIThread(Runnable)
- View.Post(Runnable)
- View.PostDelayed(Runnabe,long)
- AsyncTask
当你点击控件,产生一个动作的时候,你可以产生另一个线程做事,根据做事中的结果,你就可以执行Activity.runOnUIThread(Runnable),在参数的Runable中操作控件。
如果特定让哪个控件变化,就用View.Post(Runnable)。
AsyncTask看不到具体的线程,AsyncTask类主要有三个操作:
doInBackground()后台做的操作;onProgressUpdate()任务开始时的操作;onPostExecute()任务完成时的操作;
使用方法:
new PostTask().execute(status);传递参数到doInBackground(),在其中可以执行后台操作,比如获取服务器数据;doInBackground()的操作会返回数据,而这个数据又是onPostExecute()的参数,可以把参数置给activity中的数据变量,并让控件来用这个数据变量;
注意:doInBackground()是在其他线程运行的方法,不能调用UI;onPostExecute是在主UI运行的方法,可以更新界面。
其实四种方法都是基于handler方法的包装。在一般的情形下后面的似乎更值得推荐。但是当情形比较复杂,还是推荐使用handler。
十、其它一些小内容
介绍了那么多,只能是有些概念了,但如果具体要开发一个商用级,还需要很多知识。
0.数据库
一个应用通常少不了数据库,总不能都记录在后台吧。这里使用SQLite。
一般用SQLiteOpenHelper的子类管理数据库的生成与版本。
自己写一个DBManager,使用SQLiteOpenHelper来获取数据库,并用来管理业务。数据库的初始化,可以放在app的onCreate()里来做。后面讲的共享数据与业务初始数据也是各自有管理类,也在这个方法里。这个好理解,app初始化应该把应用级的事情都做好,准备好。
分析类比一下:一般j2ee习惯是用一个数据库服务器,应用有应用服务器,分为管理数据库与使用数据库两个方面。
这里相似:helper首先是用来管理数据库文件的,可以新建一个db,以及初始化db表,版本变化时也重置数据库。另外一方面就是给应用获取数据库实例,或者叫连接吧。
另外注意的是:Cursor。一般在业务封装中打开与关闭,但查资料也可以在activity里,让activity来管理cursor的生命同期。个人觉得,一般不用放在activity里。
还有就是数据库里放什么?这方面从我使用其它APP感觉一下。APP可以清除数据,这时登录后从服务器上再获取,最新的数据离线时可以本地查看。比如我收藏的股票,可以本地读,本地没有从服务器上读。我一天的运动数据,可以从本地读,但汇总数据从服务器上读。
1.全局变量
平台的配置,建议放在全局Application或者程序入口。
PlatformConfig.setWeixin(appid,secret)这些用友盟的三方的配置都放在这里。这里还没太懂?整个机制不知是什么样的。
写一个baseActivity。activity中要使用远程请求,在baseActivity中产生一个请求对象,每个页面就都有了,具体在下面说。
baseActivitycom.johnson.commonlibs.common_utils.utils.HttpUtils也在baseActivity中,用isNetworkAvailable来得到网格情况。
2.用户账号与自动登录
3.远程请求
这个用Retrofit2框架,Retrofit 是安卓上最流行的HTTP Client库之一。写一个接口ApiService,把APP中所有的请求放进来。比如:
@GET("orderShow.do")
Call<JsonObject> orderShow(@Query("inputStr") String inputStr);
使用时,先产生接口的实例。
apiService = ServiceGenerator.generate(Application.getInstance()).setEndpoint(BaseApiUrl.class).getApiService(ApiService.class);
再使用实例的方法,方法就是接口中的了。
apiService.orderShow(inputStr).enqueue(new Callback<JsonObject>() {..}
上面的括号里就是一个回调方法,自己实现onResponse与onFailure两个方法。
思考:ServiceGenerator估计是代理工厂,产生一个实现接口的代理对象,动态代理吧?里面可能是真正的httpClient来处理请求。
4.验证码
5.可惜没有地图使用方面的代码
6.SharedPreferences
看到系统登录后保存了用户信息,发现是存在SharedPreferences中,也是差不多key-value的方式。查了下资料:
调用Context对象的getSharedPreferences()方法获得的SharedPreferences对象可以被同一应用程序下的其他组件共享.调用Activity对象的getPreferences()方法获得的SharedPreferences对象只能在该Activity中使用.
SharedPreferences是Android平台上一个轻量级的存储类,用来保存应用的一些常用配置,比如Activity状态,Activity暂停时,将此activity的状态保存到SharedPereferences中;当Activity重载,系统回调方法onSaveInstanceState时,再从SharedPreferences中将值取出。
SharedPreferences提供了java常规的Long、Int、String等类型数据的保存接口。 [1]
SharedPreferences类似过去Windows系统上的ini配置文件,但是它分为多种权限,可以全局共享访问。
提示最终是以xml方式来保存,整体效率来看不是特别的高,对于常规的轻量级而言比SQLite要好不少,如果真的存储量不大可以考虑自己定义文件格式。xml处理时Dalvik会通过自带底层的本地XML Parser解析,比如XMLpull方式,这样对于内存资源占用比较好。
SharedPreferences 可以用来进行数据的共享,包括应用程序之间,或者同一个应用程序中的不同组件。比如两个activity除了通过Intent传递数据之外,也可以通过SharedPreferences来共享数据。
从使用上说,一般用单例对象处理SharedPreferences。app应用当然与共享数据实例对象的生存周期一样,同时需要一个context当参数(context.getApplicationContext()比较保险)。在app的onCreate中产生这个单例对象,并把app自己当参数传进去,所谓同生共死。这里我们有个共享数据管理类。
7.初始化数据
app启动时,可能有一些初始化数据。比如一些行政区划数据,我们在j2ee中通常从后台获取,在app中看到是从res中读取jason的文件。这里我还不知道如果有变化怎么更新资源文件?难道是app升级吗?
我们让一个类中持有这些数据,怎么获取res中数据呢?new InputStreamReader( context.getResources().openRawResource(fileResId));用流的方式,这里有一个context,也是app的onCreate()的时候,把app自己传进来就行了。这里我们有一个初始数据管理类。
十一、深入理解一些机制
1.Activity与进程,线程的关系
4大组件组成:Activity,Service,ContentProvider,BroadcastReceiver。应用第一次启动时,会启动一个新进程。该进程会启动主线程ActivityThread,也叫做UI线程,UI的绘制都在该线程里完成。
个人理解:一个APP进程中只能有一个ui主线程。Activity的切换都不会另开线程,都是在一个线程里运行。我猜测一个app里的activity对主线程来说,也都是动态加载进来的。如同activity动态加载view之类的一样。主线程里应该有一个List<activity>这样的东东。前面说过UI线程中默认有消息处理looper,是处理任何activity里的界面响应,也处理自定义的handle的消息。消息交给activity本身的回调,再一层层回调activity里的东东。很有层次感。
2.不同app之间相互调用activity,以及与task的关系。
task是一个具有栈结构的容器,可以放置多个Activity实例。启动一个应用,系统就会为之创建一个task,来放置根Activity;默认情况下,一个Activity启动另一个Activity时,两个Activity是放置在同一个task中的,后者被压入前者所在的task栈,当用户按下后退键,后者从task被弹出,前者又显示在幕前,特别是启动其他应用中的Activity时,两个Activity对用户来说就好像是属于同一个应用;
个人理解:app相当于学校里的班级,学生相当于activity。task相当于运动会的项目。task在栈中记录activity的引用(项目中记录着学生),那当然班级与学生也引用着。也许项目是以班级为单位的,班级有个默认项目,还都是一个班的学生。也许同一项目是不同班级的学生。我们的镜头切换不同的项目时,比如从桌面启动时,情况就比较复杂。Intent也许就是配合activity切换与task的分组管理的。估计其它app应用调用微信什么的,都是调用里面的具体一个activity,在一个task中,还相互传递参数。
十、使用vebview显示远程页面
现在很多app上都用h5页面取代制作复杂的activity页面了。我猜想,毕竟相对简单,而且适应手机浏览器的共用,app变化也小,页面更容易开发。
我们的webView控件,主要有这么几个设置:
webView.setWebViewClient(new WebViewClient() {..重写几个方法...}) webView.setWebChromeClient(new WebChromeClient(){..重写几个方法...}) webView.setOnKeyListener(new View.OnKeyListener() {..重写几个方法...}) WebSettings settings = webView.getSettings(); settings.setJavaScriptCanOpenWindowsAutomatically(true); settings.setJavaScriptEnabled(true); settings.setSupportZoom(true); settings.setBuiltInZoomControls(true); settings.setDisplayZoomControls(false); settings.setUseWideViewPort(true); settings.setCacheMode(WebSettings.LOAD_NO_CACHE); settings.setLayoutAlgorithm(LayoutAlgorithm.SINGLE_COLUMN); settings.setLoadWithOverviewMode(true); settings.setAppCacheEnabled(true); settings.setDomStorageEnabled(true); webView.loadUrl(IConstant.URL.WEB_URL);
后面就可以加载远程的h5页面了。
....(to be continued!)
发现一个系列的andriod studio教材,实践中...
http://blog.csdn.net/kmyhy/article/details/54929222
android项目的实战
两周前开始正式实战,昨天终于实现了launch页,进主fragment页,远程获取数据,listview显示数据与图片。所以本篇开始继续下篇的内容:
过程比较艰辛,主要是电脑是用了i3350,4年多以前的宏基的Aspire4741。内存4G,经常是内存95%,WIN10硬盘100%读写。简单优化了一下电脑,所以avd什么都用不了,安装到我手机上用。
一、安装android studio,基本使用。
二、下载了一个Memeify的例子,体现了intent等使用,手机内图片的生成与使用。
三、考虑到找到的项目太大了,但缺少地图功能,于是先研究地图
先是网上找例子,想用google的地图,装手机上闪退。只好研究百度地图,也是闪退,后来发现是权限问题。手机上设置就OK了,于是改动态获取。
这个过程上,尝试很多版本设置,太麻烦了。什么glade版本tools版本,编译版本,最低版本。还研究了百度地图申请key,加了service对象,研究了jks签名apk包。
四、真正启动android项目开发
原项目中的一堆问题也不想处理了,也无法生成apk用,于是新建一个项目,一个个要的功能往过来搬家。先把展示页弄出来,可以跳转到一个主页面。
实现一个小功能,实际的基础工作非常多,参考系统中一大堆util,还有一个公共模块都搬过来。太多了怕无法运行成功,少了就要一个个分析才行。
展示页根据有没有用户产生登录或者主页面。我先让他转到我新弄的地图页面。简单的一个apk就20M了,每次传手机上安装,测试非常耗时,但我不想暂时去除地图功能。
闪退是最头大的,没有任何信息,在加法与减法中徘徊,用toast产生我想看的信息,就这么调试。
主页面是非常复杂的,有5个fragment,有的里面还有一层层嵌套的view,如上面分析,我的目标是frament出来,可以切换,先把里面具体的都去除。好在frament都出来了。
下一步就是先弄最常用的listview,但它还有一个轮播头。这里面碰到很大的问题,先临时弄了一个后台的.do请求给手机用,手机上还要转jason到VO,还有asyncTask写入list给adaptor用,还要触发holder产生view,页面上还有fasco加载图片。
几天都被这个fragment折磨着,要么是list没数据,要么是闪退,一个个写toast解决,简化。但怎么也出来来列表,又研究页面布局问题。最后发现是Fasco在基类中没有init()。因为我是一个全新的项目,把分析的项目copy过来的,还注销了很多感觉不用的功能,比如各种平台的分析,计数等额外功能,现在不需要,代码太多了。这里就出问题。
因为listview有个头,我还去掉头测试,还不知道是不是一定要头,也不知道是布局的问题不。或者是数据转化的exception,但我没办法在as中调试,打出日志,一遍遍安装到手机上。以至于微信说当天发送达到上限了。我只好研究autopull效果与Fasco的使用,无意中看到init()要用到。当页面来来的那一刻,突然一种快感袭来,几天的折磨一哄而散。
四,接下来研究登录,录入正式的数据,多弄几个页面。另外把地理位置记库里,把数据点显示在地图上。
五、登录已经成功。后面是显示listview里的详情页面,而且可以评论。先不玩自定义的,来标准的。
参考:
http://blog.csdn.net/zgljl2012/article/details/44553469
AlertDialog ad = builder.create(); //创建对话框
ad.show(); //需先显示,然后才能查找控件
start =(TimePicker)ad.findViewById(R.id.timepicker_start);
end = (TimePicker)ad.findViewById(R.id.timepicker_end);
text = (EditText)ad.findViewById(R.id.editText_content);
webview处理:
http://neilj.github.io/Squire/
http://blog.csdn.net/carson_ho/article/details/52693322
android项目的成果
目前已经在阿里云上运行了一个多月了,有些朋友使用。
一、lanuch页面
二、公告页
三、GPS点信息(百度地图)
四、生活故事
相关推荐
andriod andriod学习 andriod andriod学习 andriod andriod学习
通过阅读和分析实际的项目代码,你可以学习到如何组织项目结构,如何处理数据存储,以及如何实现特定功能,比如网络通信或者本地数据库操作。同时,文档部分则会提供理论支持和详细解释,帮助你在遇到问题时找到解决...
这个压缩包文件“安卓Andriod源码——选择城市列表,配本地数据库,可以直接应用到项目.zip”包含了一个完整的Android应用程序项目,旨在提供一个选择城市列表的功能,并且这个功能是与本地数据库配合使用的。...
关于网上物流的PPT报告,其中详细讲述了关于基于andriod五路项目的报告。他是非常详细以及好的。
这个“雷电游戏”项目是初学者在学习Android开发时制作的一个初步实践,虽然不完美,但足以展示Android应用的基本构建过程。 1. **环境搭建**:在开始Android开发之前,你需要安装Android Studio,这是Google提供的...
综上所述,这个“andriod图文识别模块源码”涵盖了从图像处理到文字识别的整个流程,提供了在Android应用中实现图文识别的全面解决方案。开发者可以借此提升应用的功能性和用户体验,实现高效的文字提取和处理。
在本项目中,“Gridview加载网络图片Andriod源码”提供了实现GridView加载网络图片的功能,无需依赖额外的jar包,这使得项目更轻量且易于维护。 首先,我们需要了解如何在Android中处理网络图片。在Android API 24...
描述中的“安卓Andriod源码——高级图片滚动控件,3D版的图片轮播器Demo.zip”表明这是一个用于Android开发的代码示例,主要功能是一个3D效果的图片轮播组件。这个Demo可能是为了帮助开发者理解和实现类似功能,通过...
Android学习策略是一个逐步深入的过程,对于初学者而言,掌握正确的学习路径至关重要。以下是一份详细的Android学习计划: **初级阶段** 1. **环境配置**:首先,你需要安装最新的Android SDK、ADT(Android ...
这个"Google AndRiod 入门级实例程序"是一个专门为初学者设计的学习资源,旨在帮助新接触Android开发的人快速理解和掌握基本概念、工具以及编程技巧。 1. **Android SDK与开发环境**: Android应用开发的基础是...
《多库俄罗斯方块Andriod版本开发详解》 在移动设备上,经典游戏...通过深入研究这个项目,我们可以了解Andriod游戏开发的全貌,从图形渲染到事件处理,再到用户体验的优化,这些都是构建一个成功Andriod游戏的关键。
通过以上学习路线图,初学者可以从零开始逐步构建起扎实的Java基础,并过渡到Android应用与游戏开发领域。每个阶段都设定了明确的目标,旨在帮助学习者有序地推进学习进程,避免走弯路。此外,还推荐了“尚观4G智能...
总的来说,Andriod图片查看案例涵盖了Android开发中的图片加载、显示、手势识别、内存管理和用户体验优化等多个方面,对于开发者来说,这是一个很好的学习和实践平台。通过对这个案例的深入理解,开发者可以掌握处理...
Android Afinal框架是一款轻量级的数据库操作库,专为Android平台设计,简化了Android中的SQLite数据库操作。Afinal提供了一种简洁的API接口,使得开发者可以更方便、高效地进行数据存储和查询。这个“andriod ...
3. **项目结构**:一个Android项目通常包括多个组件,如MainActivity(主活动)、布局文件(XML)、资源文件(如图片、音频、字符串等)、AndroidManifest.xml(应用配置文件)等。了解这些组件及其作用是进行...
综上所述,对于初学者来说,从图形化编程工具开始,逐步了解Android开发的基本概念和流程,是一个良好的学习起点。随着学习的深入和技术的掌握,再逐步转向使用更为专业的开发工具和语言,是学习Android开发推荐的...
经典Andriod开发书籍...送给入门(keng)的或者计划入门(keng)的筒子们!
首先,我们从基础开始。Android系统是基于Linux内核的开源平台,它的开发环境主要是Android Studio,这是一个集成开发环境(IDE),包含了编写、调试和发布Android应用所需的所有工具。在学习Android时,你需要熟悉...
Android应用源码之weibo4andriod.zip项目安卓应用源码下载Android应用源码之weibo4andriod.zip项目安卓应用源码下载 1.适合学生毕业设计研究参考 2.适合个人学习研究参考 3.适合公司开发项目技术参考
安卓APP项目-基于Andriod的班级考勤系统的设计-适合计算机毕设、实训项目、大作业学习