Android Api Demos登顶之路(四十七)Loader-->Throttle

这个demo演示了如何利用类加载器对自定义的内容提供者共享的数据进行管理

MainActivity

public class MainActivity extends Activity {
    // 定义主机名,用以拼接Uri,Uri表明了内容提供的地址,外部应用通过Uri访问内容提供者,来实现对数据的增删改查
    private static final String AUTHORITY = "com.fishtosky.loaderthrottle";

    /*
     * 本例中我们将自定义的一个数据库通过内容提供者共享给其它的外部应用,使外部应用可以对数据库中的内容进行 增删改查的操作。
     * 定义一个类用于定义关于内容提供者和工作表的一些常量,该类实现了BaseColumns接口,表示将继承该接口
     * _id和_icount两列,我们无需再定义就会在表中创建出这两个列
     */
    public static class MainTable implements BaseColumns {
        // 构造函数私有化,不允许创建此类的实例
        private MainTable() {
        };

        // 定义表的名字
        public static final String TABLE_NAME = "main";
        // 定义这张表的uri
        public static final Uri CONTENT_URI = Uri.parse("content://"
                + AUTHORITY + "/main");
        // 定义表中某个条目(某行数据)的Uri的前面公共的部分,使用时我们还需要在后面添加条目的Id
        public static final Uri CONTENT_ID_URI_BASE = Uri.parse("content://"
                + AUTHORITY + "/main");
        // 定义Uri的命名机制,/前面的部分是android系统定义的,不能改变,/后面的部分可以自定义任意字符串
        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/com.fishtosky.throttle";
        // 定义某个条目的Uri的命名机制
        public static final String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/com.fishtosky.throttle";
        // 定义默认的排序方式
        public static final String DEFAULT_SORT_ORDER = "data COLLATE LOCALIZED ASC";
        // 定义列的名字,本例中只有一列
        public static final String COLUM_NAME_DATA = "data";
    }

    /*
     * 定义数据库的帮助库,用于创建数据库和工作表
     */
    public static class DatabaseHelper extends SQLiteOpenHelper {
        // 定义数据库的名字的版本
        private static final String DATABASE_NAME = "loader_throttle.db";
        private static final int DATABASE_VERSION = 1;

        public DatabaseHelper(Context context) {
            super(context, DATABASE_NAME, null, DATABASE_VERSION);
        }

        @Override
        public void onCreate(SQLiteDatabase db) {
            db.execSQL("CREATE TABLE " + MainTable.TABLE_NAME + " ("
                    + MainTable._ID + " INTEGER PRIMARY KEY,"
                    + MainTable.COLUM_NAME_DATA + " TEXT);");
        }

        @Override
        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
            Log.w("TAG", "Upgrading database from version " + oldVersion
                    + " to " + newVersion + ", which will destroy all old data");
            // 版本升级时调用,删除旧表,创建新表
            db.execSQL("DROP TABLE IF EXISTS notes");
            onCreate(db);
        }
    }

    /*
     * 自定义内容提供者,通过它实现把数据库共享给外部应用
     */
    public static class SimpleProvider extends ContentProvider {
        // 定义一个集合,把从数据库中选出的列映射到该集合中
        private Map<String, String> mNotesProjectionMap;
        // 定义Uri的匹配器,用于解析传入的Uri
        private UriMatcher mUriMatcher;
        // 定义当Uri匹配时的返回码
        // 匹配整个表时的返回码
        private static final int MAIN = 1;
        // 匹配某一行时的返回码
        private static final int MAIN_ID = 2;
        private DatabaseHelper mOpenHelper;

        public SimpleProvider() {
            // 为内容提供者注册Uri
            mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
            mUriMatcher.addURI(AUTHORITY, MainTable.TABLE_NAME, MAIN);
            // #表示通配符
            mUriMatcher.addURI(AUTHORITY, MainTable.TABLE_NAME + "/#", MAIN_ID);

            mNotesProjectionMap = new HashMap<String, String>();
            mNotesProjectionMap.put(MainTable._ID, MainTable._ID);
            mNotesProjectionMap.put(MainTable.COLUM_NAME_DATA,
                    MainTable.COLUM_NAME_DATA);
        }

        @Override
        public boolean onCreate() {
            // 创建数据库和数据表
            mOpenHelper = new DatabaseHelper(getContext());
            return true;
        }

        /*
         * 用于供外部应用从内容提供者中获取数据
         */
        @Override
        public Cursor query(Uri uri, String[] projection, String selection,
                String[] selectionArgs, String sortOrder) {
            // 使用Sql查询语句构建的辅助类
            SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
            qb.setTables(MainTable.TABLE_NAME);
            // 根据匹配Uri的返回码来判定是查询整个数据表,还是查询某条数据
            switch (mUriMatcher.match(uri)) {
            case MAIN:
                // 查询整个表
                qb.setProjectionMap(mNotesProjectionMap);
                break;
            case MAIN_ID:
                qb.setProjectionMap(mNotesProjectionMap);
                // 追加筛选条件
                qb.appendWhere(MainTable._ID + "=?");
                // 获取查询参数即所要查询条目的Id
                selectionArgs = DatabaseUtils.appendSelectionArgs(
                        selectionArgs,
                        new String[] { uri.getLastPathSegment() });
                break;

            default:
                throw new IllegalArgumentException("UnKnown Uri" + uri);
            }

            // 如果没定义排序规则,则按照默认的规则进行排序
            if (TextUtils.isEmpty(sortOrder)) {
                sortOrder = MainTable.DEFAULT_SORT_ORDER;
            }

            // 获取到可读的数据库
            SQLiteDatabase db = mOpenHelper.getReadableDatabase();
            Cursor c = qb.query(db, projection, selection, selectionArgs, null,
                    null, sortOrder);
            // 监听uri的变化
            c.setNotificationUri(getContext().getContentResolver(), uri);
            return c;
        }

        /*
         * 返回对应Uri MIME类型用以验证数据的合法性
         */
        @Override
        public String getType(Uri uri) {
            switch (mUriMatcher.match(uri)) {
            case MAIN:
                return MainTable.CONTENT_TYPE;
            case MAIN_ID:
                return MainTable.CONTENT_ITEM_TYPE;
            default:
                throw new IllegalArgumentException("UnKnown Uri" + uri);
            }
        }

        /*
         * 用于外部应用向内容提供者中插入数据
         */
        @Override
        public Uri insert(Uri uri, ContentValues values) {
            // 只能插入到数据表中
            if (mUriMatcher.match(uri) != MAIN) {
                throw new IllegalArgumentException("UnKnown Uri" + uri);
            }
            if (values != null) {
                SQLiteDatabase db = mOpenHelper.getWritableDatabase();
                long row_Id = db.insert(MainTable.TABLE_NAME, null, values);
                // 如果插入成功,则插入行的Id存在
                if (row_Id > 0) {
                    // ContentUris用于操作Uri路径后面的Id部分
                    Uri noteUri = ContentUris.withAppendedId(
                            MainTable.CONTENT_ID_URI_BASE, row_Id);
                    //必须设置对Uri的监听,不然loader无法获取到数据库的更新,不能实现实时更新
                    getContext().getContentResolver().notifyChange(noteUri, null);
                    // 返回所插入条目的Uri
                    return noteUri;
                }
            }
            throw new SQLException("Failed to insert row into " + uri);
        }

        /*
         * 用于外部应用删除内容提供者中的数据
         */
        @Override
        public int delete(Uri uri, String where, String[] whereArgs) {
            SQLiteDatabase db = mOpenHelper.getWritableDatabase();
            String findWhere;
            int count = -1;

            switch (mUriMatcher.match(uri)) {
            case MAIN:
                count = db.delete(MainTable.TABLE_NAME, where, whereArgs);
                break;
            case MAIN_ID:
                // 组装查询条件
                findWhere = DatabaseUtils.concatenateWhere(MainTable._ID + "="
                        + ContentUris.parseId(uri), where);
                count = db.delete(MainTable.TABLE_NAME, findWhere, whereArgs);
                break;

            default:
                throw new IllegalArgumentException("Unknown URI " + uri);
            }

            getContext().getContentResolver().notifyChange(uri, null);
            return count;
        }

        @Override
        public int update(Uri uri, ContentValues values, String where,
                String[] whereArgs) {
            SQLiteDatabase db = mOpenHelper.getWritableDatabase();
            String findWhere;
            int count = -1;

            switch (mUriMatcher.match(uri)) {
            case MAIN:
                count = db.update(MainTable.TABLE_NAME, values, where,
                        whereArgs);
                break;
            case MAIN_ID:
                // 组装查询条件
                findWhere = DatabaseUtils.concatenateWhere(MainTable._ID + "="
                        + ContentUris.parseId(uri), where);
                count = db.update(MainTable.TABLE_NAME, values, findWhere,
                        whereArgs);
                break;

            default:
                throw new IllegalArgumentException("Unknown URI " + uri);
            }

            getContext().getContentResolver().notifyChange(uri, null);
            return count;
        }

    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        FragmentManager fm = getFragmentManager();
        if (fm.findFragmentById(android.R.id.content) == null) {
            LoaderThrottleFragment frg = new LoaderThrottleFragment();
            fm.beginTransaction().add(android.R.id.content, frg).commit();
        }
    }

    public static class LoaderThrottleFragment extends ListFragment {
        private static final int POPULATE_ID = Menu.FIRST;
        private static final int CLEAR_ID = Menu.FIRST + 1;
        private SimpleCursorAdapter mAdapter;
        private AsyncTask<Void, Void, Void> mPopulatingTask;
        final String[] projection = new String[] { MainTable._ID,
                MainTable.COLUM_NAME_DATA };

        private LoaderCallbacks<Cursor> myLoader = new LoaderCallbacks<Cursor>() {

            @Override
            public Loader<Cursor> onCreateLoader(int id, Bundle args) {
                CursorLoader c = new CursorLoader(getActivity(),
                        MainTable.CONTENT_URI, projection, null,
                        null, null);
                System.out.println("数据变化了吗?");
                //最多每2秒更新一次
                c.setUpdateThrottle(2000);
                return c;
            }

            @Override
            public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
                System.out.println("数据准备完毕了吗?"+data.getCount());
                mAdapter.swapCursor(data);
                if(isResumed()){
                    setListShown(true);
                }else{
                    setListShownNoAnimation(true);
                }
            }

            @Override
            public void onLoaderReset(Loader<Cursor> loader) {
                mAdapter.swapCursor(null);
            }
        };

        @Override
        public void onActivityCreated(Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
            setEmptyText("No data.  Select ‘Populate‘ to fill with data from Z to A at a rate of 4 per second.");
            setHasOptionsMenu(true);
            mAdapter = new SimpleCursorAdapter(getActivity(),
                    android.R.layout.simple_list_item_1, null,
                    new String[] { MainTable.COLUM_NAME_DATA },
                    new int[] { android.R.id.text1 }, 0);
            setListAdapter(mAdapter);
            setListShown(false);

            getLoaderManager().initLoader(111, null, myLoader);
        }

        @Override
        public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
            super.onCreateOptionsMenu(menu, inflater);
            menu.add(Menu.NONE, POPULATE_ID, 0, "populate").setShowAsAction(
                    MenuItem.SHOW_AS_ACTION_IF_ROOM);
            menu.add(Menu.NONE, CLEAR_ID, 0, "clear").setShowAsAction(
                    MenuItem.SHOW_AS_ACTION_IF_ROOM);
        }

        @Override
        public boolean onOptionsItemSelected(MenuItem item) {
            switch (item.getItemId()) {
            case POPULATE_ID:
                addToDatabase();
                //testadd();
                return true;
            case CLEAR_ID:
                deleteData();
                return true;
            }
            return super.onOptionsItemSelected(item);
        }

        /*private void testadd() {
            ContentValues values = new ContentValues();
            values.put(MainTable.COLUM_NAME_DATA, "I am test string");
            Uri rowUri=getActivity().getContentResolver().insert(MainTable.CONTENT_URI, values);
            if(rowUri!=null){
                getLoaderManager().restartLoader(111, null, myLoader);
            }
            System.out.println("rowUri:"+rowUri.toString());
        }*/

        private void deleteData() {
            if (mPopulatingTask != null) {
                mPopulatingTask.cancel(false);
                mPopulatingTask = null;
            }
            AsyncTask<Void, Void, Void> task = new AsyncTask<Void, Void, Void>() {
                @Override
                protected Void doInBackground(Void... params) {
                    getActivity().getContentResolver().delete(MainTable.CONTENT_URI, null, null);
                    return null;
                }
            };
            task.execute((Void[]) null);
        }

        private void addToDatabase() {
            // 如果异步任务不为空,则取消任务
            if (mPopulatingTask != null) {
                mPopulatingTask.cancel(false);
                mPopulatingTask = null;
            }
            // 开启线程向数据库中添加内容
            mPopulatingTask = new AsyncTask<Void, Void, Void>() {
                @Override
                protected Void doInBackground(Void... params) {
                    // 向数据库中添加内容
                    for (char c = ‘z‘; c >= ‘a‘; c--) {
                        if (isCancelled()) {
                            break;
                        }
                        StringBuilder sb = new StringBuilder("Data ");
                        sb.append(c);
                        ContentValues values = new ContentValues();
                        values.put(MainTable.COLUM_NAME_DATA, sb.toString());
                        Uri rowUri=getActivity().getContentResolver().insert(MainTable.CONTENT_URI, values);
                        //System.out.println("rowUri:"+rowUri.toString());
                        try {
                            Thread.sleep(250);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    return null;
                }

            };
            // 使用系统默认的线程池来管理线程
            //mPopulatingTask.execute((Void[]) null);
            mPopulatingTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,
                    (Void[]) null);
            //getLoaderManager().restartLoader(111, null, myLoader);
        }

        @Override
        public void onListItemClick(ListView l, View v, int position, long id) {
            super.onListItemClick(l, v, position, id);
            Toast.makeText(getActivity(), "Item click:" + id, 0).show();
        }
    }
}

在配置文件中注册内容提供者

<provider
            android:name="com.fishtosky.loaderthrottle.MainActivity$SimpleProvider"
            android:authorities="com.fishtosky.loaderthrottle">
        </provider>

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-11-10 07:44:23

Android Api Demos登顶之路(四十七)Loader-->Throttle的相关文章

Android Api Demos登顶之路(十四)Quick Contacts

这个demeo主要演示的是使内容提供者和内容解析者来获取其它应用的数据.Content Provider为不同应用之间共享数据提供了统一的接口,Android系统的每个Content Provider都定义了一个CONTENT_URI,Android中每个Context对象(如Activity)对含有一个ContentResolver,ContentResolver可以根据CONTENT_URI获取对应的Content Provider. 在本例中使用了startManagingCursor(c

Android Api Demos登顶之路(四十)Fragment--&gt;Layout

这个demo演示了fragment的布局特点.本例中在竖屏的状态下,当我们点击列表的条目时 打一个activity来显示这个条目的详细信息. * 而在横屏的状态下由于屏幕足够宽,我们就在界面上同时显示了两个fragment,一个用来 显示标题,另一个用来显示详细信息. layout目录下创建竖屏显示的布局文件:fragment_layout.xml <?xml version="1.0" encoding="utf-8"?> <FrameLayou

Android Api Demos登顶之路(四十五)Loader--&amp;gt;Cursor

这个demo演示了类载入器的用法.关于类载入器的使用我们在前面的demo中已经介绍过了 在此再小小的复习一下. 类载入器的使用步骤: * 1.获取类载入器的管理者LoaderManager manager = tent.getLoaderManager(); * 2.初始化loader MainActivity public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedIn

Android Api Demos登顶之路(三十)Display Options

这个demo演示了actionbar的各种布局样式. activity_main.xml <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height=&

Android Api Demos登顶之路(五十二)Search

android 为所有需要提供查询功能的activity提供了两种查询方式:search dialog 和searchview * 这个demo演示了第一种查询方式. * 基本思路:用户提交查询后,Android系统构造一个Intent并把用户的查询内容放在这个Intent中.然后Android启动你定义的用来处理用户查询的Activity(称为Searchable Activity),并把这个Intent发给该Activity. * 使用SearchDialog的步骤 * 1.在res/xml

Android API Demos 系列之 — 播放GIF动画的类Movie

良好的开端,是成功的一半.A good beginning is half done.  -_- 本文目录 ● 一.什么是GIF ● 二.Android系统和应用如何播放GIF 一.[什么是GIF] Gif动态图片,是通过对多图层的图片,按时间进行不同的切换,以达到动画的效果.Gif动态图片的特点是,图片小,易于随时安置调用.比起一张单调的静态图片,Gif格式的动态图片明显更加的生动和有意思. 二.[Android系统和应用如何播放GIF] 在Android系统的原生控件ImageView并不支

【Android API Guides简译(四)】使用Service还是使用线程?

一个服务是一个组件,这个组件可以在Android后台运行,即使你的这个应用被关闭,它依然在运行.所以说只有你需要一个和当前程序无关的后台程序时,才去创建它. 而如果你只是想让你的App在主线程外工作,而且操作限定在当前程序中时,只需要在在里面创建另一个线程. 比如你只是想在你的Activity在运行时,放一首音乐,那么你应该在onCreat()方法里创建另一个线程,在onStart()里开始线程,在onStop()里结束这个线程,同时你也要考虑到使用AsyncTask orHandlerThre

Android 零基础学习之路

第一阶段:Java面向对象编程 1.Java基本数据类型与表达式,分支循环. 2.String和StringBuffer的使用.正则表达式. 3.面向对象的抽象,封装,继承,多态,类与对象,对象初始化和回收:构造函数.this关键字.方法和方法的参数传递过程.static关键字.内部类,Java的垃极回收机制,Javadoc介绍. 4.对象实例化过程.方法的覆盖.final关键字.抽象类.接口.继承的优点和缺点剖析:对象的多态性:子类和父类之间的转换.抽象类和接口在多态中的应用.多态带来的好处.

[转帖]为什么他能成为谷歌新当家?皮查伊的登顶之路

为什么他能成为谷歌新当家?皮查伊的登顶之路 https://tech.sina.com.cn/it/2019-12-10/doc-iihnzhfz4783261.shtml 新浪科技美国 郑峻 “自我们创办谷歌以来,没有比他更让我们放心的人,也没有比他更适合领导谷歌和Alphabet的人.”在宣布交班隐退的公开邮件中,谷歌两位联合创始人这样评价他们选择的新当家人桑达尔·皮查伊(Sundar Pichai). 盛赞溢美,无以复加.谷歌母公司Alphabet上周宣布,两位联合创始人拉里·佩奇(Lar