通常在android应用中,数据都是在本应用沙盒之内的,其他外部应用不能够访问,那么如果一个应用需要访问另外一个应用的数据,怎么办呢?那就把另外一个应用的数据公布出来,比如android中的通讯录数据,这些数据是以ContentProvider方式提供与其他应用访问的。
那么我们也可以定义自己的ContentProvider来使跨应用共享数据。数据具体的存贮方式可以为数据库、文件,持久化或非持久化存储的其他形式。在这里我们还是使用sqlite数据库存贮数据吧。
老规矩,先来点基础知识。
一.基础知识
1:URI是什么?统一资源标识符,用来标识某一资源的。
通常一个Uri主要由以三部分组成:scheme、Authority、path
1.scheme:ContentProvider(内容提供者)的scheme已经由Android系统规定为:content://
2.主机名(或Authority):用于唯一标识这个ContentProvider,外部调用者可以根据这个标识来找到它。
3.路径(path):可以用来表示我们要操作的数据,路径的构建应根据业务而定,如下:
要操作persion表中id为5的记录,可以构建这样的路径:/persion/5
要操作persion表中id为20的记录的name字段, persion/name/10
要操作persion表中的所有记录,可以构建这样的路径:/persion
使用Uri类中的parse()方法获取Uri: Uri uri = Uri.parse("content://com.dongzi/persion")
上面Uri的scheme: content://
Authority: com.dongzi
path: /contact
2、UriMatcher、ContentUrist和ContentResolver
Android系统提供了两个用于操作Uri的工具类:UriMatcher 和ContentUris
UriMatcher:用于匹配Uri:
代码如下 |
复制代码 |
static final int CODES=2;
static final int CODE=1;
static final String AUTHORITY="com.dongzi"; //授权
static final UriMatcher uriMatcher; //Uri匹配
static { //注册匹配的Uri以及返回码
uriMatcher=new UriMatcher(UriMatcher.NO_MATCH); //不匹配任何路径返回-1
uriMatcher.addURI(AUTHORITY, "persion", CODES); //匹配content://com.dongzi/persion 返回2
uriMatcher.addURI(AUTHORITY, "persion/#", CODE); //匹配content://com.dongzi/persion/1234 返回1
}
|
ContentUris:用于获取Uri路径后面的ID部分,它有两个比较实用的方法:
• withAppendedId(uri, id)用于为路径加上ID部分
• parseId(uri)方法用于从路径中获取ID部分
代码如下 |
复制代码 |
//为Uri添加ID
Uri uri=Uri.parse("content://"+AUTHORITY+"/persion");
ContentUris.withAppendedId(uri, 1234);
//生成后的Uri为:content://com.dongzi/person/1234
//获取Uri后面的ID
long id=ContentUris.parseId(Uri.parse("content://com.dongzi/person/1234"));
//得到ID为:1234 |
ContentResolver提供了如下主要方法:
代码如下 |
复制代码 |
@Override
public int delete(Uri arg0, String arg1, String[] arg2) {
//该方法用于供外部应用从ContentProvider删除数据。
return 0;
}
@Override
public String getType(Uri uri) {
//该方法用于返回当前Url所代表数据的MIME类型。
return null;
}
@Override
public Uri insert(Uri uri, ContentValues values) {
//该方法用于供外部应用往ContentProvider添加数据。
return null;
}
@Override
public boolean onCreate() {
//在其它应用第一次访问它时被创建。
return false;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
//该方法用于供外部应用从ContentProvider中获取数据。
return null;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
//该方法用于供外部应用更新ContentProvider中的数据。
return 0;
}
|
这里主要说下Url所代表数据的MIME类型:
如果操作的数据属于集合类型,那么MIME类型字符串应该以vnd.android.cursor.dir/开头,
例如:要得到所有person记录的Uri为content://com.dongzi/person,那么返回的MIME类型字符串应该为:"vnd.android.cursor.dir/person"。
如果要操作的数据属于非集合类型数据,那么MIME类型字符串应该以vnd.android.cursor.item/开头,
例如:得到id为1234的person记录,Uri为content://com.dongzi/person/1234,那么返回的MIME类型字符串为:"vnd.android.cursor.item/person"。
使用ContentResolver操作ContentProvider中的数据
当外部应用需要对ContentProvider中的数据进行添加、删除、修改和查 询操作时,可以使用ContentResolver 类来完成,要获取ContentResolver 对象,可以使用Activity提供的getContentResolver()方法。ContentResolver提供了ContentProvider对应的增、删、改、查方法。
监听ContentProvider中数据的变化
如果我们需要得到数据变化通知,可以使用ContentObserver对数据(数据采用uri描述)进行通知更改以及监听。
代码如下 |
复制代码 |
//通知内容以及发生改变,同时注册了内容监听,监听到内容变化,就调用onChange方法
this.getContext().getContentResolver().notifyChange(uri, new ContentObserver(new Handler()){
public void onChange(boolean selfChange) {
//此处可以进行相应的业务处理
}
});
|
二.实战
说了那么多,是时候了解ContentProvider的使用了,我们这里采用sqlite存贮数据。当然,我们直接采用联系人数据不是更好?
1:首先我们定义DBHelper继承SQLiteOpenHelper,并建表。
代码如下 |
复制代码 |
package com.dongzi;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.database.sqlite.SQLiteOpenHelper;
public class DBHelper extends SQLiteOpenHelper {
static final String DB_NAME = "dongzi.db";
static final int DB_VERSION = 1;
static final String TABLE="persion";
static final String TABLE_COLUMN_NAME="name";
static final String TABLE_COLUMN_PHONE="phone";
static final String CREATE_TABLE = "create table persion(id integer primary key autoincrement,name varchar(40) phone varchar(40))";
static final String DRPO_TABLE="drop table if exists persion";
public DBHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_TABLE);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
//这里其实是比较版本,然后升级数据库的,比如说是增加一个字段,或者删除一个字段,或者增加表
db.execSQL(DRPO_TABLE);
onCreate(db);
}
}
|
2:然后定义MyContentProvider继承ContentProvider,并且在类加载时候初始化UriMatcher匹配,以及授权AUTHORITY,同时,这个ContentProvider需要在AndroidManifest.xml中进行注册,并添加授权。
代码如下:
代码如下 |
复制代码 |
package com.dongzi;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.net.Uri;
import android.text.TextUtils;
public class MyContentProvider extends ContentProvider {
DBHelper dbHelper=null;
//MIME类型
static final String PERSIONS_TYPE="vnd.android.cursor.dir/person";
static final String PERSION_ITEM_TYPE="vnd.android.cursor.item/person";
//返回码
static final int CODES=2;
static final int CODE=1;
//授权
static final String AUTHORITY="com.dongzi"; //授权
static final UriMatcher uriMatcher; //Uri匹配
static { //注册匹配的Uri以及返回码
uriMatcher=new UriMatcher(UriMatcher.NO_MATCH); //不匹配任何路径返回-1
uriMatcher.addURI(AUTHORITY, "persion", CODES); //匹配content://com.dongzi/persion 返回2
uriMatcher.addURI(AUTHORITY, "persion/#", CODE); //匹配content://com.dongzi/persion/1234 返回1
}
private void init(){
//为Uri添加ID
Uri uri=Uri.parse("content://"+AUTHORITY+"/persion");
ContentUris.withAppendedId(uri, 1234);
//生成后的Uri为:content://com.dongzi/person/1234
//获取Uri后面的ID
long id=ContentUris.parseId(Uri.parse("content://com.dongzi/person/1234"));
//得到ID为:1234
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
//该方法用于供外部应用从ContentProvider删除数据。
SQLiteDatabase db=dbHelper.getWritableDatabase();
int count=0;
switch(uriMatcher.match(uri)){
case CODES:
count = db.delete(DBHelper.DB_NAME, selection, selectionArgs);
break;
case CODE:
// 下面的方法用于从URI中解析出id,对这样的路径content://com.dongzi/persion/1234
// 进行解析,返回值为10
long id = ContentUris.parseId(uri);
String where = "id=" + id;// 删除指定id的记录
where += !TextUtils.isEmpty(selection) ? " and (" + selection + ")" : "";// 把其它条件附加上
count = db.delete(DBHelper.DB_NAME, where, selectionArgs);
break;
default:throw new IllegalArgumentException("throw Uri:"+uri.toString());
}
db.close();
return count;
}
@Override
public String getType(Uri uri) {
//该方法用于返回当前Url所代表数据的MIME类型。
switch(uriMatcher.match(uri)){
case CODES:
return PERSIONS_TYPE; //这里CODES代表集合,故返回的是集合类型的MIME
case CODE:
return PERSION_ITEM_TYPE;
default:throw new IllegalArgumentException("throw Uri:"+uri.toString());
}
}
@Override
public Uri insert(Uri uri, ContentValues values) {
//该方法用于供外部应用往ContentProvider添加数据。
SQLiteDatabase db= dbHelper.getWritableDatabase();
long id=0;
//匹配Uri
switch(uriMatcher.match(uri)){
//返回码
case CODES:
id=db.insert(DBHelper.TABLE, DBHelper.TABLE_COLUMN_NAME, values);// 返回的是记录的行号,主键为int,实际上就是主键值
return ContentUris.withAppendedId(uri, id);
case CODE:
id=db.insert(DBHelper.TABLE, DBHelper.TABLE_COLUMN_NAME, values);// 返回的是记录的行号,主键为int,实际上就是主键值
String path = uri.toString();
return Uri.parse(path.substring(0, path.lastIndexOf("/"))+id); // 替换掉id
default:throw new IllegalArgumentException("throw Uri:"+uri.toString());
}
}
@Override
public boolean onCreate() {
//在其它应用第一次访问它时被创建。
dbHelper =new DBHelper(getContext());
return false;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
//该方法用于供外部应用从ContentProvider中获取数据。
SQLiteDatabase db=dbHelper.getWritableDatabase();
Cursor cursor=null;
switch(uriMatcher.match(uri)){
case CODES:
cursor=db.query(DBHelper.DB_NAME, projection, selection, selectionArgs, null, null, sortOrder);
break;
case CODE:
//下面的方法用于从URI中解析出id,对这样的路径content://com.dongzi/persion/1234
// 进行解析,返回值为10
long id = ContentUris.parseId(uri);
String where = "id=" + id;// 获取指定id的记录
where += !TextUtils.isEmpty(selection) ? " and (" + selection + ")" : "";// 把其它条件附加上
cursor=db.query(DBHelper.DB_NAME, projection, where, selectionArgs, null, null, sortOrder);
break;
default:break;
}
return cursor;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
//该方法用于供外部应用更新ContentProvider中的数据。
return 0;
}
}
|
如果我们基本了解了上述说的基础知识,那么这些代码不难看懂,其实也非常简单,不直接操作DBHelper类,而是通过ContentProvider间接操作,而操作ContentProvider又是太通过
ContentResolver这个类,实现不同应用都可以访问这些数据。
本文章介绍了一篇关于手机开发中的android开时的 ui高效做法,有需要了解的朋友可以参考一下下哦。
一、选择恰当的图像尺寸
视图背景图总是会填充整个视图区域,图像尺寸的不适合会导致图像的自动缩放,为了避免这种情况,我们可以先将图片进行缩放到视图的大小。
代码如下 |
复制代码 |
originalImage = Bitmap.createScaledBitmap(
originalImage, //被缩放图
view.getWidth(), //视图宽度
view.getHright(), //视图高度
true //双限行过滤器
);
|
二、去掉不需要的默认窗口背景
在默认情况下,窗口有一个不透明的背景,有时候我们并不需要他,就可以去掉他。因为更新看不见的窗口是浪费时间的。
去掉的方法:
1.代码实现:
代码如下 |
复制代码 |
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//删除窗口背景
getWindow().setBackgroundDrawable(null);
}
|
2.xml里实现:
首先去顶你的res/xml/styles.xml里有
代码如下 |
复制代码 |
<resources>
<style name="NoBackGroundTheme" parent="android:Theme">
<item name="android:windowBackground">@null</item>
</style>
</resources>
然后在你的manifest.xml里声明
<activity android:name="MyActivity" android:theme="@style/NoBackGroundTheme">
......
</activity>
|
三、尽可能的使用简单的布局和视图
如果一个窗口包含很多的视图,那么启动时间长、测量时间长、绘制时间长、布局时间长;
如果视图树深度太深,会导致StackOverflowException异常,和用户界面反映会很慢很慢。
解决的方法:
1.使用TextView的复合drawables,减少层次
如有这样的布局:
代码如下 |
复制代码 |
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="fill_parent"
android:layout_height="fill_parent">
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content" android:text="@string/hello" />
<Image android:layout_width="wrap_content"
android:layout_height="wrap_content" android:id="@+id/image" android:background="@drawable/icon" />
</LinearLayout>
|
我们可以这样来取代他,从而来将少层次:
代码如下 |
复制代码 |
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content" android:text="@string/hello" android:drawableRight="@drawable/icon"/>
|
2.使用ViewStub延迟展开视图
默认情况下,使用ViewStub包含的视图是不可见的。
代码如下 |
复制代码 |
<ViewStub android:layout_width="fill_parent" android:layout_height="fill_parent" android:id="@+id/vs" android:layout="@layout/main"/>
|
这个里面包含的main视图是不会展现出来的,如果需要展现出来需要代码的处理
代码如下 |
复制代码 |
findViewById(R.id.vs).setVisibility(View.VISIBLE);
者
findViewById(R.id.vs).inflate();
|
3.使用<merge>合并视图
默认情况下,布局文件的根作为一个借点加入到父视图中,如果使用<merge>可以避免根节点。
如果最外层的布局是FrameLayout,那么可以使用merge替换掉,引用官方说明:
Obviously, using <merge /> works in this case because the parent of an activity's content view is always a FrameLayout. You could not apply this trick if your layout was using a LinearLayout as its root tag for instance.
代码如下 |
复制代码 |
<merge
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent">
.....
</merge>
|
4.使用RelativeLayout减少层次
5.自定义布局
Windows操作系统下,今天进行Android4.0安装时需要更新软件包,下载下来后自动安装出现这样一个问题:
解决办法:
1.进入sdk的temp文件夹,下载好后会有一个tools_r15-windows.zip(版本号可能会不一样)
2.解压此文件,如解压成tools_r15-windows
3.进入tools_r15-windows文件夹,将tools_r15-windows里的文件复制
4.覆盖sdk根目录的tools文件夹中的文件
本文章来解决在android2.3.4没有google map的真机上增加google map,有需要的同学可以参考一下。
使用Google Map时需依赖以下:
system/app
Location.apk(2.3.4版本不需要这个了)
NetworkLocation.apk
Maps.apk
Street.apk(2.3.4版本不需要这个了)
system/etc/permissions
com.google.android.maps.xml
system/framework
com.google.android.maps.jar
1、通过工具获得root权限;
2、adb shell su回车 mount -o remount,rw /dev/block/mtdblock3 /system回车
3、adb -d push com.google.android.maps.jar /system/framework/ 或其它手机助手或豌豆夹等工具上传文件
同时还有文件/system/etc/permissions/com.google.android.maps.xml
NetworkLocation.apk放到system/app
4、把真机中/etc/permissions/platform.xml文件取出来编辑:<permissions>
<permissions>
本文章介绍一篇关于在手机开发中会出现的一些问题及全局异常处理的处理实现,有需要的朋友可以参考一下本文章。
代码如下 |
复制代码 |
package org.wp.activity;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.Thread.UncaughtExceptionHandler;
import java.lang.reflect.Field;
import java.util.Arrays;
import java.util.Properties;
import java.util.TreeSet;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.os.Build;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;
/**
*
*
* UncaughtExceptionHandler:线程未捕获异常控制器是用来处理未捕获异常的。
* 如果程序出现了未捕获异常默认情况下则会出现强行关闭对话框
* 实现该接口并注册为程序中的默认未捕获异常处理
* 这样当未捕获异常发生时,就可以做些异常处理操作
* 例如:收集异常信息,发送错误报告 等。
*
* UncaughtException处理类,当程序发生Uncaught异常的时候,由该类来接管程序,并记录发送错误报告.
*/
public class CrashHandler implements UncaughtExceptionHandler {
/** Debug Log Tag */
public static final String TAG = "CrashHandler";
/** 是否开启日志输出, 在Debug状态下开启, 在Release状态下关闭以提升程序性能 */
public static final boolean DEBUG = true;
/** CrashHandler实例 */
private static CrashHandler INSTANCE;
/** 程序的Context对象 */
private Context mContext;
/** 系统默认的UncaughtException处理类 */
private Thread.UncaughtExceptionHandler mDefaultHandler;
/** 使用Properties来保存设备的信息和错误堆栈信息 */
private Properties mDeviceCrashInfo = new Properties();
private static final String VERSION_NAME = "versionName";
private static final String VERSION_CODE = "versionCode";
private static final String STACK_TRACE = "STACK_TRACE";
/** 错误报告文件的扩展名 */
private static final String CRASH_REPORTER_EXTENSION = ".cr";
/** 保证只有一个CrashHandler实例 */
private CrashHandler() {
}
/** 获取CrashHandler实例 ,单例模式 */
public static CrashHandler getInstance() {
if (INSTANCE == null)
INSTANCE = new CrashHandler();
return INSTANCE;
}
/**
* 初始化,注册Context对象, 获取系统默认的UncaughtException处理器, 设置该CrashHandler为程序的默认处理器
*
* @param ctx
*/
public void init(Context ctx) {
mContext = ctx;
mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
Thread.setDefaultUncaughtExceptionHandler(this);
}
/**
* 当UncaughtException发生时会转入该函数来处理
*/
@Override
public void uncaughtException(Thread thread, Throwable ex) {
if (!handleException(ex) && mDefaultHandler != null) {
// 如果用户没有处理则让系统默认的异常处理器来处理
mDefaultHandler.uncaughtException(thread, ex);
} else {
// Sleep一会后结束程序
// 来让线程停止一会是为了显示Toast信息给用户,然后Kill程序
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
Log.e(TAG, "Error : ", e);
}
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(10);
}
}
/**
* 自定义错误处理,收集错误信息 发送错误报告等操作均在此完成. 开发者可以根据自己的情况来自定义异常处理逻辑
*
* @param ex
* @return true:如果处理了该异常信息;否则返回false
*/
private boolean handleException(Throwable ex) {
if (ex == null) {
return true;
}
final String msg = ex.getLocalizedMessage();
// 使用Toast来显示异常信息
new Thread() {
@Override
public void run() {
// Toast 显示需要出现在一个线程的消息队列中
Looper.prepare();
Toast.makeText(mContext, "程序出错啦:" + msg, Toast.LENGTH_LONG).show();
Looper.loop();
}
}.start();
// 收集设备信息
collectCrashDeviceInfo(mContext);
// 保存错误报告文件
String crashFileName = saveCrashInfoToFile(ex);
// 发送错误报告到服务器
sendCrashReportsToServer(mContext);
return true;
}
/**
* 收集程序崩溃的设备信息
*
* @param ctx
*/
public void collectCrashDeviceInfo(Context ctx) {
try {
// Class for retrieving various kinds of information related to the
// application packages that are currently installed on the device.
// You can find this class through getPackageManager().
PackageManager pm = ctx.getPackageManager();
// getPackageInfo(String packageName, int flags)
// Retrieve overall information about an application package that is installed on the system.
// public static final int GET_ACTIVITIES
// Since: API Level 1 PackageInfo flag: return information about activities in the package in activities.
PackageInfo pi = pm.getPackageInfo(ctx.getPackageName(), PackageManager.GET_ACTIVITIES);
if (pi != null) {
// public String versionName The version name of this package,
// as specified by the <manifest> tag's versionName attribute.
mDeviceCrashInfo.put(VERSION_NAME, pi.versionName == null ? "not set" : pi.versionName);
// public int versionCode The version number of this package,
// as specified by the <manifest> tag's versionCode attribute.
mDeviceCrashInfo.put(VERSION_CODE, pi.versionCode);
}
} catch (NameNotFoundException e) {
Log.e(TAG, "Error while collect package info", e);
}
// 使用反射来收集设备信息.在Build类中包含各种设备信息,
// 例如: 系统版本号,设备生产商 等帮助调试程序的有用信息
// 返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段
Field[] fields = Build.class.getDeclaredFields();
for (Field field : fields) {
try {
// setAccessible(boolean flag)
// 将此对象的 accessible 标志设置为指示的布尔值。
// 通过设置Accessible属性为true,才能对私有变量进行访问,不然会得到一个IllegalAccessException的异常
field.setAccessible(true);
mDeviceCrashInfo.put(field.getName(), field.get(null));
if (DEBUG) {
Log.d(TAG, field.getName() + " : " + field.get(null));
}
} catch (Exception e) {
Log.e(TAG, "Error while collect crash info", e);
}
}
}
/**
* 保存错误信息到文件中
*
* @param ex
* @return
*/
private String saveCrashInfoToFile(Throwable ex) {
Writer info = new StringWriter();
PrintWriter printWriter = new PrintWriter(info);
// printStackTrace(PrintWriter s)
// 将此 throwable 及其追踪输出到指定的 PrintWriter
ex.printStackTrace(printWriter);
// getCause() 返回此 throwable 的 cause;如果 cause 不存在或未知,则返回 null。
Throwable cause = ex.getCause();
while (cause != null) {
cause.printStackTrace(printWriter);
cause = cause.getCause();
}
// toString() 以字符串的形式返回该缓冲区的当前值。
String result = info.toString();
printWriter.close();
mDeviceCrashInfo.put(STACK_TRACE, result);
try {
long timestamp = System.currentTimeMillis();
String fileName = "crash-" + timestamp + CRASH_REPORTER_EXTENSION;
// 保存文件
FileOutputStream trace = mContext.openFileOutput(fileName, Context.MODE_PRIVATE);
mDeviceCrashInfo.store(trace, "");
trace.flush();
trace.close();
return fileName;
} catch (Exception e) {
Log.e(TAG, "an error occured while writing report file...", e);
}
return null;
}
/**
* 把错误报告发送给服务器,包含新产生的和以前没发送的.
*
* @param ctx
*/
private void sendCrashReportsToServer(Context ctx) {
String[] crFiles = getCrashReportFiles(ctx);
if (crFiles != null && crFiles.length > 0) {
TreeSet<String> sortedFiles = new TreeSet<String>();
sortedFiles.addAll(Arrays.asList(crFiles));
for (String fileName : sortedFiles) {
File cr = new File(ctx.getFilesDir(), fileName);
postReport(cr);
cr.delete();// 删除已发送的报告
}
}
}
/**
* 获取错误报告文件名
*
* @param ctx
* @return
*/
private String[] getCrashReportFiles(Context ctx) {
File filesDir = ctx.getFilesDir();
// 实现FilenameFilter接口的类实例可用于过滤器文件名
FilenameFilter filter = new FilenameFilter() {
// accept(File dir, String name)
// 测试指定文件是否应该包含在某一文件列表中。
public boolean accept(File dir, String name) {
return name.endsWith(CRASH_REPORTER_EXTENSION);
}
};
// list(FilenameFilter filter)
// 返回一个字符串数组,这些字符串指定此抽象路径名表示的目录中满足指定过滤器的文件和目录
return filesDir.list(filter);
}
private void postReport(File file) {
// TODO 使用HTTP Post 发送错误报告到服务器
// 这里不再详述,开发者可以根据OPhoneSDN上的其他网络操作
// 教程来提交错误报告
}
/**
* 在程序启动时候, 可以调用该函数来发送以前没有发送的报告
*/
public void sendPreviousReportsToServer() {
sendCrashReportsToServer(mContext);
}
}
|