参考代码:
./packages/providers/MediaProvider/src/com/android/providers/media/
MediaProvider.java
MediaScannerReceiver.java
MediaScannerService.java
MediaUpgradeReceiver.java
MtpReceiver.java
MtpService.java
./frameworks/base/media/java/android/media/
MediaScanner.java
./frameworks/base/media/java/android/mtp/
MtpDatabase.java
MtpServer.java
MtpStorage.java
MtpStorageInfo.java
./frameworks/base/media/jni/
android_media_MediaScanner.cpp
android_mtp_MtpDatabase.cpp
android_mtp_MtpServer.cpp
./frameworks/av/media/mtp/
MtpServer.h
MtpServer.cpp
MediaProvider主要用于创建媒体库的数据库表。对它的流程理解主要分为MTP流程、MediaScanner流程以及MediaProvider本身流程。
关于MeidaScanner和MediaProvider网上有较多的解释,这里主要说一下MTP的流程。
MTP流程
MediaProvider通过MtpReceiver(MtpReceiver.java::onReceive,31~42)建立了对于Usb接口的关联,一旦接收到usbState状态变化,则调用handleUsbState函数(MtpReceiver::handleUsbState,44~65),一旦发现UsbState是MTP(Media Transfer Protocal)或者是PTP(Picture Transfer Protocal)时就会启动MtpService服务(MtpService.java)。在MTPService中又建立了对于StorageEvent的监听,一旦Storage有Event发生,MtpServer(MtpServer.java)和MtpDatabase(MtpDataBase.java)函数就会被响应,具体看函数代码(MtpService.java::addStorageLocked 254~266)
private void addStorageLocked(StorageVolume volume) {
...
if (mDatabase != null) {
//MtpDatabase添加存储数据信息 1
mDatabase.addStorage(storage);
}
if (mServer != null) {
//mServer添加存储数据信息 2
mServer.addStorage(storage);
}
}
1 中只是建立了一个关于数据路径到数据的Map映射,关键还是看2
在2中唤起了一个native 函数android_mtp_MtpServer_add_storage,并由该函数调用MtpServer.cpp中的addStorage方法(android_mtp_MtpServer.cpp::120~150)
static void
android_mtp_MtpServer_add_storage(JNIEnv *env, jobject thiz, jobject jstorage)
{
...
server->addStorage(storage);
...
}
通过该方法由sendStoreAdded(storage->getStorageID()); //MtpServer.cpp::addStorage ,121行
发出一个MTP_EVENT_STORE_ADDED事件(MtpServer.cpp:: sendStoreAdded ,255~258行)
void MtpServer::sendStoreAdded(MtpStorageID id) {
ALOGV("sendStoreAdded %08X\n", id);
sendEvent(MTP_EVENT_STORE_ADDED, id);
}
由MtpServer的run接收到该Event后通过handleRequest函数分发执行该事 件响应(MtpServer.java:: run 153~228) 。
void MtpServer::run() {
...
if (handleRequest()) {...}
...
}
触发doSendObjectInfo(MtpResponseCode MtpServer::doSendObjectInfo 818~923),在该函数中MtpDatabase.beginSendObject函数被调用。
MtpResponseCode MtpServer::doSendObjectInfo() {
...
MtpObjectHandle handle = mDatabase->beginSendObject((const char*)path, format, parent, storageID, mSendObjectFileSize, modifiedTime);
...
}
从而在 doSendObjectInfo中MediaProvider插入该数据信息(MtpDatabase.java::doSendObjectInfo 206~304行)
private int beginSendObject(String path, int format, int parent,
int storageId, long size, long modified) {
...
Uri uri = mMediaProvider.insert(mPackageName, mObjectsUri, values);
...
}
同样,在MtpService.java中还有一个removeStorage 事件(MtpService.java::removeStorage 268~282)
private void removeStorageLocked(StorageVolume volume) {
...
if (mDatabase != null) {
mDatabase.removeStorage(storage);
}
if (mServer != null) {
mServer.removeStorage(storage);
}
}
由该函数唤起了native的android_mtp_MtpServer_remove_storage方法(android_mtp_MtpServer.cpp, 152~166)
static void
android_mtp_MtpServer_remove_storage(JNIEnv *env, jobject thiz, jint storageId)
{
...
server->removeStorage(storage);
...
}
,过渡到MtpServer.cpp中的removeStorage函数(124~134)
void MtpServer::removeStorage(MtpStorage* storage) {
Mutex::Autolock autoLock(mMutex);
...
sendStoreRemoved(storage->getStorageID());
...
}
,并通过sendStoreRemoved函数触发MTP_EVENT_STORE_REMOVED事件,并由run函数接收到该事件后handleRequest到doSendObject函数中,并在该函 数最后调用mDatabase->endSendObjec去通知MediaScanner,canMtpFile。
MtpServer.cpp 915~986
MtpResponseCode MtpServer::doSendObject() {
...
done:
// reset so we don't attempt to send the data back
mData.reset();
mDatabase->endSendObject(mSendObjectFilePath, mSendObjectHandle, mSendObjectFormat, result == MTP_RESPONSE_OK);
...
}
MtpDatabase.java 306~340
private void endSendObject(String path, int handle, int format, boolean succeeded) {
...
mMediaScanner.scanMtpFile(path, mVolumeName, handle, format);
...
}
可参考:http://blog.csdn.net/innost/article/details/8876392
MediaScanner流程
这块的内容太多了,我就不具体介绍,需要的请参考
http://wenku.baidu.com/view/9151d3d349649b6648d747d2.html
和
深入理解Android 卷1 第10章
这里紧接着上面的函数,当MtpDatabase:: endSendObject执行了mMediaScanner.scanMtpFile函数后,便会由scanMtpFile函数通过MediaFile的类型判断,通知是否去执行MediaProvider的update操作。
MediaScanner.java 1477~1530行
public void scanMtpFile(String path, String volumeName, int objectHandle, int format) {
…
if (!MediaFile.isAudioFileType(fileType) && !MediaFile.isVideoFileType(fileType) && !MediaFile.isImageFileType(fileType) && !MediaFile.isPlayListFileType(fileType)) {
...
mMediaProvider.update(Files.getMtpObjectsUri(volumeName), values, "_id=?", whereArgs);
...
}
注:深入理解Android 卷1 第10章 图10-2MediaScanner扫描流程图将该过程归 纳的很详细,建议看一下。
与这个动作保持平行的是开机启动时,会由系统调用MediaScanner执行一次scanFile操作(MeidaScanner.java::scanFile 531~536行),并通过doScanFile函数中的endFile方法去判定是应该执行MediaProvider的update还是insert操作。
MediaProvider 流程
关于MediaProvider,虽然代码较多,但是主要还是对于媒体数据库的操作以及通知MediaScanner扫描文件信息。
具体可参考http://blog.csdn.net/evilcode/article/details/6321803
App Store的审核是出了名的严格,相信大家也都略有耳闻,有的时候很细小的东西也会被审核小组发现并拒绝上线。其实苹果官方提供了一份详细审核指南,包括22大项100多小项的拒绝上线条款,而且条款在不断的增加中,还包含一些模棱两可的条例,所以稍有“闪失”,App就有可能被拒绝。但是有一点比较好的地方,每次遭到拒绝的时候,苹果会给出拒绝的理由,并指出你违反了审核指南的哪一条,开发者可以根据评审小组给的回复修改App重新提交。下面我们讨论一下常见的被拒绝的原因。
1 功能问题
我们在发布应用之前一定要对产品进行认真的测试,如果在审核中出现了程序崩溃,或者有什么程序错误,无疑这是会被审核小组拒绝的。如果我们想发布一个演示版的程序,通过它给客户演示这也是不会被通过的。应用的功能与描述不相符,或者应用中含有欺诈虚假的功能将被拒绝,比如在应用中有一个按钮,但是这个按钮的功能点击是没有反应,不能点击,这样的程序不会通过。
苹果不允许访问私有API,有浏览器的网络程序必须使用iOS WebKit框架和WebKit JavasScript。还有就是几点比较头痛的规则,如果你的App没有什么显著的功能或者没有长久娱乐价值会被拒绝,你的应用在市场中已经存在了,尤其是比较多的时候会被拒绝,这几点完全是由审核小组掌握的你的命运了。
2 用户界面问题
苹果审核指南规定开发者的应用必须遵守苹果《iOS用户界面指导原则》中解释的所有条款和条件,如果违反了苹果的设计原则,会被拒绝上线,所以开发者在设计和开发产品之前一定要认真阅读《iOS用户界面指导原则》,这些原则中也渗透着苹果产品的一些理念,不仅是为了避免程序被拒绝而应该看,为了设计出更好的App,开发者们也应该认真看看。苹果不允许开发者更改自身按键的功能,声音按键以及静音按键,如果开发者使用了这些按键并利用它们做一些别的功能,将会被拒绝。
3 商业问题
要发布的应用中首先不能侵犯苹果公司的商标及版权,简单的说,在应用中不能出现苹果的图标,被咬了一口的苹果是不能出现在你的程序中的,不能使用类似苹果公司现在产品的相关的名字为应用命名,涉及到iPhone、iPad、iTunes等相关或者相近的名字都是不可以的,苹果认为这会误导用户,认为该应用是来自苹果公司的产品,误导用户认为该应用是受到苹果的肯定与认可的,也是不行的。
私自使用受保护的第三方材料(商标、版权、商业机密、其它私有内容),需要提供版权认可。如果你的应用涉及到第三方版权的信息,开发者们要仔细考虑考虑了,由于国内开放者对版权法律意思比较淡薄,总会忽视这一点,然而这一点是非常致命的。苹果处理这种被起诉的侵权应用,最轻的处罚是应用下架,有的需要将开发者账户里的钱转到起诉者账户,再严重就是,起诉者将你告上法庭,除了自己账户中的钱被扣除外还要另赔付起诉者相关费用。
4 不当内容
一些不合适,不和*谐的内容,苹果当然不会允许上架的,比如具有诽*谤,人身攻*击的应用,含有暴*力倾向的应用,低*俗、令人反感、厌恶的应用,赤*裸*裸的色*情应用。含有赌*博性质的应用必须并且必须明确表示苹果不是发起者,也没有以任何方式参与活动。这些条款一般由审核小组主观判断是否通过,也有漏网之鱼上架,有的应用苹果会强制下架。
5 其它问题
关于宗教、文化或种族群体的引用或评论包含诽谤性、攻击性或自私性内容的应用不会被通过;使用第三方支付的应用会被拒绝;模仿iPod界面的应用将会被拒绝;怂恿用户造成设备损坏的应用会被拒绝,这里有个小故事,有一款应用,功能是比比谁将设备扔的高,最后算积分,最后这个应用始终没能上架,因为在测试应用的时候就摔坏了2部手机。未获得用户同意便向用户发送推送通知,要求用户共享个人信息的应用都会被拒绝。
From http://iosbook1.com/?p=287
转自:http://liuminqian.github.io/blog/2013/08/25/ti-gao-zai-xcodeshang-de-gong-zuo-xiao-lu/
Key words: Xcode, 效率
对于在Xcode上提高工作效率,内功在这不提,对于外力,我将它分为三类: 工具、快捷键和小技巧。主要获得的路径是通过平时积累和看 WWDC12 上的 Session 402:Working Efficiently with Xcode。
一、工具类 (可参考:CocoaChina工具开发库) 主要推荐: 1. 搜索工具: alfred介绍: 让你搜索您的Mac OS更快,更快,更快的!支持本地和网络搜索 下载地址: http://www.alfredapp.com2. 调试工具: ponyDebugger
介绍: Network Traffic Debugging、Core Data Browser、View Hierarchy Debugging。 还有其他工具和技巧,下回分享,在此不再详细阐述。 使用教程:1) http://iiiyu.com/2013/01/14/simple-configuration-ponydebugger 2) https://github.com/square/PonyDebugger3. 代码自动补全的两个工具:Xcode自带的Code Snippets和Dash 1)Code Snippets
介绍:Xcode 4 自带代码片段管理工具 使用教程: (1)http://blog.cnrainbird.com/index.php/2012/11/26/xcode4_de_zi_dong_wan_cheng_gong_neng_code_sense_or_code_snip(pet (网站打)开比较慢) 扩展:(建议将3,4这两点的代码有选择的加入Code Snippets,个人用z作为简写的开头) (1)Code Snippets自带的代码片段,非常实用,需要仔细查阅,新人不容易发现的简写,比如forin ,ifelse等。 (2)https://github.com/lukeredpath/xcodesnippets xcodesnippets gem (3)https://github.com/mattt/Xcode-Snippets Mattt's Snippets (4)https://gist.github.com/4463913 Gist of User's favorites 其他人的一些code snippets2)Dash
介绍:代码片段管理和API文档浏览、搜索功能 使用教程:http://scriptfans.iteye.com/blog/1543219 下载地址:http://kapeli.com二、快捷键 (Google: Xcode + 快捷键,其他参考链接,毕竟大多快捷键很常见)
我将这些快捷键分为:代码层的操作,Xcode本身功能的操作和其他。
主要推荐: 表1 代码层的操作 表2 Xcode本身功能的操作和其他注:Command + , , 打开Behaviors, 将Running 中Starts修改成如图1,这样每次Debug的时候,都可以看到最大化的调试窗口,但必须Command + T,新加一个Tab,并将名称修改为Debug.
图1 Behaviors我的常用Tab分为Edit, Debug, Build, DataModel, 如图2所示:
图2 常用的Tab名另,还有其他快捷键,诸如: Command + `, Command + Shift + `,Command + J,Command + Control + Shift + ?, Command + R, Command + B。
小技巧 主要推荐: 1. TODO: (加个空格) 和 FIXME: (加个空格)在注释中,加入这两个关键字,可以让你查看方法(control + 6)时,看到这段文字(如图3 所示),也可以App build的时候,在该处有Warning。
图3 方法查看 2. Automator介绍:Mac上自带的一款软件,只要通过点击拖拽鼠标等操作就可以将一系列动作组合成一个工作流,从而帮助你自动的(可重复的)完成一些复杂的工作。 eg,我们需要对头文件中的import进来的文件,进行代码风格统一(按Google Style)。如果文件一多,手工地去完成这件事情将浪费大量时间。这时候,通Automator 就能很方便地完成这个任务。
主要步骤如下: