软件开发工具:第21章 Android客户端程序架构_第1页
软件开发工具:第21章 Android客户端程序架构_第2页
软件开发工具:第21章 Android客户端程序架构_第3页
软件开发工具:第21章 Android客户端程序架构_第4页
软件开发工具:第21章 Android客户端程序架构_第5页
已阅读5页,还剩29页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、郑州大学信息工程学院第21章 Android客户端程序架构点击添加文本郑州大学信息工程学院21.1 概述 21.2 项目实战:“掌上苏大”21.3 本章小结习题 21本章导读本章导读: Android客户端程序架构的设计是Android应用开发中非常重要的问题,这里应从全局变量的定义和使用、推送的实现、相对完整的基础工具包和核心工具包(类包)的实现、对新版本的监听和自动下载更新的实现、捕获全局异常、后台服务和广播接收机制的实现等诸多方面加以考虑。本章主要知识点有:(1)Android客户端程序架构的含义和具体内容;(2)项目实战:搭建“掌上苏大”APP之Android客户端的整个程序架构。21

2、.1 概述这里“Android客户端程序架构”的含义,是指开发一个Android客户端的应用,从全局的角度应该考虑哪些问题。 一般来说,一个Android客户端应用开发,从全局的角度出发,至少应该考虑到以下方面的问题。(1)全局变量的定义和使用及全局数据配置; (2)推送的实现;(3)对新版本的监听和自动下载更新的实现;(4)相对完整的基础工具包和核心工具包(类包);(5)对客户端各页面点击率的统计及相应数据分析(对用户行为的分析);(6)嵌入广告的实现;(7)Android使用UncaughtExceptionHandler捕获全局异常(线程终止异常处理);(8)Android系统账户的实现

3、;(9)整个应用的后台服务; (10)流量统计;(11)整个应用的缓存实现;(12)整个应用的内存管理以及内存泄漏的避免;(13)整个应用的广播接收机制;(14)整个应用的并发设计模式。等等。笔者将结合“掌上苏大”的开发实例,对Android客户端应用开发涉及到的从全局角度出发应考虑的问题,谈谈自己的一些体会。21.2 项目实战:“掌上苏大” “掌上苏大”是一款校园客户端应用,致力于服务苏州大学的师生,它的特点是贴近校园生活,包含消息中心、跳蚤市场、勤工俭学、校园新闻、苏大周边、交通查询、时事经纬、视频教程、真题库、考研信息、自考助学、课程表、个人中心、网站导航、音乐天地、流量查询、软件管理、

4、设置中心等若干模块,以及二维码扫描功能。21.2 项目实战:“掌上苏大”21.2.1 任务说明搭建“掌上苏大”APP之Android客户端的整个程序架构。21.2.2 整体框架和运行主界面我们在Eclipse ADT中一个创建Android应用:palmsuda_demo3工程,palmsuda_demo3工程(源码)目录结构、Splash界面、运行主界面和退出界面,如图21-1、图21-2和图21-3所示。(详见教学资源光盘code文件夹下第21章palmsuda_demo3工程)21.2 项目实战:“掌上苏大” 图21-1 palmsuda_demo3工程(源码)目录 图21-2 闪屏Sp

5、lash 图21-3 palmsuda_demo3工程主界面和退出界面21.2 项目实战:“掌上苏大”palmsuda_demo3工程中各个包的作用是:(1)com.mialab.palmsuda.main:与整个应用及诸模块相关的主关键类包。(2)com.mialab.palmsuda.base:基础类包。主要包括类BaseActivity等。(3)com.mialab.palmsuda.tools.util:核心工具包(核心类包)。包括SD卡文件读写、一般通用功能(譬如对字符串进行MD5编码、判断网络是否连接、检查服务器端是否有更新的版本等)实现、异步获取网络数据等等的相关类。(4)com

6、.mialab.palmsuda.tools.ivache:关于缓存实现和异步加载网络图片的核心工具包(核心类包)。这里也涉及到避免内存泄漏的问题。(5)mon:通用包。主要包括常量类Constants。(6)com.mialab.palmsuda.modules:主要是与单个模块相关的类包。(7)com.mialab.palmsuda.sercice:与整个应用的后台服务和广播接收器相关的类包。(8)com.mialab.palmsuda.syncauth:与Android系统账户实现相关的类包。(9)com.mialab.palmsuda.views:与自定义视图及视图控件相关的类包。21

7、.2 项目实战:“掌上苏大”21.2.3 Android全局对象ApplicationAndroid系统在运行每一个程序应用的时候,都会创建一个Application对象,用于存储与整个应用相关的公共变量。一个Android应用只会生成一个Application对象,在不同的Activity中获取的Application对象是一样的,所以Application对象是一个单例(SingleTon)。Application对象非常适合用于存储一些与整个应用相关数据,例如应用版本、应用登录账户、数据缓存等。所以可以通过继承Application类来实现应用程序级的全局变量。在palmsuda_dem

8、o3工程中,我们创建类PalmSudaApp继承android.app.Application并在AndroidManifest.xml文件中的application标签中进行注册。PalmSudaApp的onCreate()方法是该整个应用的入口点。主要代码如下:21.2 项目实战:“掌上苏大”public class PalmSudaApp extends Application private static final String TAG = Constants.APP_TAG;private static PalmSudaApp app = null;private SharedPr

9、eferences settings;private ServiceManager serviceManager;public static String versionName = ;public static int SCREEN_WEIDTH = 0;public static int SCREEN_HEIGTH = 0;public static PalmSudaApp getInstance() return app;Overridepublic void onCreate() super.onCreate();app = this;Log.d(TAG, This is PalmSu

10、da App.);CrashHandler crashHandler = CrashHandler.getInstance();crashHandler.init(getApplicationContext();settings = getSharedPreferences(APP_SETTING, Application.MODE_PRIVATE);SCREEN_WEIDTH = getResources().getDisplayMetrics().widthPixels;SCREEN_HEIGTH = getResources().getDisplayMetrics().heightPix

11、els;serviceManager = new ServiceManager(this);serviceManager.setNotificationIcon(R.drawable.notification);serviceManager.startService();bindReceiver(20); 21.2 项目实战:“掌上苏大”21.2.4 整个应用的线程终止异常处理Thread的run方法是不抛出任何检查型异常(checked exception)的,但是它自身却可能因为一个异常而被终止,导致这个线程的终结。最麻烦的是,在线程中抛出的异常即使使用try.catch也无法截获,因此可

12、能导致一些问题出现,比如发送异常的时候无法回收一些系统资源,或者没有关闭当前的连接等等。 JDK5之前,不能为单独的Thread设置UncaughtExceptionHandler,也不能指定一个默认的UncaughtExceptionHandler。为了可以设置一个UncaughtExceptionHandler,需要去继承ThreadGroup并覆写uncaughtException方法。在JDK5及以上版本中,我们可以通过Thread的实例方法setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh),为任何一个Thre

13、ad设置一个UncaughtExceptionHandler。当然你也可以为所有Thread设置一个默认的UncaughtExceptionHandler,通过调用Thread.setDefaultUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh)方法,这是Thread的一个static方法。 21.2 项目实战:“掌上苏大”我们把Thread的以下四个方法和一个接口看一下:(1)Thread.UncaughtExceptionHandler getUncaughtExceptionHandler()方法:返回该线程由于未捕

14、获到异常而突然终止时调用的处理程序。(2)void setUncaughtExceptionHandler(Thread.UncaughtExceptionHandler eh) 方法: 设置该线程由于未捕获到异常而突然终止时调用的处理程序。(3)static Thread.UncaughtExceptionHandler getDefaultUncaughtExceptionHandler()方法: 返回线程由于未捕获到异常而突然终止时调用的默认处理程序。(4)static void setDefaultUncaughtExceptionHandler(Thread.UncaughtExce

15、ptionHandler eh) 方法:设置当线程由于未捕获到异常而突然终止,并且没有为该线程定义其他处理程序时所调用的默认处理程序。(5)static interface Thread.UncaughtExceptionHandler接口:当 Thread因未捕获的异常而突然终止时,调用处理程序的接口。这要求我们定义一个Handler类时,必须实现Thread.UncaughtExceptionHandler接口的void uncaughtException(Thread t,Throwable e)方法。如果不设置一个Handler,那么单个Thread的Handler是null。但是,如

16、果这个单个线程是ThreadGroup中的一个Thread,那么这个线程将使用ThreadGroup的UncaughtExceptionHandler。ThreadGroup自身已经实现了Thread.UncaughtExceptionHandler接口。21.2 项目实战:“掌上苏大”uncaughtException(Thread a, Throwable e)可以拿到Thread,所以在uncaughtException释放相关资源是最好的办法。palmsuda_demo3工程中的类CrashHandler主要代码如下:public class CrashHandler implemen

17、ts UncaughtExceptionHandler public static final String TAG = Constants.APP_TAG;private Thread.UncaughtExceptionHandler mDefaultHandler;private static CrashHandler INSTANCE = new CrashHandler(); / CrashHandler实例private CrashHandler() public static CrashHandler getInstance() return INSTANCE;public voi

18、d init(Context context) mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();Thread.setDefaultUncaughtExceptionHandler(this);Overridepublic void uncaughtException(Thread thread, Throwable ex) 21.2 项目实战:“掌上苏大”21.2.5 程序主要流程1PalmSudaApp的onCreate()方法程序的入口是PalmSudaApp的onCreate()方法,在onCreate()方法里

19、:创建了CrashHandler实例,并调用其实例方法init(),为整个应用的线程设置了线程终止异常处理器;继而通过ServiceManager启动了后台的Service,并周期性触发广播接收器StartServiceRecevier的onReceive()方法。2Splash的onCreate()方法然后程序流程转到闪屏Splash的onCreate()方法,Splash主要代码如下:Splash界面延迟8秒后,通过Splash中的Handler运行SplashHandler的run()方法,调用gotoPalmHome()方法,加载主界面PalmSudaHome。21.2 项目实战:“掌

20、上苏大”public class Splash extends Activity private Handler handler = new Handler();Overrideprotected void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState);requestWindowFeature(Window.FEATURE_NO_TITLE);/设置为无标题栏getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowM

21、anager.LayoutParams.FLAG_FULLSCREEN); /设置为全屏模式setContentView(R.layout.splash);/ 获取当前版本,并设置在启动界面的TextViewthis.getCurrentVersion();/ 延迟8秒,再运行SplashHandler的run()方法handler.postDelayed(new SplashHandler(), 8000);class SplashHandler implements Runnable Overridepublic void run() gotoPalmHome();private void

22、 gotoPalmHome() /加载主界面Intent intent = new Intent(this, PalmSudaHome.class);startActivity(intent);finish();/ 把当前的Activity从任务栈里面移除21.2 项目实战:“掌上苏大”3主界面PalmSudaHome的onCreate()方法这时程序流程转到PalmSudaHome的onCreate()方法,PalmSudaHome主要代码如下:public class PalmSudaHome extends BaseActivity private MainViewHelper mVie

23、wHelper;private SharedPreferences settings;Overrideprotected void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState);setContentView(R.layout.palm_main);settings = PalmSudaApp.getInstance().getSettings(); /获取本地设置文件mViewHelper = new MainViewHelper(this);loadData();private void load

24、Data() PalmSudaApp.contentId = ;if (TextUtils.isEmpty(PalmSudaApp.contentId) handleMainView(10285, 苏州大学, true, false);21.2 项目实战:“掌上苏大”private void handleMainView(final String contentid, final String addr,final boolean isfirst, final boolean isSwitch) MaintainMgr.getInstance().getModuleList(contentid

25、, addr, versionName,isfirst, new MaintainMgr.ContentReadyCallback() Overridepublic void dataReady(Object data) if (data != null) aItem = (ContentItem) data;setMainView(aItem, isSwitch); else showToast(没有获得数据,请查看网络是否通畅!););private void setMainView(ContentItem aItem, boolean isSwitch) mViewHelper.setC

26、otentItem(aItem);21.2 项目实战:“掌上苏大”由以上代码,我们看到以下的流程:PalmSudaHome的onCreate()方法loadData()方法handleMainView(final String contentid, final String addr,final boolean isfirst, final boolean isSwitch)方法MaintainMgr.getInstance().getModuleList(final String contentId, final String content Address, final String ve

27、rsion,final boolean isfirst, final ContentReadyCallback aCallback)方法。必须注意到:MaintainMgr.getInstance()的getModuleList()方法的签名表明,一旦成功获得数据,将进行回调,回调的是PalmSudaHome的setMainView(ContentItem aItem, boolean isSwitch)方法,继而调用了MainViewHelper的setContentItem(ContentItem aItem)方法,使数据(包括远程数据,譬如表示模块的小图标)在手机的主界面显示出来。21.

28、2 项目实战:“掌上苏大”4MaintainMgr.getInstance()的getModuleList()方法获得数据MaintainMgr.getInstance()的getModuleList()方法使用线程池ExecutorService实例中的线程执行实现Runnable接口的任务(即执行Run方法中的代码)MaintainMgr的getAssetModuleList(String contentId)方法(注意传进去的参数是10285)MaintainMgr的getFromAsset(Context context, String fileName)方法(注意传进去的文件名fil

29、eName是datas/ 10285.txt,10285.txt是json数据,存储路径是assets目录下的datas文件夹。)MaintainMgr的getContentItem(String src, boolean isSave, String filename)方法(把json数据封装到ContentItem实体对象中)。(说明:这里为了方便起见,并没有从后台数据库中取数据,而是把数据放到了10285.txt中,并且是json格式。实际开发中并非如此,而要进行后台接口的编写,通过提供API接口,把后台数据库中的数据转换成json格式数据,以供手机客户端访问,如第18章服务器端接口编程

30、所述。)主管理类MaintainMgr的主要代码如下:21.2 项目实战:“掌上苏大”public class MaintainMgr private static MaintainMgr mgr;private ContentItem mContentItem;private PalmSudaApp app = PalmSudaApp.getInstance();private ExecutorService executorService = null;private MaintainMgr() executorService = Executors.newFixedThreadPool(

31、6);public static MaintainMgr getInstance() if (mgr = null) mgr = new MaintainMgr();return mgr;public void getModuleList(final String contentId,final String contentAddress, final String version,final boolean isfirst, final ContentReadyCallback aCallback) final Handler handler = new Handler() public v

32、oid handleMessage(Message message) aCallback.dataReady(message.obj);21.2 项目实战:“掌上苏大”executorService.execute(new Runnable() Overridepublic void run() try String src = null;ContentItem contentItem = null;if (contentItem = null) src = getAssetModuleList(contentId);contentItem = getContentItem(src, fals

33、e, );if (contentItem != null) mContentItem = contentItem;handler.sendMessage(Message.obtain(handler, 0, contentItem); catch (Exception e) handler.sendMessage(Message.obtain(handler, 0, mContentItem);android.util.Log.e(hand, content item-, e););private ContentItem getContentItem(String src, boolean i

34、sSave, String filename) private String getAssetModuleList(String contentId) throws IOException return getFromAsset(app, datas/ + contentId + .txt);public String getFromAsset(Context context, String fileName) throws IOException public interface ContentReadyCallback public void dataReady(Object data);

35、21.2 项目实战:“掌上苏大”5回调MainViewHelper的setContentItem(ContentItem aItem)方法MainViewHelper的setContentItem(ContentItem aItem)方法MainViewHelper的notifyDataChange()方法MainViewHelper的setFlipperView(List gridItems)方法和setBarView(List barItems)方法手机界面上显示出相应的图片和文字。(参见教学资源光盘code文件夹下第21章palmsuda_demo3工程中主界面帮助类MainViewHe

36、lper.java的代码)。21.2 项目实战:“掌上苏大”21.2.5 推送的实现推送实现的步骤如下:(1)先把教学资源光盘code文件夹下第21章的asmack.jar和mialab-pushlib.jar两个jar文件拷贝到palmsuda_demo3工程中libs目录下。(2)在AndroidManifest.xml文件中的application标签下注册NotificationService和NotificationDetailsActivity。 21.2 项目实战:“掌上苏大”(3)在com.mialab.palmsuda.service包中创建ServiceManager类,在

37、ServiceManager类中添加startService()和startNotificationService()两个方法,在ServiceManager的startService()方法中添加调用startNotificationService()方法的代码。(4)在PalmSudaApp的onCreate()方法中创建ServiceManager实例,并添加调用ServiceManager的startService()实例方法,(代码详见教学资源光盘code文件夹下第21章palmsuda_demo3工程中的PalmSudaApp.java和ServiceManager.java。)(

38、5)把教学资源光盘code文件夹下第14章消息推送目录下的mialabpush.war拷贝到Tomcat服务器的webapps目录下,启动Tomcat服务器。(mialabpush.war的部署同第14章消息推送。)(6)如图21-4所示,在mialabpush的控制台输入要推送的消息,便可实现推送。21.2 项目实战:“掌上苏大”图21-4 mialabpush控制台 图21-5 客户端显示推送消息如图21-5所示,手机客户端显示推送消息。21.2 项目实战:“掌上苏大”21.2.6 整个应用的后台服务和广播接收机制在PalmSudaApp的onCreate()方法中调用ServiceMan

39、ager实例方法startService(),并通过bindReceiver(20);的调用,周期性触发StartServiceRecevier的onReceive()方法。public class PalmSudaApp extends Application private ServiceManager serviceManager;Overridepublic void onCreate() serviceManager = new ServiceManager(this);serviceManager.setNotificationIcon(R.drawable.notificatio

40、n);serviceManager.startService();bindReceiver(20);21.2 项目实战:“掌上苏大”public void bindReceiver(int minutes) Log.d(bindReceiver, #bindReceiver: repeat minutes= + minutes);Intent intent = new Intent(PalmSudaApp.getInstance(),StartServiceRecevier.class);intent.setAction(start.service.receiver.action);Alarm

41、Manager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);if (sender != null) am.cancel(sender); else sender = PendingIntent.getBroadcast(PalmSudaApp.getInstance(), 0,intent, PendingIntent.FLAG_UPDATE_CURRENT);long trigerTime = System.currentTimeMillis() + 300000+ (long) (300000 * Math.ran

42、dom();if (Constants.TEST_MODE | Constants.DEBUG_MODE) minutes = 3;trigerTime = System.currentTimeMillis() + 90000;am.setRepeating(AlarmManager.RTC_WAKEUP, trigerTime, minutes * 60000,sender);21.2 项目实战:“掌上苏大”ServiceManager的startService()方法调用相关代码如下:public final class ServiceManager private Context con

43、text;private Properties props;private String apiKey;private String xmppHost;private String xmppPort;public ServiceManager(Context context) this.context = context;props = loadProperties();apiKey = props.getProperty(apiKey, );xmppHost = props.getProperty(xmppHost, );xmppPort = props.getProperty(xmppPo

44、rt, 5222);private Properties loadProperties() Properties props = new Properties();try int id = context.getResources().getIdentifier(pushclient, raw,context.getPackageName();props.load(context.getResources().openRawResource(id); catch (Exception e) Log.e(LOGTAG, Could not find the properties file., e

45、);return props;public void startService() startNotificationService();startBackService();21.2 项目实战:“掌上苏大”public void startNotificationService()Thread serviceThread = new Thread(new Runnable() Overridepublic void run() Intent intent = NotificationService.getIntent();context.startService(intent););serv

46、iceThread.start();public void startBackService() Log.d(LOGTAG, startBackService.);Intent intent = new Intent(com.mialab.palmsuda.service.BackService);context.startService(intent);context.bindService(intent, connection, Context.BIND_AUTO_CREATE);private BackService backService;private ServiceConnection connection = new ServiceConn

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论