zoukankan      html  css  js  c++  java
  • 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内部已经帮我们实现了一个ContentObserver,所以不须要我们再自己去实现。

    先简单说一下什么是Loader。

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

    1)动态监測所处理对象状态的变化,大部分情况下是处理数据,但我认为仅仅是一方面。

    2)当界面变化,须要被又一次创建的时候,它们可以又一次load到上一次的数据,而不须要再又一次进行查询。

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

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

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



    从上图中能够看到,当我们点击Sendbutton的时候,短信发过去,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了,那么就能够在这里进行推断。

    结束!源码下载。



  • 相关阅读:
    windows 的文件夹映射实现
    项目管理工具
    SSM(Spring+SpringMVC+MyBatis)高并发优化思路
    高性能高可用高并发技术架构的一些理解
    你懂什么是分布式系统吗?Redis分布式锁都不会?
    使用批处理文件(*.bat)同时打多个cmd窗口
    mysql删除重复数据只保留一条
    native2ascii命令
    利用编辑距离(Edit Distance)计算两个字符串的相似度
    eclipse如何正确部署tomcat7
  • 原文地址:https://www.cnblogs.com/mfrbuaa/p/4029713.html
Copyright © 2011-2022 走看看