.概述:


ContentProvider汉语为内容提供器,又叫数据内容提供器,差不多一个意思吧,因为他是android应用程序间非常通用的共享数据的一种方式。是推荐的应用程序间共享数据的一种方式。android中许多系统软件和应用软件都使用该方式实现数据共享,比如电话本,相片,音乐,短彩信等,刚开始研究android的人也许会感觉奇怪,直接读取数据库也许会更简单方便,搞一个内容提供器在数据和应用之间,装得高深莫测,故弄玄虚,其实这正体现了面象对象的优越性。通过ContentProvider对各类数据进行包装,包括数据库,文件,XML数据,从而提供统一的对外接口,这在某种程度上提高了软件的可维护性。在android中大量的使用了相类似的设计,比如数据适配器,为各种控件提供统一数据内容,数据观察者,为监测数据变化提供统一接口,这些设计,都是对设计模式的灵活应用,提升了应用程序的健壮性和可维护性。

外界的程序通过ContentResolver接口可以访问ContentProvider提供的数据,ContentResolver提供了很多final或者static的方法,这些提供的方法和ContentProvider中需要实现的方法是对应的,要详细了解或者进一一点了解,可以查看包android.content.ContentResolver类的内容。

Activity或者service中都能通过getContentResolver()可以得到当前应用的ContentResolver实例。然后通过ContentResolver接口访问ContentProvider提供的数据,从而对数据进行查询,修改,删除,添加等操作。要实现的一个内容提供器给其他应用使用,我们需要重载类ContentProvider类,并在该类中实现以下方法,这些方法经过ContentProvider类的转化,能够为第三方应用提供统一的对外服务接口:

查询数据Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs,String sortOrder) 通过Uri进行查询,返回一个Cursor修改数据int update(Uri uri, ContentValues values, String where, String[] selectionArgs) 更新Uri指定位置的数据,返回所影响的行数添加数据Uri insert(Uri url, ContentValues values) 将一组数据插入到Uri 指定的地方,返回新insertedURI删除数据int delete(Uri url, String where, String[] selectionArgs) 删除指定Uri并且符合一定条件的数据,返回所影响的行数 

二。创建ContentProvider: 要创建我们自定义的ContentProvider,我们需要遵循以下几步:

1.创建一个继承了ContentProvider父类的类

2.定义一个名为CONTENT_URI,并且是publicstatic finalUri类型的类变量,你必须为其指定一个唯一的字符串值,最好的方案是以类的全名称,如: publicstatic final Uri CONTENT_URI = Uri.parse(“content://com.google.android.MyContentProvider”); 3.创建你的数据存储系统。大多数ContentProvider使用Android文件系统或SQLite数据库来保持数据,但是你也可以以任何你想要的方式来存储。 4.定义你要返回给客户端的数据列名。如果你正在使用Android数据库,则数据列的使用方式就和你以往所熟悉的其他数据库一样。但是,你必须为其定义一个叫_id的列,它用来表示每条记录的唯一性。 5.如果你要存储字节型数据,比如位图文件等,那保存该数据的数据列其实是一个表示实际保存文件的URI字符串,客户端通过它来读取对应的文件数据,处理这种数据类型的ContentProvider需要实现一个名为_data的字段,_data字段列出了该文件在Android文件系统上的精确路径。这个字段不仅是供客户端使用,而且也可以供ContentResolver使用。客户端可以调用ContentResolver.openOutputStream()方法来处理该URI指向的文件资源,如果是ContentResolver本身的话,由于其持有的权限比客户端要高,所以它能直接访问该数据文件。 6.声明publicstatic String型的变量,用于指定要从游标处返回的数据列。 7.查询返回一个Cursor类型的对象。所有执行写操作的方法如insert(),update()以及delete()都将被监听。我们可以通过使用ContentResover().notifyChange()方法来通知监听器关于数据更新的信息。 8.AndroidMenifest.xml中使用<provider>标签来设置ContentProvider 9.如果你要处理的数据类型是一种比较新的类型,你就必须先定义一个新的MIME类型,以供ContentProvider.geType(url)来返回。MIME类型有两种形式:一种是为指定的单个记录的,还有一种是为多条记录的。这里给出一种常用的格式:

vnd.android.cursor.item/vnd.yourcompanyname.contenttype(单个记录的MIME类型) 比如,一个请求列车信息的URIcontent://com.example.transportationprovider/trains/122可能就会返回typevnd.android.cursor.item/vnd.example.rail这样一个MIME类型。

vnd.android.cursor.dir/vnd.yourcompanyname.contenttype(多个记录的MIME类型) 比如,一个请求所有列车信息的URIcontent://com.example.transportationprovider/trains可能就会返回vnd.android.cursor.dir/vnd.example.rail这样一个MIME类型。

下列代码将创建一个ContentProvider,它仅仅是存储用户名称并显示所有的用户名称(使用SQLLite数据库存储这些数据):

package com.wissen.testApp;                           public class MyUsers {            public static final String AUTHORITY  = “com.wissen.MyContentProvider”;                               // BaseColumn类中已经包含了 _id字段           public static final class User implements BaseColumns {                public static final Uri CONTENT_URI  = Uri.parse(”content://com.wissen.MyContentProvider”);                // 表数据列             public static final String  USER_NAME  = “USER_NAME”;            }        }

上面的类中定义了Content Provider的CONTENT_URI,以及数据列。下面我们将定义基于上面的类来定义实际的Content Provider类:
public class MyContentProvider extends ContentProvider {            private SQLiteDatabase     sqlDB;            private DatabaseHelper    dbHelper;            private static final String  DATABASE_NAME     = “Users.db”;            private static final int        DATABASE_VERSION         = 1;            private static final String TABLE_NAME   = “User”;            private static final String TAG = “MyContentProvider”;                               private static class DatabaseHelper extends SQLiteOpenHelper {                DatabaseHelper(Context context) {                    super(context, DATABASE_NAME, null, DATABASE_VERSION);                }                                   @Override                public void onCreate(SQLiteDatabase db) {                    //创建用于存储数据的表                db.execSQL(”Create table ” + TABLE_NAME + “( _id INTEGER PRIMARY KEY AUTOINCREMENT, USER_NAME TEXT);”);                }                                   @Override                public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {                    db.execSQL(”DROP TABLE IF EXISTS ” + TABLE_NAME);                    onCreate(db);                }            }                               @Override            public int delete(Uri uri, String s, String[] as) {                return 0;            }                               @Override            public String getType(Uri uri) {                return null;            }                               @Override            public Uri insert(Uri uri, ContentValues contentvalues) {                sqlDB = dbHelper.getWritableDatabase();                long rowId = sqlDB.insert(TABLE_NAME, “”, contentvalues);                if (rowId > 0) {                    Uri rowUri = ContentUris.appendId(MyUsers.User.CONTENT_URI.buildUpon(), rowId).build();                    getContext().getContentResolver().notifyChange(rowUri, null);                    return rowUri;                }                throw new SQLException(”Failed to insert row into ” + uri);            }                               @Override            public boolean onCreate() {                dbHelper = new DatabaseHelper(getContext());                return (dbHelper == null) ? false : true;            }                               @Override            public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {                SQLiteQueryBuilder qb = new SQLiteQueryBuilder();                SQLiteDatabase db = dbHelper.getReadableDatabase();                qb.setTables(TABLE_NAME);                Cursor c = qb.query(db, projection, selection, null, null, null, sortOrder);                c.setNotificationUri(getContext().getContentResolver(), uri);                return c;            }                               @Override            public int update(Uri uri, ContentValues contentvalues, String s, String[] as) {                return 0;            }        } 一个名为MyContentProvider的Content Provider创建完成了,它用于从Sqlite数据库中添加和读取记录。Content Provider的入口需要在AndroidManifest.xml中配置:<provider android:name=”MyContentProvider” android:authorities=”com.wissen.MyContentProvider” />之后,让我们来使用这个定义好的Content Provider,下面先向数据库中添加一条用户数据,然后显示数据库中所有的用户数据。:package com.wissen.testApp;                     public class MyContentDemo extends Activity {          @Override          protected void onCreate(Bundle savedInstanceState) {              super.onCreate(savedInstanceState);              insertRecord(”MyUser”);              displayRecords();          }                            private void insertRecord(String userName) {              ContentValues values = new ContentValues();              values.put(MyUsers.User.USER_NAME, userName);              getContentResolver().insert(MyUsers.User.CONTENT_URI, values);          }                         private void displayRecords() {              String columns[] = new String[] { MyUsers.User._ID, MyUsers.User.USER_NAME };              Uri myUri = MyUsers.User.CONTENT_URI;              Cursor cur = managedQuery(myUri, columns,null, null, null );              if (cur.moveToFirst()) {                  String id = null;                  String userName = null;                  do {                      id = cur.getString(cur.getColumnIndex(MyUsers.User._ID));                      userName = cur.getString(cur.getColumnIndex(MyUsers.User.USER_NAME));                      Toast.makeText(this, id + ” ” + userName, Toast.LENGTH_LONG).show();                 } while (cur.moveToNext());             }          }      }


三。对第三方或者系统ContentProvider数据库进行操作

ContentProvider操作数据库不再使用标准的SQL语言。select,add, delete, modify等操作被转化为一种特殊的URI来进行,

这种URI3个部分组成,“content://”,代表数据的路径,和一个可选的标识数据的ID。这种查询字符串格式很常见,

我会在随后的URI介绍中对其说明,android调用第三方应用也会使用URIAndroidandroid.provider包下提供一系列的帮助类,

里面包含了很多以类变量形式给出的查询字符串,比如比较老的联系人操作集中在android.provider.Contacts类中,

而新版本可以在android.provider.ContactsContract类中得到。

查询记录:

Cursor cur = managedQuery(person, null, null, null);

这个查询返回一个包含所有数据字段的游标,我们可以通过迭代这个游标来获取所有的数据:
下面代码演示一个如何依次读取联系人信息表中的指定数据列name和number。

package com.wissen.testApp;                           public class ContentProviderDemo extends Activity {            @Override            public void onCreate(Bundle savedInstanceState) {                super.onCreate(savedInstanceState);                setContentView(R.layout.main);               displayRecords();            }                               private void displayRecords() {                //该数组中包含了所有要返回的字段             String columns[] = new String[] { People.NAME, People.NUMBER };               Uri mContacts = People.CONTENT_URI;               Cursor cur = managedQuery(                   mContacts,                  columns,  // 要返回的数据字段               null,          // WHERE子句               null,         // WHERE 子句的参数               null         // Order-by子句             );               if (cur.moveToFirst()) {                   String name = null;                   String phoneNo = null;                   do {                      // 获取字段的值                 name = cur.getString(cur.getColumnIndex(People.NAME));                     phoneNo = cur.getString(cur.getColumnIndex(People.NUMBER));                     Toast.makeText(this, name + ” ” + phoneNo, Toast.LENGTH_LONG).show();                  } while (cur.moveToNext());               }            }        }

修改记录:


我们可以使用ContentResolver.update()方法来修改数据,我们来写一个修改数据的方法:

private void updateRecord(int recNo, String name) {             Uri uri = ContentUris.withAppendedId(People.CONTENT_URI, recNo);             ContentValues values = new ContentValues();             values.put(People.NAME, name);             getContentResolver().update(uri, values, null, null);         }

现在你可以调用上面的方法来更新指定记录:

updateRecord(10, ”XYZ”);//更改第10条记录的name字段值为“XYZ”

添加记录:
要增加记录,我们可以调用ContentResolver.insert()方法,该方法接受一个要增加的记录的目标URI,以及一个包含了新记录值的Map对象,调用后的返回值是新记录的URI,包含记录号。
上面的例子中我们都是基于联系人信息簿这个标准的Content Provider,现在我们继续来创建一个insertRecord() 方法以对联系人信息簿中进行数据的添加:

private void insertRecords(String name, String phoneNo) { ContentValues values = new ContentValues(); values.put(People.NAME, name); Uri uri = getContentResolver().insert(People.CONTENT_URI, values); Log.d(”ANDROID”, uri.toString()); Uri numberUri = Uri.withAppendedPath(uri, People.Phones.CONTENT_DIRECTORY); values.clear(); values.put(Contacts.Phones.TYPE, People.Phones.TYPE_MOBILE); values.put(People.NUMBER, phoneNo); getContentResolver().insert(numberUri, values); }

这样我们就可以调用insertRecords(name, phoneNo)的方式来向联系人信息簿中添加联系人姓名和电话号码。

删除记录:

Content Provider中的getContextResolver.delete()方法可以用来删除记录,下面的记录用来删除设备上所有的联系人信息:

private void deleteRecords() {             Uri uri = People.CONTENT_URI;             getContentResolver().delete(uri, null, null);         }
你也可以指定WHERE条件语句来删除特定的记录:

getContentResolver().delete(uri, “NAME=” + “‘XYZ XYZ’”, null);

这将会删除name为‘XYZ XYZ’的记录。


四。扩展阅读URI

通用资源标志符uri是UniversalResource Identifier的英文缩写

Uri代表要操作的数据和资源的方法路径,他不是android独特的内容,早在WEB时代已经存在,URI作为URL的子集,和URL一起构成了丰富多彩的多媒体WEB时代。如果没有URI和URL,我们的网络将是一个纯文本时代,他使得网页应用能够找到图片,声音,动画能多媒体文件。如:http://www.baidu.com/img/bdlogo.gif再比如:mailto:[email protected]

其一般由三部分组成:

访问资源的命名机制。

存放资源的主机名。

资源自身的名称,由路径表示。

Android上可用的每种资源-图像、视频片段等都可以用Uri来表示。
AndroidUri由以下三部分组成:"content://"、数据的路径、标示ID(可选)

Android上可用的每种资源-图像、视频片段等都可以用Uri来表示。

举些例子,如:

所有联系人的Uricontent://contacts/people

某个联系人的Uri:content://contacts/people/5

所有图片Uri:content://media/external

某个图片的Uricontent://media/external/images/media/4

我们很经常需要解析Uri,并从Uri中获取数据。

Android系统提供了两个用于操作Uri的工具类,分别为UriMatcherContentUris

虽然这两类不是非常重要,但是掌握它们的使用,会便于我们的开发工作。

下面就一起看一下这两个类的作用。



2.UriMatcher

UriMatcher 类主要用于匹配Uri.

使用方法如下。

首先第一步,初始化:

view plain copy to clipboard print ?
  1. UriMatchermatcher=newUriMatcher(UriMatcher.NO_MATCH);

第二步注册需要的Uri:

view plain copy to clipboard print ?
  1. matcher.addURI("com.yfz.Lesson","people",PEOPLE);
  2. matcher.addURI("com.yfz.Lesson","person/#",PEOPLE_ID);

第三部,与已经注册的Uri进行匹配:

 Uri uri = Uri.parse("content://" + "com.yfz.Lesson" + "/people");  int match = matcher.match(uri);         switch (match)         {             case PEOPLE:                 return "vnd.android.cursor.dir/people";             case PEOPLE_ID:                 return "vnd.android.cursor.item/people";             default:                 return null;         }  

match方法匹配后会返回一个匹配码Code,即在使用注册方法addURI时传入的第三个参数。

上述方法会返回"vnd.android.cursor.dir/person".

总结:

--常量 UriMatcher.NO_MATCH表示不匹配任何路径的返回码

--# 号为通配符

--* 号为任意字符

另外说一下,官方SDK说明中关于Uri的注册是这样写的:

private static final UriMatcher sURIMatcher = new UriMatcher();      static      {          sURIMatcher.addURI("contacts", "/people", PEOPLE);          sURIMatcher.addURI("contacts", "/people/#", PEOPLE_ID);          sURIMatcher.addURI("contacts", "/people/#/phones", PEOPLE_PHONES);          sURIMatcher.addURI("contacts", "/people/#/phones/#", PEOPLE_PHONES_ID);          sURIMatcher.addURI("contacts", "/people/#/contact_methods", PEOPLE_CONTACTMETHODS);          sURIMatcher.addURI("contacts", "/people/#/contact_methods/#", PEOPLE_CONTACTMETHODS_ID);          sURIMatcher.addURI("contacts", "/deleted_people", DELETED_PEOPLE);          sURIMatcher.addURI("contacts", "/phones", PHONES);          sURIMatcher.addURI("contacts", "/phones/filter/*", PHONES_FILTER);          sURIMatcher.addURI("contacts", "/phones/#", PHONES_ID);          sURIMatcher.addURI("contacts", "/contact_methods", CONTACTMETHODS);          sURIMatcher.addURI("contacts", "/contact_methods/#", CONTACTMETHODS_ID);          sURIMatcher.addURI("call_log", "/calls", CALLS);          sURIMatcher.addURI("call_log", "/calls/filter/*", CALLS_FILTER);          sURIMatcher.addURI("call_log", "/calls/#", CALLS_ID);      }  

这个说明估计已经是Google官方没有更新,首先是初始化方法,没有传参,那么现在初始化时,实际是必须传参的。可以看一下Android2.2的源码,无参数的构造方法已经是private的了。

另外就是addURI这个方法,第二个参数开始时不需要"/", 否则是无法匹配成功的。

3.ContentUris

ContentUris 类用于获取Uri路径后面的ID部分

1)为路径加上ID: withAppendedId(uri, id)

比如有这样一个Uri

view plain copy to clipboard print ?
  1. Uriuri=Uri.parse("content://com.yfz.Lesson/people")

通过withAppendedId方法,为该Uri加上ID

view plain copy to clipboard print ?
  1. UriresultUri=ContentUris.withAppendedId(uri,10);

最后resultUri为: content://com.yfz.Lesson/people/10

2)从路径中获取ID: parseId(uri)

view plain copy to clipboard print ?
  1. Uriuri=Uri.parse("content://com.yfz.Lesson/people/10")
  2. longpersonid=ContentUris.parseId(uri);

最后personid 为 :10

附上实验的代码

    package com.yfz;      import com.yfz.log.Logger;      import android.app.Activity;      import android.content.ContentUris;      import android.content.UriMatcher;      import android.net.Uri;      import android.os.Bundle;      public class Lesson_14 extends Activity {                            private static final String AUTHORITY = "com.yfz.Lesson";              private static final int PEOPLE = 1;              private static final int PEOPLE_ID = 2;                            //NO_MATCH表示不匹配任何路径的返回码               private static final UriMatcher sURIMatcher = new UriMatcher(UriMatcher.NO_MATCH);              static              {                  sURIMatcher.addURI(AUTHORITY, "people", PEOPLE);                                    //这里的#代表匹配任意数字,另外还可以用*来匹配任意文本                   sURIMatcher.addURI(AUTHORITY, "people/#", PEOPLE_ID);              }                            @Override              protected void onCreate(Bundle savedInstanceState) {                  super.onCreate(savedInstanceState);                  Logger.d("------ Start Activity !!! ------");                                    Uri uri1 = Uri.parse("content://" + AUTHORITY + "/people");                  Logger.e("Uri:" + uri1);                  Logger.d("Match 1" + getType(uri1));                                    Uri uri2 = Uri.parse("content://" + AUTHORITY + "/people" + "/2");                                    Logger.e("Uri:" + uri2);                  Logger.d("Match 2" + getType(uri2));                                    //拼接Uri                   Uri cUri = ContentUris.withAppendedId(uri1, 15);                  Logger.e("Uri:" + cUri);                  //获取ID                   long id = ContentUris.parseId(cUri);                  Logger.d("Uri ID: " + id);              }                            private String getType(Uri uri) {                  int match = sURIMatcher.match(uri);                  switch (match)                  {                      case PEOPLE:                          return "vnd.android.cursor.dir/person";                      case PEOPLE_ID:                          return "vnd.android.cursor.item/person";                      default:                          return null;                  }              }      }  

五。扩展应用,通过ContextProvider监控数据和文件系统变化不多解释,几个例子,上代码:监控短信,彩信,电话数据库,当有新短信彩信未接电话时,获取新短信,彩信,电话数目并显示
public class MainActivity extends Activity {private Mylayout ml = null;String mcallstr, msmsstr;int mcallcount, msmscount;final static int MSG_NEW_SMS_COUNT = 2;final static int MSG_NEW_CALL_COUNT = 1;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);requestWindowFeature(Window.FEATURE_NO_TITLE);getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,WindowManager.LayoutParams.FLAG_FULLSCREEN);getWindow().setFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON,WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);mcallstr = "未接电话:";msmsstr = "未读短信:";mcallcount = findMissedCallCount();msmscount = findNewSmsCount() + findNewMmsCount();// setContentView(R.layout.activity_main);ml = new Mylayout(this);ml.setBackgroundColor(Color.BLACK);ml.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));setContentView(ml);Intent mService = new Intent(MainActivity.this, MyhallServer.class);// ��������mService.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);startService(mService);((myapp) this.getApplication()).setact(MainActivity.this);getApplicationContext().getContentResolver().registerContentObserver(Uri.parse("content://mms-sms/"), true,new newMmsContentObserver(getApplicationContext(), myHandler));getApplicationContext().getContentResolver().registerContentObserver(android.provider.CallLog.Calls.CONTENT_URI, /* * content://call_log * /calls */true,new MissedCallContentObserver(getApplicationContext(),myHandler));}@Overrideprotected void onDestroy() {// TODO Auto-generated method stubgetContentResolver().unregisterContentObserver(new newMmsContentObserver(this, myHandler));getContentResolver().unregisterContentObserver(new MissedCallContentObserver(this, myHandler));super.onDestroy();}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);return true;}// 通过HANDLER修改电话短信条数private Handler myHandler = new Handler() {public void handleMessage(Message msg) {switch (msg.what) {case MSG_NEW_SMS_COUNT:int sms = (Integer) msg.obj;Log.i("@@@@@", "msg.obj = " + msg.obj.toString());Log.i("@@@@@", "sms = " + sms);msmscount = sms;break;case MSG_NEW_CALL_COUNT:int call = (Integer) msg.obj;Log.i("@@@@@", "msg.obj = " + msg.obj.toString());Log.i("@@@@@", "call = " + call);mcallcount = call;break;default:break;}}};// 监控短信,彩信数目变化private int findNewSmsCount() {Cursor csr = null;int newSmsCount = 0;try {csr = getApplicationContext().getContentResolver().query(Uri.parse("content://sms"), null, "type = 1 and read = 0",null, null);newSmsCount = csr.getCount(); // 未读短信数目} catch (Exception e) {e.printStackTrace();} finally {if (csr != null)csr.close();}return newSmsCount;}// 监控短信,短信数目变化private int findNewMmsCount() {Cursor csr = null;int newMmsCount = 0;try {csr = getApplicationContext().getContentResolver().query(Uri.parse("content://mms/inbox"), null, "read = 0", null,null);newMmsCount = csr.getCount();// 未读彩信数目} catch (Exception e) {e.printStackTrace();} finally {if (csr != null)csr.close();}return newMmsCount;}// 监控电话数目private int findMissedCallCount() {int missedCallCount = 0;/* * Cursor csr = getContentResolver().query(Calls.CONTENT_URI, new * String[] { Calls.NUMBER, Calls.TYPE, Calls.NEW }, null, null, * Calls.DEFAULT_SORT_ORDER); *  * if (csr != null) { if (csr.moveToFirst()) { int type = * csr.getInt(csr.getColumnIndex(Calls.TYPE)); switch (type) { case * Calls.MISSED_TYPE: if (csr.getInt(csr.getColumnIndex(Calls.NEW)) == * 1) { missedCallCount = csr.getCount(); } *  * break; case Calls.INCOMING_TYPE: break; case Calls.OUTGOING_TYPE: * break; default: break; } } // release resource csr.close(); } */StringBuilder where = new StringBuilder("type = ");where.append(Calls.MISSED_TYPE);where.append(" AND new = 1");// start the queryCursor cur = null;try {cur = this.getContentResolver().query(Calls.CONTENT_URI,new String[] { Calls._ID }, where.toString(), null,Calls.DEFAULT_SORT_ORDER);if (cur != null) {missedCallCount = cur.getCount();}} catch (Exception ex) {} finally {if (cur != null) {cur.close();}}return missedCallCount;}// 监控信息数据库public class newMmsContentObserver extends ContentObserver {private Context ctx;private Handler m_handler;int newMmsCount = 0;int newSmsCount = 0;public newMmsContentObserver(Context context, Handler handler) {super(handler);ctx = context;m_handler = handler;}@Overridepublic void onChange(boolean selfChange) {newMmsCount = findNewSmsCount();newSmsCount = findNewMmsCount();Log.i("@@@@@", "newSmsCount = " + (newSmsCount + newMmsCount));m_handler.obtainMessage(MSG_NEW_SMS_COUNT,(newMmsCount + newSmsCount)).sendToTarget();}}// 监控电话数据库public class MissedCallContentObserver extends ContentObserver {private Context ctx;int missedCallCount = 0;private Handler m_handler;private static final String TAG = "MissedCallContentObserver";public MissedCallContentObserver(Context context, Handler handler) {super(handler);ctx = context;m_handler = handler;}@Overridepublic void onChange(boolean selfChange) {missedCallCount = findMissedCallCount();Log.i("@@@@@", "missedCallCount = " + missedCallCount);m_handler.obtainMessage(MSG_NEW_CALL_COUNT, missedCallCount).sendToTarget();}}public class Mylayout extends View {Context mContext = null;Bitmap tmpBitmap = null;boolean IMG_ENABLE = false;int w, h;Bitmap[] BmWeek = null;Bitmap[] BmTime = null;Bitmap[] BmDate = null;public Mylayout(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);// TODO Auto-generated constructor stubmContext = context;WindowManager wManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);Display display = wManager.getDefaultDisplay();w = display.getWidth();h = display.getHeight();tmpBitmap = Bitmap.createBitmap(w, h, Config.ARGB_8888);}public Mylayout(Context context, AttributeSet attrs) {super(context, attrs);// TODO Auto-generated constructor stubmContext = context;WindowManager wManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);Display display = wManager.getDefaultDisplay();w = display.getWidth();h = display.getHeight();tmpBitmap = Bitmap.createBitmap(w, h, Config.ARGB_8888);}public Mylayout(Context context) {super(context);// TODO Auto-generated constructor stubmContext = context;WindowManager wManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);Display display = wManager.getDefaultDisplay();w = display.getWidth();h = display.getHeight();try {tmpBitmap = Bitmap.createBitmap(w, h, Config.ARGB_8888);} catch (OutOfMemoryError e) {e.printStackTrace();tmpBitmap.recycle();System.gc();System.runFinalization();tmpBitmap = Bitmap.createBitmap(w, h, Config.ARGB_8888);}}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {// TODO Auto-generated method stubsuper.onLayout(changed, l, t, r, b);}@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {// TODO Auto-generated method stubsuper.onMeasure(widthMeasureSpec, heightMeasureSpec);}@Overrideprotected void onDraw(Canvas canvas) {// TODO Auto-generated method stub5super.onDraw(canvas);Canvas tmpCanvas = new Canvas();tmpCanvas.setBitmap(tmpBitmap);Paint p1 = new Paint();p1.setColor(Color.BLACK);p1.setStyle(Style.FILL);tmpCanvas.drawRect(0, 0, w, h, p1);// 设置字体if (!IMG_ENABLE) {Paint p = new Paint();p.setColor(Color.WHITE);p.setAntiAlias(true);p.setStrokeWidth(1);p.setStyle(Style.FILL);p.setTextSize(26);Typeface font = Typeface.create("黑体", Typeface.BOLD);p.setTypeface(font);// 显示时间p.setTextSize(80);SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");String time = sdf.format(new Date());time = time.substring(0, time.length() - 3);int fw = (int) p.measureText(time);FontMetrics fm = p.getFontMetrics();int fh = (int) Math.ceil(fm.descent - fm.top) + 2;tmpCanvas.drawText(time, (w - fw) / 2, 200, p);p.measureText(time);// 显示星期sdf = new SimpleDateFormat("EEEE");String week = sdf.format(new Date());// tmpCanvas.drawText(week, 100, 200, p);// 显示日期p.setTextSize(30);sdf = new SimpleDateFormat("yyyy-MM-dd");String date = sdf.format(new Date());date = date.substring(5, date.length());date = date + "," + week;fw = (int) p.measureText(date);tmpCanvas.drawText(date, (w - fw) / 2, 200 + 50, p);// 显示未接电话// fw = (int) p.measureText(time);// FontMetrics fm = p.getFontMetrics();// fh = (int)Math.ceil(fm.descent - fm.top) + 2;tmpCanvas.drawText(mcallstr + String.valueOf(mcallcount),(w - fw) / 2, 300, p);// 显示未读短信tmpCanvas.drawText(msmsstr + String.valueOf(msmscount),(w - fw) / 2, 350, p);} else {drawDate(tmpCanvas, 100, 500);drawTime(tmpCanvas, 100, 400);drawWeek(tmpCanvas, 300, 500);}canvas.drawBitmap(tmpBitmap, 0, 0, null);this.invalidate();}public void drawDate(Canvas canvas, int x, int y) {Bitmap bm = null;int[] imgIds = { R.drawable.r011, R.drawable.r111, R.drawable.r211,R.drawable.r311, R.drawable.r411, R.drawable.r511,R.drawable.r611, R.drawable.r711, R.drawable.r811,R.drawable.r911, R.drawable.hy11, R.drawable.h711, };int pos = x;SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");String date = sdf.format(new Date());date = date.substring(5, date.length());// canvas.drawText(date, x, y, null);for (int i = 0; i < date.length(); i++) {if (date.charAt(i) == '-') {bm = BitmapFactory.decodeResource(mContext.getResources(),imgIds[10]);} else {bm = BitmapFactory.decodeResource(mContext.getResources(),imgIds[date.charAt(i) - '0']);}canvas.drawBitmap(bm, pos, y, null);pos += bm.getWidth();}bm = BitmapFactory.decodeResource(mContext.getResources(),imgIds[11]);canvas.drawBitmap(bm, pos, y, null);}public void drawTime(Canvas canvas, int x, int y) {Bitmap bm = null;/* * int[] imgIds = {R.drawable.time_011, R.drawable.time_111, * R.drawable.time_211, R.drawable.time_311, R.drawable.time_411, * R.drawable.time_511, R.drawable.time_611, R.drawable.time_711, * R.drawable.time_811, R.drawable.time_911, R.drawable.maohao11 }; */int[] imgIds = { R.drawable.time_0, R.drawable.time_1,R.drawable.time_2, R.drawable.time_3, R.drawable.time_4,R.drawable.time_5, R.drawable.time_6, R.drawable.time_7,R.drawable.time_8, R.drawable.time_9, R.drawable.time_dot };int pos = x;SimpleDateFormat sdf = new SimpleDateFormat("HH-mm-ss");String time = sdf.format(new Date());time = time.substring(0, time.length() - 3);// canvas.drawText(time, x, y, null);for (int i = 0; i < time.length(); i++) {if (time.charAt(i) == '-') {bm = BitmapFactory.decodeResource(mContext.getResources(),imgIds[10]);} else {bm = BitmapFactory.decodeResource(mContext.getResources(),imgIds[time.charAt(i) - '0']);}canvas.drawBitmap(bm, pos, y, null);pos += bm.getWidth();}}public void drawWeek(Canvas canvas, int x, int y) {Bitmap bm = null;String[] weeks = { "星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日" };int[] imgIds = { R.drawable.time_011, R.drawable.h211,R.drawable.h311, R.drawable.h411, R.drawable.h511,R.drawable.h611, R.drawable.h711, R.drawable.hxq11 };int pos = x;SimpleDateFormat sdf = new SimpleDateFormat("EEEE");String week = sdf.format(new Date());// canvas.drawText(week, x, y, null);bm = BitmapFactory.decodeResource(mContext.getResources(),R.drawable.hxq11);canvas.drawBitmap(bm, pos, y, null);pos += bm.getWidth();for (int i = 0; i < weeks.length; i++) {if (weeks[i].equals(week)) {bm = BitmapFactory.decodeResource(mContext.getResources(),imgIds[i]);canvas.drawBitmap(bm, pos, y, null);break;}}}@Overridepublic boolean onTouchEvent(MotionEvent event) {int action = event.getAction();switch (action) {case MotionEvent.ACTION_DOWN:break;case MotionEvent.ACTION_UP:case MotionEvent.ACTION_CANCEL:break;case MotionEvent.ACTION_MOVE:break;}return true; // super.onTouchEvent(event);}}}


android 监听SD卡文件变化

    (1)创建目录监听器:                import android.os.FileObserver;               import android.util.Log;                      /**             * SD卡中的目录创建监听器。             *            * @author mayingcai           */              public class SDCardListener extends FileObserver {                            public SDCardListener(String path) {                          /*                          * 这种构造方法是默认监听所有事件的,如果使用 super(String,int)这种构造方法,                          * 则int参数是要监听的事件类型.                          */                           super(path);                     }                            @Override                    public void onEvent(int event, String path) {                                   switch(event) {                                   case FileObserver.ALL_EVENTS:                                          Log.d("all", "path:"+ path);                                          break;                                   case FileObserver.CREATE:                                          Log.d("Create", "path:"+ path);                                          break;                            }                    }              }            (2)给目录设置监听器:                      SDCardListener listener = new SDCardListener("目录");                      //开始监听               listener.startWatching();                   /*             * 在这里做一些操作,比如创建目录什么的             */                    //停止监听              listener.stopWatching();  


参考:

http://www.jcodecraeer.com/a/anzhuokaifa/androidkaifa/2012/0821/367.html

http://blog.sina.com.cn/s/blog_821e2bb10100spxv.html

http://www.android-study.com/jichuzhishi/338.html

http://blog.csdn.net/sqk1988/article/details/7756507







更多相关文章

  1. adb shell 命令详解 在Android中查看和管理sqlite数据库
  2. android 4.4 JS 和 java 交互失效的解决方法
  3. Android 数据库SQLite升级降级
  4. Android学习路线(二十六)Android数据存储
  5. Android设备中几种YUV420p转rgb视频帧方法效率比较
  6. Android Service使用方法--简单音乐播放实例
  7. Android中如何解析JSON数据

随机推荐

  1. 关于android eclipse 打包出现android-sd
  2. [UE4.4.x] 虚幻4 安卓打包
  3. 使用android画布的save()和restore()方法
  4. android 提权升级为root权限
  5. onCharacteristicChanged 回调问题
  6. Android(安卓)TextView显示html富文本格
  7. Android(安卓)首页Fragment切换常用姿势
  8. Android(安卓)使用自定义字体
  9. Android(安卓)3D翻转效果实践
  10. Handler 总结