Android学习小Demo(19)利用Loader来实时接收短信

之前写过一篇文章《Android学习小Demo(13)Android中关于ContentObserver的使用》,在里面利用ContentOberver去监测短信URI内容的变化。我们先来回顾一下,是如何利用ContentOberver来监测短信内容的变化的。

1)要自定义一个类,比如SmsContentObserver,继承ContentObserver,并且实现其onChange方法。

2)在onChange方法中去查询对应Uri,比如短信收件箱的内容,并将对应的记录利用Handler发送到主界面。

3)在主界面Activity中,要创建一个SmsContentObserver,并且将其注册到ContentReslover中去。

4)在主界面Activity的Handler中获得在SmsContentObserver中变化的消息,更新主界面。

总的来说,过程就大概是这样,大家有兴趣可以看一下这一篇文章。

而本文介绍的是另外一种方法,利用Loader来实现差不多的效果,既然能够说效果差不多,那么就说明了Loader有一个跟ContentObserver的特性,没错,它能够检测到对应内容的变化。

先简单说一下什么是Loader。

Loader是Android在3.0之后才引进的一个类,其主要目的在于让Android跟Data之间的交互变得更加简单和高效,概括起来,我觉得其功能有以下两点:

1)动态监测所处理对象状态的变化,大部分情况下是处理数据,但我觉得只是一方面。

2)当界面变化,需要被重新创建的时候,它们能够重新load到上一次的数据,而不需要再重新进行查询。

当然,它还是异步的,也就意味着不会阻塞到主界面的显示,不过这个功能很多其他的辅助类都有,也就不算啥特点了。

而正是到其第一点的特性,才让我们有机会可以不用那么麻烦去实现一个ContentObserver,而转而来利用Loader来实现相同的功能。

这一次我们做一个展示短信的Demo。当我们打开手机中的短信应用的时候,如果这个时候有新短信进来,我们会看到新短信马上就显示在界面上的,而我们这个Demo也正是如此效果,具体请看(截图大了点,莫怪)。

从上图中可以看到,当我们点击Send按钮的时候,短信发过去,ListView中马上就显示出来刚刚发送的短信。

那么应该怎么使用Loader呢,我们下面来看代码吧。

1)由于Loader是3.0之后才引进来的,所以在3.0之前,如果我们想要使用Loader的时候,主Activity必须要继承FragmentActivity,才能够拿到LoaderManager。

2)要实现LoaderManager的内部接口LoaderCallbacks<D>,这是一个泛型接口,其定义如下:

public interface LoaderCallbacks<D> {
        /**
         * Instantiate and return a new Loader for the given ID.
         *
         * @param id The ID whose loader is to be created.
         * @param args Any arguments supplied by the caller.
         * @return Return a new Loader instance that is ready to start loading.
         */
        public Loader<D> onCreateLoader(int id, Bundle args);

       /**
         * ...
         * @param loader The Loader that has finished.
         * @param data The data generated by the Loader.
         */
        public void onLoadFinished(Loader<D> loader, D data);

        /**
         * Called when a previously created loader is being reset, and thus
         * making its data unavailable.  The application should at this point
         * remove any references it has to the Loader‘s data.
         *
         * @param loader The Loader that is being reset.
         */
        public void onLoaderReset(Loader<D> loader);
    }

所以,我们代码中的第一步就是要实现这个接口,如下:

public class MainActivity extends FragmentActivity implements LoaderCallbacks<Cursor>{
    ...
    private Uri uri = Uri.parse("content://sms/inbox");
    ...
    @Override
	public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
		String[] projection = new String[] {"_id","address","body","type"};

		return new CursorLoader(this, uri, projection, null, null, "date desc");
	}

	@Override
	public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {

		mAdapter.swapCursor(cursor);

	}

	@Override
	public void onLoaderReset(Loader<Cursor> arg0) {
		// TODO Auto-generated method stub

	}

3)要定义一个Uri,因为Loader它必须要从某个地方load数据,而这个Demo中,我们要获取的是收件箱的短信,所以在这里就是拿sms/inbox了。

4)在OnCreateLoader方法中,要创建一个CursorLoader。CursorLoader是AsyncTaskLoader的一个子类,所以它是一个异步的Loader,不会影响到主界面的展示。

5)在OnLoadFinished方法中,对Load完回来存放在cursor的数据进行处理。

上面的接口,只是实现的方式而已,而当调用下面这个方法的时候,Loader才开始真正地发挥作用。在onCreate方法中,

	@Override
	protected void onCreate(Bundle savedInstanceState){
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);

		lvListView = (ListView) findViewById(R.id.lvListView);

		mAdapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_2, null,
				new String[] {"address","body"}, new int[] {android.R.id.text1, android.R.id.text2});
		lvListView.setAdapter(mAdapter);

		getSupportLoaderManager().initLoader(LOADER_ID, null, this);
	}

由于我们是用的support包,所以需要用getSupportLoaderManager类来调用initLoader方法,此方法有三个参数:

a)id,由于一个Activity或者Fragment只有一个LoaderManager,但是一个LoaderManager可以有多个Loader,用来处理不同的数据,所以id在这里能唯一地确定是哪个Loader。

b)bundle,这是传给LoaderManager的参数集合。

c)这是一个LoaderCallbacks的实现类,在这个Demo中,就是此Activity,所以就是this。

6)当调用getSupportLoaderManager().initLoader()方法的时候,Android首先会根据 id 去判断是否已经存在这样的一个loader了,如果存在的话,它就会直接使用已有的loader,而不会去创建一个新的,也就是说,它不会去调用接口方法中的onCreateLoader方法了。而如果不存在对应 id 的Loader,则会去调用onCreateLoader方法,并实例化一个新的Loader出来。

而当对应 id 的loader已经存在的时候,Android会直接load数据,而接口方法中的onLoadFinished也会在数据load完之后马上被调用,这样就会存在一种情况,如果在onLoadFinished方法中使用的变量是在onCreateLoader中才初始化的,那么这个变量根本都没被初始化,就被使用了,程序就会报错了,所以在实际开发中,要考虑到这样一种情况的存在,在 onLoadFinished方法中,要做好一些判断。

最后还有一个onLoaderReset方法,没有被用到,这个方法主要是在Loader不再被使用的时候,被关闭了等情况下,用来释放对Loader的使用的,比如在这个Demo中,如果loader不再用了,那么我们的Adpater就不应该再关联对应的cursor了,那么就可以在这里进行判断。

结束!源代码下载。

Android学习小Demo(19)利用Loader来实时接收短信

时间: 2024-10-09 19:56:56

Android学习小Demo(19)利用Loader来实时接收短信的相关文章

Android学习小Demo(20)关于Fragment的应用

Android在3.0之后引入了Fragment的概念,我猜测其想法可能只是想更好地兼容大屏幕或者平板的开发,因为大屏幕可以展示更多的内容,而内容一多,逻辑有可能就乱,而利用Fragment,则可以将不同的逻辑封装进不同的Fragment中,但是展现呢,还是在同一个Activity中,在同一个屏幕上显示.而对于屏幕并不大的手机来说,如果一个页面展示的东西并不多,那么其实将逻辑直接写在Activity,利用多个Activity实现多个页面的展示,我觉得也是可以接受的,毕竟用Activity还是用F

Android学习小Demo(23)Aidl实现进程间通信

我们知道,Android是靠Binder机制来实现进程间的通信,而上一篇文章中,我们利用AIDL,简单地从代码方面的角度讲解了在服务端中的Binder的存在形式,是以服务的实现存在的,而在客户端,则是以代理的形式,实现存在的只是一个关于服务端的Binder实现的引用. 理论上的东西我们要去学习掌握,但是也不能忽略了实际的动手能力,对吧. 今天,我们就一步一步地利用我们所了解地关于AIDL的知识来实现一个跨进程通信的例子. 在Android的上层应用中,每一个App都是一个单独的进程,所以,要实现

Android学习小Demo(22)带删除按钮的TextView

很多时候,会有一些很简单的需求,比如你利用一个Button弹出某个页面,选择了某个对象之后,你会将对象的某些属性,比如名称之类,显示在按钮上. 而紧跟着,又会想着,能不能把刚选择的对象给清掉,比如把按钮上的文字给去掉,这个时候,你就会希望,要是按钮后面还能够有多一个图标,一点击,就把当前控件的文字等清除掉就好了,并且还会对应的回调函数,让我们多处理一些事情,那多好. 很可惜,Android并没有提供现成的控件供我们这样使用,但换个角度想想,这又根本不可惜,因为我们可以自己来实现这样的效果呀,这是

Android学习小Demo(21)ListView的联动选择

在日常的App开发中,尤其是在开发生活服务的应用上,非常多时候,我们会须要联动地展现省市区的数据等,需求大概例如以下: 1)展现全部省份 2)当点击某省份的时候,在二级菜单上展现此省份以下所属的城市列表 3)选中返回,显示我们选中的城市 4)当又一次进入选择页面的时候,标识出我们上一次选中(或者说当前已经选择)的值 下图是一个类似的ListView联动选择控件. 1)首先定义一个Layout,左右各放置一个ListView,大概界面例如以下: 2)自己定义一个控件(ValuePicker),在控

android学习十四(android的接收短信)

收发短信是每个手机基本的操作,android手机当然也可以接收短信了.android系统提供了一系列的API,使得我们可以在自己的应用程序里接收和发送短信. 其实接收短信主要是利用我们前面学过的广播机制.当手机接收到一条短信的时候,系统会发出一条值为andorid.provider.Telephony.SMS_RECEIVED的广播,这条广播里携带着与短信相关的所有数据.每个应用程序都可以在广播接收器里对它进行监听,收到广播时在从中解析出短信的内容即可. 下面我们来个具体的例子实践下吧,新建一个

利用阿里大于接口发短信(Delphi版)

阿里大于是阿里通信旗下产品,融合了三大运营商的通信能力,提供包括短信.语音.流量直充.私密专线.店铺手机号等个性化服务.每条四毛五,价钱还算公道,经老农测试,响应速度非常快,基本上是秒到.官方文档提供了以下语言的 Demo JAVA .NET PHP Python CURL C/C++ NodeJS 唯独没有 Dephi,这不能怪马云,毕竟 Delphi 实在太小众了. 最近用 Delphi 写个 App,注册用户需要用到手机短信验证,于是找到的阿里大于,使用 Delphi 10.1 berli

Android从普通发送和接收短信到对短信进行拦截

概述: 说实话,关于Android中对短信的一些相关操作是一个比较入门的东西.那我现在还要来写这一篇博客的原因只是因为现在开发中有相关内容,而又想将这些东西分享给更多的人来学习,同时在以后对Android系统的短信进行其他学习的时候也就放在这里做一个记录了,于是就写了这篇啰嗦的文章.如果你觉得这是一个不错的东西,欢迎收藏,以便在以后更方便地查看本人在此篇文章中更新的内容.下面我就从标题中的三个方面来对Android系统中的短信操作进行一个简单地学习. 短信的发送 由于Android中对短信发送方

android基础----&gt;发送和接收短信

收发短信应该是每个手机最基本的功能之一了,即使是许多年前的老手机也都会具备这项功能,而Android 作为出色的智能手机操作系统,自然也少不了在这方面的支持.今天我们开始自己创建一个简单的发送和接收短信的应用. 目录导航 接收短信 发送短信 友情链接 接收短信 项目的结构如下:一个简单的接收和发送短信的功能 一.定义一个接收短信的广播:当手机接收到一条短信的时候,系统会发出一条值为android.provider.Telephony.SMS_RECEIVED 的广播,这条广播里携带着与短信相关的

android接收短信——framework处理流程(android 5.1)

modem层不懂,所以直接从RIL.java开始.以电信卡接收短信为例 modem通知RIL.java中的 RILReceiver处理接收信息 class RILReceiver implements Runnable { byte[] buffer; RILReceiver() { buffer = new byte[RIL_MAX_COMMAND_BYTES]; } @Override public void run() { ...... //建立socked连接,读取数据 processR