Android更新UI的两种方法——handler与runOnUiThread()
1、Intent传递对象方式:
Serializable
Parcelable
2、全局Context获取:
Android提供了一个Application类,每当应用程序启动时,系统会自动将这个类初始化。我们可以定义个一个自己的Application,用户管理程序内的一些全局状态信息。
4、异步消息处理:
Message、Handler、MessageQueue(消息队列)、Looper
每个线程只有一个MessageQueue对象、Looper对象
通过Handler发送了消息后,该Message会被添加到MessageQueue队列中等待被处理,Looper一直尝试从MessageQueue队列取出待处理消息,分发回Handler的handleMessge()方法中。
在主线程创建之后会创建一个Looper对象,创建Looper对象的时候会去创建一个messageQueue,而Looper是一个轮询器,会不停的轮询messageQueue中的消息,在获取到消息之后就会把这个消息交给handler来进行处理,在主线程中创建一个handler对象,这个handler对象不仅可以获取到消息进行处理,也可以把一个消息放到消息队列中。
Message、Handler、MessageQueue、Looper之间的关系
Android消息处理机制(Handler、Looper、MessageQueue与Message)
Android异步消息处理机制~深入理解 Looper、Handler、Message三者关系
Android Handler 异步消息处理机制的妙用~创建强大的图片加载类
5、在Android中实现异步任务机制有两种方式,Handler和AsyncTask。
Handler模式需要为每一个任务创建一个新的线程,任务完成后通过Handler实例向UI线程发送消息,完成界面的更新,这种方式对于整个过程的控制比较精细,但也是有缺点的,例如代码相对臃肿,在多个任务同时执行时,不易对线程进行精确的控制。为了简化操作,Android1.5提供了工具类AsyncTask抽象类,它使创建异步任务变得更加简单,不再需要编写任务线程和Handler实例即可完成相同的任务。
详解Android中AsyncTask的使用(包含源码解析)
6、Service:
<1>、新建一个DownloadBind内部类继承Bind类,通过DownloadBind类对象实现与活动绑定交互。
在Activity里,实例化ServiceConnection接口的实现类,重写onServiceConnected()和onServiceDisconnected()方法
绑定:
bindService(intent, conn,BIND_AUTO_CREATE);
BindService和Started Service都是Service,有什么地方不一样呢:
1. Started Service中使用StartService()方法来进行方法的调用,调用者和服务之间没有联系,即使调用者退出了,服务依然在进行【onCreate()- >onStartCommand()->startService()->onDestroy()】,注意其中没有onStart(),主要是被onStartCommand()方法给取代了,onStart方法不推荐使用了。
2. BindService中使用bindService()方法来绑定服务,调用者和绑定者绑在一起,调用者一旦退出服务也就终止了【onCreate()->onBind()->onUnbind()->onDestroy()】。
bindService()启动service的生命周期和调用bindService()方法的Activity的生命周期是一致的,也就是如果Activity如果结束了,那么Service也就结束了。Service和调用bindService()方法的进程是同生共死的。好的编程习惯,都是在Activity的onStop()方法中加上unBindService(ServiceConnection conn)代码
<2>、前台服务
服务的优先级比较低,当内存不足时,系统会回收掉正在后台运行的服务。如果希望服务一直保持运行状态,就需要用前台服务。
譬如墨迹天气一直在通知栏展示天气情况
<3>、异步的自动停止的服务
服务默认运行在主线程中,如果处理的任务比较耗时,就会出现ANR(Application Not Responding),所以需要在服务的处理方法中开启一个线程。
public int onStartCommand(Intent intent,int flags, int startId){ new Thread(new Runnable(){ public void run(){ //执行完毕后自动停止 stopSelf(); } }).start(); return super.onStartCommand(intent,flags,startId); }
这种方法容易忘记开启线程,或者容易忘记执行stopSelf(),所以Android提供了IntentService类,继承其即可。
<4>、Android定时任务的两中方式:JavaAPI里的Timer类,Android的Alarm机制。
Timer方法不适合长期在后台运行的定时任务,因为手机CPU会休眠,就无法执行。
Alarm机制可以唤醒CPU。
启动服务后,定时跳转到一个广播接收器中,接收到时再跳转到服务中。
7、Handler、HandlerThread
Handler:
一般来说在子线程中执行耗时任务,当任务完成时,会返回UI线程,一般是更新UI。这时有两种方法可以达到目的。
一种是子线程handler.sendMessage发一个消息,主线程接收,然后更新UI。
另一种是handler.post(r)。r是要执行的任务代码。意思就是说r的代码实际是在UI线程执行的。可以写更新UI的代码。(子线程是不能更新UI的)
handler可以分发Message对象和Runnable对象到主线程中, 每个Handler实例,都会绑定到创建他的线程中(一般是位于主线程), 也就是说Handler对象初始化后,就默认与对它初始化的进程的消息队列绑定。
Handler handler = new Handler(); /**该方法的内部类将在handler.sendMessage(msg)后执行 Handler handler = new Handler(){ @Override public void handleMessage(Message msg){ System.out.println("msg:"+msg.arg1); } };*/
HandlerThread
Android中Handler的使用,一般都在UI主线程中执行,因此在Handler接收消息后,处理消息时,不能做一些很耗时的操作,否则将出现ANR错误。Android中专门提供了HandlerThread类,来解决该类问题。
HandlerThread类继承自Thread,专门处理Hanlder的消息,依次从Handler的队列中获取信息,逐个进行处理,保证安全,不会出现混乱引发的异常。HandlerThread继承于Thread,所以它本质就是个Thread。与普通Thread的差别就在于,它有个Looper成员变量。
首先Handler和HandlerThread的主要区别是:Handler与Activity在同一个线程中,HandlerThread与Activity不在同一个线程,而是在新的线程中(Handler中不能做耗时的操作)。
<1>、创建一个HandlerThread,即创建了一个包含Looper的线程。
HandlerThread handlerThread = new HandlerThread("leochin.com");
handlerThread.start();
//创建HandlerThread后一定要记得start()
<2>、获取HandlerThread的Looper
Looper looper = handlerThread.getLooper();
<3>、创建Handler,通过Looper初始化
Handler handler = new Handler(looper);
通过以上三步我们就成功创建HandlerThread。通过handler发送消息,就会在子线程中执行。
如果想让HandlerThread退出,则需要调用handlerThread.quit()。
8、通知Notification
PendingIntent延迟执行的Intent
在MainActivity里发出通知,点击时进入NoticationActivity中
NotificationManager manager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); Notification notification = new Notification(R.drawable.ic_launcher,"This is ticket text",System.currentTimeMillis()); Intent intent = new Intent(this,NoticationActivity.class); PendingIntent pi = PendingIntent.getActivity(this, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT); notification.setLatestEventInfo(this, "This is content title", "This is content text",pi); manager.notify(1, notification);
接收到通知后调用manager.cancel(1)可取消通知。
接收、发送、拦截短信
发送短信:
<1>、MainActivity中注册接收通知广播
为防止自定义MessageReceiver和系统默认短信程序都接收到短信,可设置自定义MessageReceiver的优先级,然后拦截短信广播即可
IntentFilter receiveFilter = new IntentFilter(); receiveFilter.addAction("android.provicer.Telephony.SMS_RECEIVED"); //receiveFilter.setPriority(100); MessageReceiver messageReceiver = new MessageReceiver(); registerReceiver(messageReceiver,receiveFilter);
<2>、点击按钮时发送
SmsManager manager = SmsManager.getDefault(); manager.sendTextMessage(to.getText().toString(), null , msgInput,getText().toString() ,null,null); /** * 监控发送状态(发送时第四个参数为PendingIntent) * SmsManager manager = SmsManager.getDefault(); * Intent sentIntent = new Intent("SEND_SMS_ACTION"); * PendingIntent pi = PendingIntent.getBroadcast(MainActivity.this,0,sentIntent,0); * manager.sendTextMessage(to.getText().toString(), null , msgInput,getText().toString() , pi, null); * * 注册时: * IntentFilter receiveFilter = new IntentFilter(); * receiveFilter.addAction("SEND_SMS_ACTION"); * SendStatusReceiver sendStatusReceiver = new SendStatusReceiver(); * registerReceiver(sendStatusReceiver,receiveFilter); */
接收短信:
使用广播接收器BroadcastReceiver(自定义一个MessageReceiver)来接收短信
class MessageReceiver extends BroadcastReceiver{...} //class SendStatusReceiver extends BroadcastReceiver{...}
调用摄像头拍照
从相册中选择图片
播放音频、视频
9、内容提供其Content Provider
为存储和获取数据提供统一的接口。可以在不同的应用程序之间共享数据。
URI:
权限(authority/包名) + 路径(path/表名)
标准URI:
content://包名/表名
字符串转URI:
Uri uri = Uri.parse(标准URI)
匹配内容URI:
UriMatcher uriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
uriMatcher.addURI("权限","路径","自定义代码");
uriMatcher.match(uri):返回自定义代码
读取系统联系人
getContentResolver().query()..
创建自己的内容提供器
新建类继承ContentProvider即可,注意需要在AndroidMainTest.xml中注册
getType():
获取URI对象对应的MIME类型
URI对应的MIME字符串有三部分组成:
<1>、必须以vnd开头
<2>、如果URI以路径结尾,后接android.cursor.dir/;如果URI以ID结果,后接android.cursor.item/
<3>、最后接上 vnd.权限.路径
例:
URI: content://com.example.app.provider/table1
MIME为:vnd.android.cursor.dir/vnd.com.example.app.provider.table1
URI:content://com.example.app.provider/table1/1
MIME为:vnd.android.cursor.item/vnd.com.example.app.provider.table1
10、数据存储
<1>、文件存储
存储:openFileOutput("文件名","操作模式")
默认存储在/data/data/<package name>/files/目录下
读取:openFileInput("文件名")
new Scanner方式和new BufferReader方式
自动到/data/data/<package name>/files/目录下读取文件
<2>、SharedPreference存储
键值对存储
a、调用SharedPreference对象的edit()方法获取一个SharedPreference.Editor对象
b、向SharedPreference.Editor对象中添加数据 putString..putInt..
c、commit()提交
读取:SharedPreference对象提供的getString..getInt..
范例:记住密码功能
适用范围:保存少量的数据,且这些数据的格式非常简单:字符串型、基本类型的值。比如应用程序的各种配置信息(如是否打开音效、是否使用震动效果、小游戏的玩家积分等)等
<3>、数据库存储
自定义类继承SQLiteOpenHelper抽象类
数据库文件默认存储在/data/data/<package name>/databases/目录下
调用getReadableDatabase()或getWritableDatabase()可以创建或打开一个数据库
查询时别忘了调用cursor的close()方法释放数据库连接
范例:升级数据库的最佳写法
11、广播Broadcast
标准广播
没有先后顺序,所有广播接收器几乎都在同一时刻接收到该广播消息
有序广播
有先后顺序,同一时刻只有一个广播接收器可收到该消息
发送标准广播
Intent intent = new Intent("com.example.MY_BROADCAST");
sendBroadcast(intent);
发送有序广播
先后顺序判定标准遵循为:将当前系统中所有有效的动态注册和静态注册的BroadcastReceiver按照priority属性值从大到小排序,对于具有相同的priority的动态广播和静态广播,动态广播会排在前面。
Intent intent = new Intent("com.example.MY_BROADCAST");
sendOrderedBroadcast(intent,null);
创建广播接收器
自定义类继承BroadcastReceiver抽象类
默认情况下,广播接收器也是运行在UI线程,因此,onReceive方法中不能执行太耗时的操作。否则将因此ANR。一般情况下,根据实际业务需求,onReceive方法中都会涉及到与其他组件之间的交互,如发送Notification、启动service等。
当广播接收者onReceive方法需要执行很长时间时,最好将此耗时工作通过Intent发送给Service,由Service完成,并且不能使用子线程解决,因为BroadcastReceiver是接收到广播后才创建的,并且生命周期很短,因此子线程可能在没有执行完就已经被杀死了。
截断广播
在广播接收器的onReceive()中使用abortBroadcast()
注册广播方式
动态注册:在代码里注册
必须程序启动才能接收广播
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE"); //网路发生变化时,系统发出的值为该Action的系统广播
NetworkChangeReceiver receiver = new NetworkChangeReceiver();//自定义的广播接收器类
registerReceiver(receiver,intentFilter);
注意在onDestory()方法中取消注册:unregisterReceiver(receiver);
静态注册:在AndroidManifest.xml里注册
程序不启动也可接收广播
<receiver android:name=".NetworkChangeReceiver"> <intent-filter android:priority="100"> <!-- 有序广播需要加该参数--> <action android:name="android.net.conn.CONNECTIVITY_CHANGE"/> </intent-filter> </receiver>
使用本地广播
使用LocalBroadcastManager来对广播进行管理
对于LocalBroadcastManager方式发送的应用内广播,只能通过LocalBroadcastManager动态注册的ContextReceiver才有可能接收到(静态注册或其他方式动态注册的ContextReceiver是接收不到的)。
LocalBroadcastManager manager = LocalBroadcastManager.getInstance(this);
manager.sendBroadcast(intent);
manager.unregisterReceiver(receiver);
..
范例:广播最佳实践-实现强制下线功能
思路:在界面上弹出一个对话框,让用户无法进行其他操作,必须点击对话框中的确定按钮,然后回到登录界面即可
在LoginActivity登录后,跳转到登录成功主界面MainActivity,在MainActivity中点击按钮发出强制下线广播,跳转到登录界面
LoginActivity -> MainActivity -> ForceOfflineReceiver -> LoginActivity
12、
=============================================================================
天气APP总结
文件夹:
activity
db
model
service
receiver
util
建库:
CoolWeatherOpenHelper.java --> SQLiteOpenHelper
Model:
Province.java
City.java
Country.java
数据库操作类:
CoolWeatherDB.java
单例模式
saveProvince(Province province)..
loadProvince()..
服务器交互:
HttpUtil.java
通过URL取数据
sendHttpRequest(final String address,final HttpCallbackListener listener);
新建一个线程发送请求
HttpCallbackListener
回调服务接口,定义两个方法onFinish、onError
工具类解析数据:
Utility.java
返回的数据格式为"代号|城市,代号|城市"
解析数据后保存到数据库
handleProvincesResponse(CoolWeatherDB coolWeatherDB ,String response)
handleCitiesResponse(CoolWeatherDB coolWeatherDB ,String response ,int provinceId)
...
取到天气数据后,将数据保存到本地SharedPreferences
handleWeatherResponse(Context context , String respone)
saveWeatherInfo(..)
选择省、市、县活动:
CoolWeatherActivity.java
queryFromServer(final String code , final String type )
queryFromServer(null , "province" )
queryFromServer(selectProvince.getProvinceCode() , "city" )
调用HttpUtil中方法取数据,取到数据后通过runOnUiThread回到主线程处理逻辑
runOnUiThread是Activity内部的方法
展示天气活动:
WeatherActivity.java
有县code时直接从本地取,没有时通过URL获取
直接显示:showWeather()
后台自动更新天气:
AutoUpdateService.java -> Service
在onStartCommand里启动一个线程,通过HttpUtil取到最新的天气,然后更新updateWeather(更新SharePreferences)
启动一个定时任务,跳转到通知AutoUpdateReceiver.java
在通知的onReceive()方法里再跳转到服务AutoUpdateService里并启动
相关推荐
在这个文档中,宋志豪同学可能详细记录了他如何利用存储扩展原理设计和实现了一个汉字字库存储方案,包括遇到的问题、解决方案以及实验验证的过程。 总的来说,这个实验不仅涉及理论知识,还要求实践操作,通过这样...
总结来说,实现"一行代码即可监听App中所有网络链接的上传以及下载进度",需要以下步骤: 1. 针对网络请求库(如OkHttp),创建一个拦截器来监听上传/下载进度。 2. 对于Glide,创建自定义的`ProgressListener`或`...
### 低代码与无代码的总结大全 #### 一、定义 - **低代码(Low-Code)**:低代码是一种高效快速的应用程序开发方法,它最大限度地减少了编写传统代码的需求,转而采用图形化界面和直观的拖放操作来构建逻辑流程。...
总结一下,这个“VB代码视图鼠标滚轮扩展”是一个针对Visual Basic 6 IDE的第三方插件,它利用DLL技术实现了鼠标滚轮在代码编辑窗口中的滚动功能,提高了程序员的工作效率。用户需要按照一定的步骤安装和启用此扩展...
总结来说,NocoBase是一个全面的无代码/低代码开发平台,它以其易扩展性和丰富的功能,为用户提供了快速构建企业级应用的可能。无论是对于希望简化开发流程的小型企业,还是需要高度定制化解决方案的大企业,...
XPCOM的接口由XPIDL(Interface Definition Language)定义,它不仅提供了核心组件和类别,如档案和内存管理、线程、基本数据结构,还支持通过第三方平台或应用程序甚至扩展套件提供组件。 #### 二、源代码分析结果...
在80C51中,片外ROM和RAM的扩展可以通过线选法实现,它们共享数据总线和地址总线,而访问控制由不同的信号和指令区分,比如访问片外ROM时,ALE信号会出现两次,表示在一个机器周期内可以处理两条指令代码。...
总结来说,"org.holon.statistic.lines_1.0 2.0"是一款强大的Eclipse插件,它为开发者提供了关于代码行数和注释行数的详细统计,有助于提升开发效率,确保代码的可读性和可维护性。在软件开发的各个环节,这样的工具...
这意味着循环将在遇到第一个`.`时停止,即文件扩展名的起始位置。 3. **返回结果**:`Filename2 = Left(PathName, x - 1)`这行代码用于获取从文件名的起始位置到`.`之前的字符串,并作为函数的返回值。这里使用了`...
本教程将介绍如何通过一行代码轻松实现Android视频和音频播放,并实现全屏功能。这个方法适用于各种Android项目,目标是成为Android平台上最简便、最广泛使用的视频播放解决方案。 首先,我们要引入关键的库,...
【标题解析】:“第五届阿里中间件性能挑战赛复赛第6名代码+比赛总结”这个标题揭示了这是一个关于编程竞赛的资源,包含了在阿里中间件性能挑战赛复赛中获得第六名的参赛队伍的源代码以及他们对比赛的总结。...
总结起来,统计C#代码行数可以通过多种方式实现,包括利用Visual Studio的内置功能、第三方工具,以及编写自定义脚本。根据具体需求和项目规模,可以选择最合适的解决方案。在进行代码行数统计时,也要考虑到代码...
总结一下,"tid-kijyun-XcodeSourceEditorExtension-Alignment-0cc9572"是一个专为Swift开发设计的Xcode源代码编辑器扩展,其主要功能是对齐赋值语句,以优化代码的可读性和整洁度。它有助于开发者遵循良好的编码...
4. 构筑测试体系:包括自测试代码的价值、待测试的示例代码、第一个测试、再添加一个测试、修改测试夹具、探测边界条件、测试远不止如此等。 5. 重构名录:包括重构的记录格式、挑选重构的依据等。 6. 第一组重构:...
5. 验证安装:通过运行一段简单的PHP代码来检查intl扩展是否成功安装,例如: ```php phpinfo(); ``` 运行此脚本,如果页面中显示有“intl”部分,说明扩展已正确安装。 关于标签中的“phpstudy”,它是...
其在国内BI市场上具有领先地位,并且连续多年在市场份额上保持第一的位置。帆软软件的主要产品包括: - **FineReport**:一款以IT为中心的预定义报表平台,适用于复杂的报表参数查询、数据填报等场景。 - **FineBI**...
1. **下载安装**:从官方渠道或第三方市场(如Chrome Web Store)下载xdebug helper-1.4.3.crx文件,拖拽到Chrome浏览器的扩展管理页面进行安装。 2. **配置Xdebug**:在服务器端的php.ini文件中配置Xdebug,确保其...
通过以上分析,我们可以总结出,该实验旨在利用Logisim这一工具设计并实现一个汉字字库存储芯片的扩展方案。实验中不仅涉及到了存储技术本身,还包含了大量基础的数字电路设计知识,如逻辑门的设计、信号传输路径的...
第一步 下载PHP的源代码,如php-5.4.16。解压后进入php-5.4.16\ext目录。输入 ./ext_skel –extname=myext,myext就是扩展的名称,执行后生成myext目录。 ext_skel是PHP官方提供的用于生成php扩展骨架代码的工具。 ...
为了实现“一行代码”生成验证码,我们可以借助第三方库,如`com.github.lzyzsd:circleimageview:2.2.0`(虽然这个库主要用于圆形图片,但也可以通过自定义扩展实现验证码功能)。 以下是一行代码实现验证码的核心...