Android是如何实现应用程序之间数据共享的?一个应用程序可以将自己的数据完全暴露出去,外界更本看不到,也不用看到这个应用程序暴露的数据是如何存储的,或者是使用数据库还是使用文件,还是通过网上获得,这些一切都不重要,重要的是外界可以通过这一套标准及统一的接口和这个程序里的数据打交 道,例如:添加(insert)、删除(delete)、查询(query)、修改(update),当然需要一定的权限才可以。
如何将应用程序的数据暴露出去? Android提供了ContentProvider,一个程序可以通过实现一个Content provider的抽象接口将自己的数据完全暴露出去,而且Contentproviders是以类似数据库中表的方式将数据暴露。Content providers存储和检索数据,通过它可以让所有的应用程序访问到,这也是应用程序之间唯一共享数据的方法。要想使应用程序的数据公开化,可通过2种 方法:创建一个属于你自己的Content provider或者将你的数据添加到一个已经存在的Content provider中,前提是有相同数据类型并且有写入Contentprovider的权限。
如何通过一套标准及统一的接口获取其他应用程序暴露的数据?Android提供了ContentResolver,外界的程序可以通过ContentResolver接口访问ContentProvider提供的数据。
当前篇主要说明,如何获取其它应用程序共享的数据,比如获取Android 手机电话薄中的信息。
什么是URI?
在学习如何获取ContentResolver前,有个名词是必须了解的:URI。URI是网络资源的定义,在Android中赋予其更广阔的含义,先看个例子,如下:
将其分为A,B,C,D 4个部分:
A:标准前缀,用来说明一个Content Provider控制这些数据,无法改变的;
B:URI的标识,它定义了是哪个Content Provider提供这些数据。对于第三方应用程序,为了保证URI标识的唯一性,它必须是一个完整的、小写的 类名。这个标识在<provider> 元素的 authorities属性中说明:
<provider name=”TransportationProvider” authorities=”comexampletransportationprovider” >
C:路径,Content Provider使用这些路径来确定当前需要生什么类型的数据,URI中可能不包括路径,也可能包括多个;
D:如果URI中包含,表示需要获取的记录的ID;如果没有ID,就表示返回全部;
由于URI通常比较长,而且有时候容易出错,切难以理解。所以,在Android当中定义了一些辅助类,并且定义了一些常量来代替这些长字符串,例如:PeopleCONTENT_URI
我这里有一个读通信录中邮箱的代码,至于读电话吧类似了:
private ArrayList<String> getEmailAddress() {
emailAddress = new ArrayList<String>();
Cursor c = getContentResolver()
query(
ContactsContractDataCONTENT_URI,null,DataMIMETYPE
+ "='"
+ ContactsContractCommonDataKindsEmailCONTENT_ITEM_TYPE
+ "'", null, null);
if (cgetCount() > 0) {
while (cmoveToNext()) {
int mailindex = cgetColumnIndex(DataDATA1);
String mail = cgetString(mailindex);
Logv("minetype", mail);
emailAddressadd(mail);
}
}
cclose();
return emailAddress;
}
另外 在AndroidManifestxml中加入:
<uses-permission android:name="androidpermissionREAD_CONTACTS" />,这样才能读通讯录,当然要读电话本的话不是这个了,你自己查查api吧!
手机和 wifi 已经改变了人们的生活方式,成为生活的必需品。手机号码和宽带账号成为运营商相互竞争的重要一环,双卡双待的手机需求也逐渐增大,大多数手机厂商将主打手机改为双卡双待全网通,而运营商在占领主SIM卡后,对SIM卡2的欲望越来越大,获取SIM卡2的信息的需求也变大,只有知己知彼,才能占得先机。
这里简单介绍一下 Android 手机如何读取 Sim 卡信息
可以通过 ContentProvider 进行查询
使用 SubscriptionManager 类进行读取信息
通过 SubscriptionInfo 的实例进行读取信息,对应的是 Siminfo 的表字段,下面为该类源码:
该类没有常用的手机IMEI值和IMSI值,这个值可以通过 TelephonyManager 进行读取,不过需要通过反射,具体可见下方关于 TelephonyManager 的介绍
使用 TelephonyManager 读取SIM卡信息:
读取副卡信息大多只需要1个参数,slotId 或者 subId,源码方法如下(我们主要关心的是IMEI和IMSI,主要看getDeviceId和getSubscriberId方法):
可以看到源码中的这些方法均加了 @hide 的参数,无法直接调用,这里就需要用到反射:
现在就可以通过反射进行调用方法读取数据了
特别注意:
Context可能是Android应用中最常用的元素,而它也可能是最容易误用的。Context对象是如此常见和传递使用,它可能会很容易产生并不是你预期的情形。加载资源、启动一个新的Activity、获取系统服务、获取内部文件路径以及创建view(其实还远不止这些)统统都需要Context对象来完成。我(原文作者)想做的只是给大家提供一些Context是如何工作的见解,以及让大家在应用中更有效的使用Context的技巧。Context的类型并不是所有的context实例都是等价的。根据Android应用的组件不同,你访问的context推向有些细微的差别。Application - 是一个运行在你的应用进程中的单例。在Activity或者Service中,它可以通过getApplication()函数获得,或者人和继承于context的对象中,通过getApplicationContext()方法获得。不管你是通过何种方法在哪里获得的,在一个进程内,你总是获得到同一个实例。Activity/Service - 继承于ContextWrapper,它实现了与context同样API,但是代理这些方法调用到内部隐藏的Context实例,即我们所知道的基础context。任何时候当系统创建一个新的Activity或者Service实例的时候,它也创建一个新的ContextImpl实例来做所有的繁重的工作。每一个Activity和Service以及其对应的基础context,对每个实例来说都是唯一的。BroadcastReciver - 它本身不是context,也没有context在它里面,但是每当一个新的广播到达的时候,框架都传递一个context对象到onReceive()。这个context是一个ReceiverRestrictedContext实例,它有两个主要函数被禁掉:registerReceiver()和bindService()。这两个函数在BroadcastReceiveronReceive()不允许调用。每次Receiver处理一个广播,传递进来的context都是一个新的实例。ContentProvider - 它本身也不是一个Context,但是它可以通过getContext()函数给你一个Context对象。如果ContentProvider是在调用者的的本地(例如,在同一个应用进程),getContext()将返回的是Application单例。然而,如果调用这和ContentProvider在不同的进程的时候,它将返回一个新创建的实例代表这个Provider所运行的包。保存引用第一个我们需要解决问题是,在一个对象或者类内部保存一个context引用,而它生命周期却超过其保存引用的对象的生命周期。例如,创建一个自定义的单例,它需要一个context来加载资源或者获取ContentProvider,从而保存一个指向当前Activiy或者Service的引用在单例中。
在制作eclipse插件的时候,时常需要对已经存在的视图做一些扩展,例如在project explorer中增加一个右键菜单,或者需要获取outline中当前选中项,等等。而这些 *** 作的前提,是获取这些视图的id,然后通过获取视图的语句获取到视图,并进行下一步 *** 作。
例如:如果是在view中:
IViewPartpart=getViewSite()getPage()findView("orgeclipseuiviewsContentOutline");
如果是在action中:
IViewPartpart=PlugingetDefault()getWorkbench()getActiveWorkbenchWindow()getActivePage()findView("orgeclipseuiviewsContentOutline");
可见获取到视图的id是很重要的。如何获取id呢,有很多方法,我觉得比较常用的是以下两种:
1通过手动查找目标视图所在的插件的pluginxml中对改视图的定义,获得视图id。
描述:我觉得这是最保险的办法,因为所有的视图都必定有一个pluginxml定义,但是找到这个pluginxml还是需要一些 *** 作,可能会耗费一些时间。
步骤:
a点击“工具栏”->“Search”->“Search”,或者热键“ctrl+h”。选“ Plugin Search”。
bSearch for 选"Extention Point",Limit to 选“references”,External Scope 选“Enabled Plug-ins only”。
c下面的scope选“Worksapaces”。
d上面的Search String框填入我们要搜索的插件的扩展点的名字,这里我们要找视图插件,所以填入:orgeclipseuiviews
e点击search以后,在底部Search视图内列出很多搜索结果,任意选中一个,双击,可以看到editor内打开了该pluginxml,选中编辑器底部的Extentions,用图形化的方式来查看会更快捷。
f可以看到该插件使用的扩展点已经以列表的形式列出,我们查找的orgeclipseuiviews扩展点也已经选中,展开选中的扩展点,可以看到它实现了哪些view,点击某一个,可以在页面右边看到该视图的详细信息,第一项即是视图的id。
我们无法知道目标视图在搜索结果中的哪个plugin中,所以可能会耗费一些时间,建议在查看搜索结果时,通过对视图的分类分析,确定一个大概范围再进行查看。
同时,用这种方法也可以查找其他扩展点的实现插件。
2通过代码直接读出该视图的id。
描述:通过这种方法,可以直接用鼠标点击某个你想知道的视图,控制台会打印出该视图的id和所属插件的id。
步骤:
a通过插件向导新建一个插件,并使用Available Templates中的Plugin with a view模板,点finish。
b对自动创建的SampleView代码进行修改,修改结果如下。其中主要步骤有三个:实现IPartListener2接口,编写isActivePart()方法,调用isActivePart()方法。
packagecomraullearnsampleviewviews;
importorgeclipseswtwidgetsComposite;
importorgeclipseuipart;
importorgeclipsejfaceviewers;
importorgeclipseswtgraphicsImage;
importorgeclipsejfaceaction;
importorgeclipsejfacedialogsMessageDialog;
importorgeclipseui;
importorgeclipseswtwidgetsMenu;
importorgeclipseswtSWT;
importcomraullearnsampleviewActivator;
/
Thissampleclassdemonstrateshowtoplug-inanew
workbenchviewTheviewshowsdataobtainedfromthe
modelThesamplecreatesadummymodelonthefly,
butarealimplementationwouldconnecttothemodel
availableeitherinthisoranotherplug-in(egtheworkspace)
Theviewisconnectedtothemodelusingacontentprovider
<p>
Theviewusesalabelprovidertodefinehowmodel
objectsshouldbepresentedintheviewEach
viewcanpresentthesamemodelobjectsusing
differentlabelsandicons,ifneededAlternatively,
asinglelabelprovidercanbesharedbetweenviews
inordertoensurethatobjectsofthesametypeare
presentedinthesamewayeverywhere
<p>
/
publicclassSampleViewextendsViewPartimplementsIPartListener2{
privateTableViewerviewer;
privateActionaction1;
privateActionaction2;
privateActiondoubleClickAction;
/
Thecontentproviderclassisresponsiblefor
providingobjectstotheviewItcanwrap
existingobjectsinadaptersorsimplyreturn
objectsas-isTheseobjectsmaybesensitive
tothecurrentinputoftheview,orignore
itandalwaysshowthesamecontent
(likeTaskList,forexample)
/
classViewContentProviderimplementsIStructuredContentProvider{
publicvoidinputChanged(Viewerv,ObjectoldInput,ObjectnewInput){
}
publicvoiddispose(){
}
publicObject[]getElements(Objectparent){
returnnewString[]{"One","Two","Three"};
}
}
classViewLabelProviderextendsLabelProviderimplementsITableLabelProvider{
publicStringgetColumnText(Objectobj,intindex){
returngetText(obj);
}
publicImagegetColumnImage(Objectobj,intindex){
returngetImage(obj);
}
publicImagegetImage(Objectobj){
returnPlatformUIgetWorkbench()
getSharedImages()getImage(ISharedImagesIMG_OBJ_ELEMENT);
}
}
classNameSorterextendsViewerSorter{
}
/
Theconstructor
/
publicSampleView(){
ActivatorgetDefault()getWorkbench()getActiveWorkbenchWindow()
getActivePage()addPartListener(this);
}
@Override
publicvoiddispose(){
//TODOAuto-generatedmethodstub
ActivatorgetDefault()getWorkbench()getActiveWorkbenchWindow()
getActivePage()removePartListener(this);
superdispose();
}
/
Thisisacallbackthatwillallowus
tocreatetheviewerandinitializeit
/
publicvoidcreatePartControl(Compositeparent){
viewer=newTableViewer(parent,SWTMULTI|SWTH_SCROLL|SWTV_SCROLL);
viewersetContentProvider(newViewContentProvider());
viewersetLabelProvider(newViewLabelProvider());
viewersetSorter(newNameSorter());
viewersetInput(getViewSite());
makeActions();
hookContextMenu();
hookDoubleClickAction();
contributeToActionBars();
}
privatevoidhookContextMenu(){
MenuManagermenuMgr=newMenuManager("#PopupMenu");
menuMgrsetRemoveAllWhenShown(true);
menuMgraddMenuListener(newIMenuListener(){
publicvoidmenuAboutToShow(IMenuManagermanager){
SampleViewthisfillContextMenu(manager);
}
});
Menumenu=menuMgrcreateContextMenu(viewergetControl());
viewergetControl()setMenu(menu);
getSite()registerContextMenu(menuMgr,viewer);
}
privatevoidcontributeToActionBars(){
IActionBarsbars=getViewSite()getActionBars();
fillLocalPullDown(barsgetMenuManager());
fillLocalToolBar(barsgetToolBarManager());
}
privatevoidfillLocalPullDown(IMenuManagermanager){
manageradd(action1);
manageradd(newSeparator());
manageradd(action2);
}
privatevoidfillContextMenu(IMenuManagermanager){
manageradd(action1);
manageradd(action2);
//Otherplug-inscancontributethereactionshere
manageradd(newSeparator(IWorkbenchActionConstantsMB_ADDITIONS));
}
privatevoidfillLocalToolBar(IToolBarManagermanager){
manageradd(action1);
manageradd(action2);
}
@Override
publicvoidpartBroughtToTop(IWorkbenchPartReferencepartRef){
//TODOAuto-generatedmethodstub
}
@Override
publicvoidpartClosed(IWorkbenchPartReferencepartRef){
//TODOAuto-generatedmethodstub
}
@Override
publicvoidpartDeactivated(IWorkbenchPartReferencepartRef){
//TODOAuto-generatedmethodstub
}
@Override
publicvoidpartHidden(IWorkbenchPartReferencepartRef){
//TODOAuto-generatedmethodstub
}
@Override
publicvoidpartInputChanged(IWorkbenchPartReferencepartRef){
//TODOAuto-generatedmethodstub
}
@Override
publicvoidpartOpened(IWorkbenchPartReferencepartRef){
//TODOAuto-generatedmethodstub
}
privatevoidisActivePart(){
IWorkbenchPartpart=getViewSite()getPage()getActivePart();
//returnpart!=null&&partequals(this);
Systemoutprintln(partgetSite()getId());
partgetSite()getPluginId();
}
}
然后调插件,在运行环境中调出该视图,接着当你用鼠标点击你想知道的视图时,在开发环境中的控制台,就会打印出该视图的id以及所属插件的id。
查看android 60 源码,发现无法再通过contentprovider获取到上网记录,请问哪位大神实现了在60 以后获取上网记录的功能吗?
(就连权限申请中都没有READ_HISTORY_BOOKMARKS这项了)。
查看源码发现:
public class Browser {
37 private static final String LOGTAG = "browser";
38
39 /
40 A table containing both bookmarks and history items The columns of the table are defined in
41 {@link BookmarkColumns}
42 @removed
43 /
44 public static final Uri BOOKMARKS_URI = Uriparse("content://browser/bookmarks");
以上就是关于怎样获取其他APP分享的数据全部的内容,包括:怎样获取其他APP分享的数据、Android中如何用ContentProvider来读取系统文件、Android 手机读取SIM卡信息等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)