cursor管理

  使用cursor的时候需要注意在使用完之后将其关闭,什么时候关闭也是一个需要注意的问题,稍不小心就可能会出错。我们自己管理cursor可能不是那么容易,问题出现这个或那样的问题,Android系统提供了一套curosr的管理,下面让我们来了解一下。

managedQueryquery的区别

  我们都知道在Android系统中,SQLite数据库的相关操作方式被封装为内容提供 Content Provider,可以帮助那些不会SQL语言的开发者快速实现Android平台上的数据库操作,但是平时我们在查询时一般返回的是Cursor对象,从本质上来看这两个API是不同的类提供的。比如 ContentResolver.query(),以及 Activity.managedQuery()所以,我们看到一个是ContentResolver提供的查询方法,位于android.content.ContextWrapper.getContentResolver(),另一个则为Activity。

  这两种方法的参数是一样的,但是Activity类的方法在整个生命周期中受Activity的影响,而常规我们处理数据逻辑可能单独分成一个类,直接使用Context对象传递实例句柄,对于数据库查询操作如果数据较为庞大尽量使用异步的 AsyncQueryHandler方法防止阻塞线程。

  Activity 里面提供了一个 managedQuery() 方法,按照 Android SDK 里面的说明,“the activity will manage its lifecycle for you.” 听起来很好,Activity 可以替你管理 Cursor 的生命周期了,就不用记着去 close() 了,代码可以更简洁。

  但是 Activity 是怎么去管理 Cursor 的生命周期的呢?SDK 文档没说。最近遇到一个 bug,在一个 Activity 中,用 managedQuery() 查询数据库,将查询得到的 Cursor 用 CursorAdapter 与 ListView 绑定。然后在 Activity 里面执行批量删除数据表记录操作,因为耗时比较长,所以用了多线程处理。测试团队发现的 bug 是,在删除操作进行过程中,如果按下 Home 键,应用就崩溃了。崩溃原因是 Cursor 被释放了,导致工作线程的删除操作异常。

  看了 Activity.java 的源码之后就明白为什么会崩溃了。managedQuery() 其实无非就是把查询得到的 Cursor 放到了 Activity 类的一个数组成员变量mManagedCursors中,然后当 Activity stop 的时候,将这个数组里的每个 cursor 都调用mCursor.deactivate();使curosr无效,直到下次再调用requery()方法,以及在 restart()的时候,将数组里的每个 cursor 都重新查询一次。所以在按下 Home 键之后,Activity 调用了 OnStop 了,cursor 也就无效了,如果有个线程还在继续使用这个 cursor,就会抛异常了。

  因此,在用 managedQuery() 的时候,需要清楚 cursor 什么时候会被释放,并考虑好自己的代码在 cursor 被释放后不再需要使用这个 cursor.

  可以用普通的query,然后运行 startManagingCursor(cursor),同样可以把cursor交给系统去管理,不用担心cursor没有close的情况了。 

 

使用CurosrLoader管理cursor

  Android 3.0引入了CursorLoader实现异步加载数据,为了避免同步查询数据库时阻塞UI线程的问题。在API 11之前可以通过下载支持库,来使之前的系统支持此功能.

  在Android 3.0之后,官方推荐使用CursorLoader来对curosr进行管理,如果想在3.0之前的版本使用,需要继承FragmentActivity,该类位于android-support-v4.jar包中,直接使用FragmentActivity会报错,需要导入该包(该包位于F:\android-sdk\extras\android\support)。

  相信不少人都知道Android compatibility这个兼容包的存在。是的,Android compatibility包里面就有FragmentActivity和Fragment这套东西。它有两个版本v4和v13,其中v4就支持支持从android sdk1.6开始,可以使用Fragment。Android compatibility包是一个静态的jar包,我们只需要将它置于工程中,导入进工程,就能很方便的引用到FragmentActivity和Fragment了。

下面的代码展示了在Android 3.0之前使用Loader的用法:

import android.os.Bundle;

import android.support.v4.app.FragmentActivity;

import android.support.v4.app.LoaderManager;

import android.support.v4.content.Loader;

import android.widget.Toast;

 

public class MyActivity extends FragmentActivity implements LoaderManager.LoaderCallbacks<Object> {

public void onCreate(Bundle savedInstanceState) {

    super.onCreate(savedInstanceState);

    setContentView(R.layout.main);

    getSupportLoaderManager().initLoader(0, null, this);

}

 

public Loader<Object> onCreateLoader(int i, Bundle bundle){

    return null; // TODO

}

 

public void onLoadFinished(Loader loader, Object o) {

    Toast.makeText(this, "onLoadFinished", Toast.LENGTH_SHORT).show();

}

 

public void onLoaderReset(Loader loader)    {

    Toast.makeText(this, "onLoaderReset", Toast.LENGTH_SHORT).show();

}

}

 

 

Loaders,中文可理解为“加载器”,在Android3.0中新增。从字面含义可见其功能,即提供数据加载。特别地,加载数据的方式为异步。它具有以下特点:

l  Loaders用于所有的Activity和Fragment;

l  提供异步数据装载机制;

l  监控他们的来源数据变化情况,在数据发生变化的时候传递新的结果;

l  自动重连到最后一个数据加载器游标,因此不需要重新查询数据

如何在应用中使用Loaders

使用Loaders的先决条件:

l  需要一个Activity 或者 Fragmnet

l  一个LoaderManager实例

l  一个用于加载数据的的CursorLoader对象(依赖于ContentProvider)

l  一个LoaderManager.LoaderCallbacks的实现类.

l  一个数据展现适配器,比如SimpleCursorAdapter

l  一个数据源,比如ContentProvider

启动数据加载器Loaders

LoaderManager管理者一个Activity或者Fragment中的一个或多个Loader实例,每个Activity或者Fragment只有对应一个LoaserManager。

         一般在Activity的onCreate方法或者Fragment的onActivityCreated方法中初始化一个Loader:

getLoaderManager().initLoader(0, null, this);

参数:

1、  第一个参数:0 为Loader的唯一标识ID;

2、  第二个参数: 为Loader的构造器可选参数,这里为null;

3、  第三个参数:this,这里表示当前Activity对象或者Fragment对象,提供给LoaderManager对象进行数据汇报。

InitLoader()方法保证了Loader初始化及对象激活,执行这个方法有2个可能的结果:

1、  如果ID存在,则重复利用;

2、  如果ID不存在,则出发LoaderManager.LoaderCallbacks的onCreateLoader()方法新创建一个Loader并返回;

 

不管在什么情况下,只有Loader状态发生了变化,与之关联的LoaderManager.LoaderCallbacks实现类都会被告知;

  你可能注意到了,initLoader返回的Loader对象并未与任何变量关联,那是因为LoaderManager有自动的Loader管理功能;LoaderManager在必要的时候自动启动及停止数据加载操作,并且维护者Loader的状态;这就意味着,你很少直接与Loader进行交互。一般地,使用LoaderManager.LoaderCallbacks的onCreateLoader()方法去干预数据加载的过程中的特殊事件。

如何重启数据加载器Loaders

  在上面创建Loaders时,如果ID不存在则创建,否则使用旧的Loader,但有些时候,我们需要清理掉旧的数据重新开始。

  使用restartLoaser()可以做到。比如,SearchView.OnQueryTextListener的实现类,在查询条件发生改变时重启Loaders,以便获取最新的查询结果。

public boolean onQueryTextChanged(String newText) {

    // Called when the action bar search text has changed.  Update

    // the search filter, and restart the loader to do a new query

    // with this filter.

    mCurFilter = !TextUtils.isEmpty(newText) ? newText : null;

    getLoaderManager().restartLoader(0, null, this);

    return true;}

如何使用LoaderManager的回调方法

  LoaderManager.LoaderCallbacks 接口是客户端与LoaderManager进行交互的腰带。

  Loader ,特别是CursorLoader,期望在停止状态后保存它们的状态。这样的话,用户在交互过程中,就避免了数据的重新加载而导致UI卡死的局面。使用回调函数,就可以知道什么时候去创建一个新的Loader,并且告知应用程序什么时候停止使用Loader加载的数据。

回调方法有:

l  onCreateLoader():根据给定的ID创建新的Loader;

l  onLoaderFinished():当Loader完成数据加载后调用;

l  onLoaderReset():Loader重置,使之前的数据无效;

 

onCreateLoader使用实例:

// If non-null, this is the current filter the user has provided.

String mCurFilter;

...

public Loader<Cursor> onCreateLoader(int id, Bundle args) {

    // This is called when a new Loader needs to be created.  This

    // sample only has one Loader, so we don't care about the ID.

    // First, pick the base URI to use depending on whether we are

    // currently filtering.

    Uri baseUri;

    if (mCurFilter != null) {

        baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI,

                  Uri.encode(mCurFilter));

    } else {

        baseUri = Contacts.CONTENT_URI;

    }

 

    // Now create and return a CursorLoader that will take care of

    // creating a Cursor for the data being displayed.

    String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND ("

            + Contacts.HAS_PHONE_NUMBER + "=1) AND ("

            + Contacts.DISPLAY_NAME + " != '' ))";

    return new CursorLoader(getActivity(), baseUri,

            CONTACTS_SUMMARY_PROJECTION, select, null,

            Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");}

CursorLoader(Context context, Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)构造器参数解释:

Context:上下文,这里是Activity对象或者Fragment对象

Uri:内容检索地址

Projection:要显示的列,传null表示查询所有的列

Selection:查询过滤语句,类似SQL WHERE ,传null,表示查询所有

selectionArgs:查询参数,替换在selection中定义的  ?

sortOrder:排序定义,类似SQL ORDER BY

完整的实例

public static class CursorLoaderListFragment extends ListFragment

        implements OnQueryTextListener, LoaderManager.LoaderCallbacks<Cursor> {

 

    // This is the Adapter being used to display the list's data.

    SimpleCursorAdapter mAdapter;

 

    // If non-null, this is the current filter the user has provided.

    String mCurFilter;

 

    @Override public void onActivityCreated(Bundle savedInstanceState) {

        super.onActivityCreated(savedInstanceState);

 

        // Give some text to display if there is no data.  In a real

        // application this would come from a resource.

        setEmptyText("No phone numbers");

 

        // We have a menu item to show in action bar.

        setHasOptionsMenu(true);

 

        // Create an empty adapter we will use to display the loaded data.

        mAdapter = new SimpleCursorAdapter(getActivity(),

                android.R.layout.simple_list_item_2, null,

                new String[] { Contacts.DISPLAY_NAME, Contacts.CONTACT_STATUS },

                new int[] { android.R.id.text1, android.R.id.text2 }, 0);

        setListAdapter(mAdapter);

 

        // Prepare the loader.  Either re-connect with an existing one,

        // or start a new one.

        getLoaderManager().initLoader(0, null, this);

    }

 

    @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {

        // Place an action bar item for searching.

        MenuItem item = menu.add("Search");

        item.setIcon(android.R.drawable.ic_menu_search);

        item.setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);

        SearchView sv = new SearchView(getActivity());

        sv.setOnQueryTextListener(this);

        item.setActionView(sv);

    }

 

    public boolean onQueryTextChange(String newText) {

        // Called when the action bar search text has changed.  Update

        // the search filter, and restart the loader to do a new query

        // with this filter.

        mCurFilter = !TextUtils.isEmpty(newText) ? newText : null;

        getLoaderManager().restartLoader(0, null, this);

        return true;

    }

 

    @Override public boolean onQueryTextSubmit(String query) {

        // Don't care about this.

        return true;

    }

 

    @Override public void onListItemClick(ListView l, View v, int position, long id) {

        // Insert desired behavior here.

        Log.i("FragmentComplexList", "Item clicked: " + id);

    }

 

    // These are the Contacts rows that we will retrieve.

    static final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {

        Contacts._ID,

        Contacts.DISPLAY_NAME,

        Contacts.CONTACT_STATUS,

        Contacts.CONTACT_PRESENCE,

        Contacts.PHOTO_ID,

        Contacts.LOOKUP_KEY,

    };

    public Loader<Cursor> onCreateLoader(int id, Bundle args) {

        // This is called when a new Loader needs to be created.  This

        // sample only has one Loader, so we don't care about the ID.

        // First, pick the base URI to use depending on whether we are

        // currently filtering.

        Uri baseUri;

        if (mCurFilter != null) {

            baseUri = Uri.withAppendedPath(Contacts.CONTENT_FILTER_URI,

                    Uri.encode(mCurFilter));

        } else {

            baseUri = Contacts.CONTENT_URI;

        }

 

        // Now create and return a CursorLoader that will take care of

        // creating a Cursor for the data being displayed.

        String select = "((" + Contacts.DISPLAY_NAME + " NOTNULL) AND ("

                + Contacts.HAS_PHONE_NUMBER + "=1) AND ("

                + Contacts.DISPLAY_NAME + " != '' ))";

        return new CursorLoader(getActivity(), baseUri,

                CONTACTS_SUMMARY_PROJECTION, select, null,

                Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC");

    }

 

    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {

        // Swap the new cursor in.  (The framework will take care of closing the

        // old cursor once we return.)

        mAdapter.swapCursor(data);

    }

 

    public void onLoaderReset(Loader<Cursor> loader) {

        // This is called when the last Cursor provided to onLoadFinished()

        // above is about to be closed.  We need to make sure we are no

        // longer using it.

        mAdapter.swapCursor(null);

    }}

 

转载于:https://www.cnblogs.com/adm1989/archive/2013/01/14/2860207.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/403157.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

数字金额加逗号;js给数字加三位一逗号间隔的两种方法;js数据格式化

需求&#xff1a;数字金额&#xff0c;按照三位一个逗号显示。既 千 百万 十亿 或者是按照固定的几位一个逗号展示。 方法1&#xff1a; <script type "text/javascript">//保留三位小数&#xff0c;toLocaleString() 方法可把一个 Number 对象转换为本地格…

学习java的经典书籍

《java编程思想》 《Java编程思想(第4版)》书共22章&#xff0c;包括操作符、控制执行流程、访问权限控制、复用类、多态、接口、通过异常处理错误、字符串、泛型、数组、容器深入研究、Iava’UO系统、枚举类型、并发以及图形化用户界面等内容。这些丰富的内容&#xff0c;包含…

项目管理软件伙伴https://www.huobanyun.cn/

现在项目管理软件市面上很多&#xff0c;但能够完全适合每家公司需求的比较难找&#xff0c;因为众口难调&#xff0c;每家公司都有自己的特殊情况&#xff0c;所以&#xff0c;建议考虑下有比较齐全的基础功能的标准化软件产品&#xff0c;同时又在项目管理开发能力上比较突出…

eclipse配置

eclipse 算是跨平台的开发工具了&#xff0c;而且使用的人群很多&#xff0c;虽然网上有很多答案&#xff0c;但我还是想整理下自己的答案&#xff0c;方便日后查询&#xff1a; 1. 编码设置 2. 解决No grammar constraints (DTD or XML schema) 3. [WARNING] Using platform …

el-form表单新增表单项动态校验;el-form校验动态表单v-if不生效;

场景&#xff1a;本文是两种表单校验 1.对于数组for循环&#xff0c;校验每一项 2.对于两个不同的字段&#xff0c;分别v-if显示隐藏的校验 一、新增和删除表单项&#xff0c;动态校验。 el-form表单动态动态新增表单进行校验。直接参考 动态增减表单项 以下代码可直接复制&…

MT7628如何控制GPIO

查看datasheet和确认GPIO复用引脚scheme 通过查看mt7628 datasheet可以明确复用关系&#xff1a; 在这里我以I2S对应的GPIO引脚为例。 查看 mt7628an.dtsi 文件中对gpio的注册 $(TOPDIR)假定为宿主机上 OpenWrt 的编译目录。 在$(TOPDIR)/target/linux/ramips/dts/mt7628an.d…

.Net Core集成Office Web Apps(一)

最近开始学习.Net Core&#xff0c;并使用Visual Studio Code工具来开发。感觉开发起来特别的方便&#xff0c;但是有个头疼的地方&#xff1a;许多的类库被修改了&#xff0c;一时半会儿还熟悉不了&#xff0c;需要查阅官方API。。。 Microsoft Office Web Apps&#xff08;以…

Unhandled event loop exception Item not added

win7_x64 eclipse&#xff0c;老是出现如题的问题&#xff0c;太烦了。上网一搜&#xff0c;好多人说是杀毒软件的问题。 我把360关了&#xff0c;问题依旧&#xff0c;再把ADSafe关掉&#xff0c;问题解决了。所以还是不要装一些乱七八糟的东东了&#xff0c;eclipse不喜欢&a…

el-upload上传组件的动态添加;el-upload动态上传文件;el-upload区分文件是哪个组件上传的。

需求&#xff1a;正常我们上传都是一个固定的文件传到固定的后端字段里去。 但是有可能遇到&#xff0c;这种自定义新增多个上传组件&#xff0c;也就是遍历数组似的多个同样的上传组件 此时就遇到一个问题&#xff1a;因为是遍历出来的上传组件&#xff0c;导致上传成功:on-su…

openwrt gpio控制与使用

查看datasheet和确认GPIO复用引脚scheme 通过查看mt7628 datasheet可以明确复用关系&#xff1a; 在这里我以I2S对应的GPIO引脚为例。 查看 mt7628an.dtsi 文件中对gpio的注册 $(TOPDIR)假定为宿主机上 OpenWrt 的编译目录。 在$(TOPDIR)/target/linux/ramips/dts/mt7628an.d…

git 配置图形比较工具

2019独角兽企业重金招聘Python工程师标准>>> 以meld为例&#xff0c;安装方式是sudo apt-get install A. 在/usr/local/bin 目录下创建extDiff 文件(注意: 目录可以是任意) cd /usr/local/bin sudo gedit /usr/local/bin 内容为: #!/bin/bash /usr/bin/meld "$…

推荐!!!前端将url转成blob和blob转成url;前端将文件流读取成url;前端将blob文件读取出url预览和下载

一般后端返回的地址&#xff0c;前端通过返回blob读取出url&#xff0c;然后使用a标签下载 方式一&#xff1a;通过接口将后端返回的文件流blob读取出url&#xff08;推荐推荐&#xff09; downLoadFileImg (fileUrl, fileName) {// 可下载&#xff0c;名称也有效 -- 推荐cons…

CH340电路设计

最近选用USB转串口芯片进行开发调试&#xff0c;在调研了各主流芯片的之后&#xff0c;觉得 CH340 系列的性价比很高&#xff0c;而且技术支持在国内&#xff0c;如果遇到问题解决起来也会方便很多。但是 CH340 / CH341 型号很多&#xff0c;具体选型就就该结合需求和芯片手册了…

Windows Phone 的后台代理不支持的 API

适用于&#xff1a; Windows Phone 8 | Windows Phone OS 7.1 有一组 API 不能在由计划任务执行的代码中使用。这包括以从 ScheduledTaskAgent 调用的任何库中代码的形式实现ScheduledTaskAgent 的类中包含的代码。其中一些 API 由开发工具进行检测&#xff0c;并且在运行时或编…

CH340芯片选型

CH340是一个USB总线的转接芯片&#xff0c;其中转串口的应用场合居多&#xff0c;且市场占有率很高。CH340芯片根据不同的功能可以实现为USB转串口、打印口和IrDA红外接口&#xff0c;因此选型的时候就首先需要根据功能加以区分了。如下表所示&#xff1a;&#xff08;以下数据…

vue拖拽列表----vuedraggable组件;ElementUI 实现Table组件实现拖拽效果

vue-draggable中文文档 简单的遍历list列表拖拽 部分元素不可拖拽参考&#xff1b; 部分不可拖拽参考 ElementUI 实现Table组件实现拖拽效果 列表的拖拽功能&#xff1a; 一、下载依赖 npm i -S vuedraggable二、页面使用 <template><div><vuedraggable cla…

Linux 如何加载并口/打印口驱动

实际上Linux是自带并口驱动的&#xff0c;因此不需要再使用第三方驱动编译加载了。 设置并口的具体步骤如下&#xff1a; rmmod lp rmmod parport_pcinsmod /usr/lib/modules/$(shell uname -r)/kernel/drivers/parport/parport_pc io0xb000 irq10 或者 modprobe parport_pc …

[DB]mysql 及sql server2005下实现分页效果的sql语句

简要做一下总结&#xff1a; 为实现类似top的功能&#xff0c;我们在SQL Server中和MySQL中使用到的SQL语句是不同的。 1、在SQL Server中&#xff0c;我们使用 select top N * from tablename来查询tablename表中前N条记录。 根据所给变量的不同还有其他方法&…

filters获取data中的数据;filters使用data中的数据

如果直接在filters中通过this引入data数据&#xff0c;则无效获取不到。 可以通过filter方法传值 来获取data的数据使用 <div >{{formInline.bjthObj.insuranceCompanyName | CompanyVal(cops)}}</div>data () {return {insuranceCompanyName: ,cops:[],}}filters:…