您的位置:首页 > 编程语言 > PHP开发

漫谈anroid软件设计中的contentprovider及其应用

2013-07-10 13:00 197 查看
一.概述:
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。
修改数据
intupdate(Uri uri, ContentValues values, String where, String[] selectionArgs) 更新Uri指定位置的数据,返回所影响的行数
添加数据
Uri insert(Uri url, ContentValues values) 将一组数据插入到Uri 指定的地方,返回新inserted的URI
删除数据
int
delete
(Uri url, String where, String[] selectionArgs)
删除指定
Uri
并且符合一定条件的数据,返回所影响的行数
二。创建ContentProvider:
 
要创建我们自定义的ContentProvider,我们需要遵循以下几步:

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

2.定义一个名为CONTENT_URI,并且是publicstatic final的Uri类型的类变量,你必须为其指定一个唯一的字符串值,最好的方案是以类的全名称,如:
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类型)
比如,一个请求列车信息的URI如content://com.example.transportationprovider/trains/122可能就会返回typevnd.android.cursor.item/vnd.example.rail这样一个MIME类型。
vnd.android.cursor.dir/vnd.yourcompanyname.contenttype(多个记录的MIME类型)
比如,一个请求所有列车信息的URI如content://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类:

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


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

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

我会在随后的URI介绍中对其说明,android
调用第三方应用也会使用URI
。Android
在android.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(intrecNo, 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() 方法以对联系人信息簿中进行数据的添加:
 这样我们就可以调用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:daming@163.com


其一般由三部分组成:访问资源的命名机制。 
存放资源的主机名。 
资源自身的名称,由路径表示。 
Android上可用的每种资源-图像、视频片段等都可以用Uri来表示。
Android的Uri由以下三部分组成:"content://"、数据的路径、标示ID(可选)
Android上可用的每种资源-图像、视频片段等都可以用Uri来表示。
举些例子,如: 
所有联系人的Uri:content://contacts/people
某个联系人的Uri:content://contacts/people/5
所有图片Uri:content://media/external
某个图片的Uri:content://media/external/images/media/4
我们很经常需要解析Uri,并从Uri中获取数据。
Android系统提供了两个用于操作Uri的工具类,分别为UriMatcher和ContentUris。
虽然这两类不是非常重要,但是掌握它们的使用,会便于我们的开发工作。
下面就一起看一下这两个类的作用。

2.UriMatcher
UriMatcher 类主要用于匹配Uri.
 
使用方法如下。
首先第一步,初始化:
view plaincopy to clipboardprint?UriMatcher matcher = new UriMatcher(UriMatcher.NO_MATCH);  
 第二步注册需要的Uri:
view plaincopy to clipboardprint?matcher.addURI("com.yfz.Lesson", "people", PEOPLE);  
matcher.addURI("com.yfz.Lesson", "person/#", PEOPLE_ID);  
  
第三部,与已经注册的Uri进行匹配:
 Uri uri = Uri.parse("content://" + "com.yfz.Lesson" + "/people");
intmatch = 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 plaincopy to clipboardprint?Uri uri = Uri.parse("content://com.yfz.Lesson/people")  
 通过withAppendedId方法,为该Uri加上ID
view plaincopy to clipboardprint?Uri resultUri = ContentUris.withAppendedId(uri, 10);  
 最后resultUri为: content://com.yfz.Lesson/people/10
 
2)从路径中获取ID: parseId(uri)
view plaincopy to clipboardprint?Uri uri = Uri.parse("content://com.yfz.Lesson/people/10")  
long personid = 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 intPEOPLE = 1;
private static final intPEOPLE_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) {
intmatch = 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;
intmcallcount, msmscount;
final static intMSG_NEW_SMS_COUNT = 2;
final static intMSG_NEW_CALL_COUNT = 1;

@Override
protected 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));
}

@Override
protected void onDestroy() {
// TODO Auto-generated method stub
getContentResolver().unregisterContentObserver(
new newMmsContentObserver(this, myHandler));
getContentResolver().unregisterContentObserver(
new MissedCallContentObserver(this, myHandler));
super.onDestroy();
}

@Override
public 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:
intsms = (Integer) msg.obj;
Log.i("@@@@@", "msg.obj = " + msg.obj.toString());
Log.i("@@@@@", "sms = " + sms);
msmscount = sms;
break;
case MSG_NEW_CALL_COUNT:
intcall = (Integer) msg.obj;
Log.i("@@@@@", "msg.obj = " + msg.obj.toString());
Log.i("@@@@@", "call = " + call);
mcallcount = call;
break;
default:
break;
}
}
};

// 监控短信,彩信数目变化
private intfindNewSmsCount() {
Cursor csr = null;
intnewSmsCount = 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 intfindNewMmsCount() {
Cursor csr = null;
intnewMmsCount = 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 intfindMissedCallCount() {
intmissedCallCount = 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()) { inttype =
* 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 query
Cursor 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;
intnewMmsCount = 0;
intnewSmsCount = 0;

public newMmsContentObserver(Context context, Handler handler) {
super(handler);
ctx = context;
m_handler = handler;
}

@Override
public 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;
intmissedCallCount = 0;
private Handler m_handler;
private static final String TAG = "MissedCallContentObserver";

public MissedCallContentObserver(Context context, Handler handler) {
super(handler);
ctx = context;
m_handler = handler;
}

@Override
public 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;
intw, h;
Bitmap[] BmWeek = null;
Bitmap[] BmTime = null;
Bitmap[] BmDate = null;

public Mylayout(Context context, AttributeSet attrs, intdefStyle) {
super(context, attrs, defStyle);
// TODO Auto-generated constructor stub
mContext = 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 stub
mContext = 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 stub
mContext = 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);
}

}

@Override
protected void onLayout(boolean changed, intl, intt, intr, intb) {
// TODO Auto-generated method stub
super.onLayout(changed, l, t, r, b);

}

@Override
protected void onMeasure(intwidthMeasureSpec, intheightMeasureSpec) {
// TODO Auto-generated method stub
super.onMeasure(widthMeasureSpec, heightMeasureSpec);

}

@Override
protected void onDraw(Canvas canvas) {
// TODO Auto-generated method stub5
super.onDraw(canvas);
Canvas tmpCanvas = new Canvas();
tmpCanvas.setBitmap(tmpBitmap);
Paintp1 = new Paint();
p1.setColor(Color.BLACK);
p1.setStyle(Style.FILL);
tmpCanvas.drawRect(0, 0, w, h, p1);
// 设置字体
if (!IMG_ENABLE) {
Paintp = 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);
intfw = (int) p.measureText(time);
FontMetrics fm = p.getFontMetrics();
intfh = (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, intx, inty) {

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, };
intpos = 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 (inti = 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, intx, inty) {
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 };

intpos = 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 (inti = 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, intx, inty) {
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 };
intpos = 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 (inti = 0; i < weeks.length; i++) {
if (weeks[i].equals(week)) {
bm = BitmapFactory.decodeResource(mContext.getResources(),
imgIds[i]);
canvas.drawBitmap(bm, pos, y, null);
break;
}
}
}

@Override
public boolean onTouchEvent(MotionEvent event) {
intaction = 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(intevent, 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


 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息