Android官方培训文档
暂停Activity
通常应该在onPause()回调方法里面做以下事情
1、停止动画或者是其他正在运行的操作,那些都会导致CPU的浪费
2、提交在用户离开时期保存的内容(例如保存的内容)
3、释放系统资源,例如broadcast receiver ,sensors 或者是其他任何会影响到电量的资源
通常,不应该使用onPause()方法来保存用户改变的数据(例如填入表格中的个人信息)到永久存储(File或者DB上)。仅仅当确认用户期待那些改变能够被自动保存的时候,
才把那些数据存到永久存储。但是,我们应该避免在onPause()。例如写数据到DB,因为它会导致切换到下一个activity变得缓慢。
恢复Acitivity
请注意,系统每次调用这个方法时,activity都处于前台,包括每一次创建的时候。所以,应该实现onResume()来初始化那些在onPause()方法里面释放掉的组件,并执行那些activity每次进入Resumed state都需要的初始化动作(例如开始动画与初始化那些只有在获取用户焦点时才需要的组件)。
恰当的停止与重启我们的activity是很重要的,在activity生命周期中,他们能确保用户感知到程序的存在并不会丢失他们的进度。在下面一些关键的场景中会涉及到停止与重启。
1、用户打开最近使用app的菜单并从我们的app切换到另外一个app,这个时候我们的app是被停止的。如果用户通过手机主界面的启动程序图标或最近使用程序的窗口回到我们的app,那么我们的activity会重启。
2、用户在我们的app里面执行一个新activity的操作,当前activity会在第二个activity被创建后stop。如果用户点击back按钮,第一个activity会被重启。
3、用户在使用我们的app时接收到一个来电通话。
Activity提供了onstop()与onrestart()方法允许在acitivity停止与重启时进行调用。不同于暂停状态的部分阻塞UI,停止状态是UI不再课件并且用户的焦点转移到另一个activity中。
NOTE:因为系统在activity停止时会在内存中保存activity的实例,所有有时不需要实现onStop(),onRestart()甚至是onStart()方法,因为大多数activity相对比较简单,activity会自己停止与重启,我们只需要使用onPause()来停止正在运行的动作并断开系统资源连接。
无论什么原因导致activity停止,系统总是会在onstop()之前onPause()
停止Activity
当activity调用onstop方法,activity不再可见,并且应该释放那些不再需要的所有资源。一旦activity停止,系统会在需要内存空间时摧毁它的实例。极端情况下,系统会直接杀死我们的app进程,并不执行activity的ondestory方法。因此我们需要使用onstop来释放资源,从而避免内存泄漏。
Note:即使系统会在activity stop时停止这个activity,它仍会保存View对象的状态到一个Bundle中,并且在用户返回这个activity时恢复它们
启动与重启Activity
onstop()方法应该做清除所有activity资源的操作,我们需要在重启activity时,重新实例化那些被清除的资源,同样,我们也需要在activity第一次创建时实例化那些资源。介于上面的原因,应该使用onstart()作为onstop所对应方法。因为系统会在创建activity与从停止状态重启activity时都会调用onstart()。也就是说,我们在onstop里面做了那些清除的操作,就该在Onstart里面重新把那些清除掉的资源重新创建出来。
创建一个Fragment类
创建一个Fragment,首先需要继承Fragment类,然后在关键的生命周期方法中插入APP的逻辑,像Activity一样。
其中一个区别当创建Fragment的时,必须重写onCreateView()回调方法来定义布局,事实上,Fragment运行起来,唯一一个需要我们重写的回调方法。
就像activity一样,当Fragment从activity添加或移除、当activity生命周期发生变化时,frament生命周期回调函数管理其状态。例如当activity的onPause()被调用时,它里面的所有fragment的onPause()方法也会被触发。
如果我们的activity允许fragment移除或者替换,我们应该在activity的onCreate()方法中添加初始化fragment
运用fragment(尤其是那些在运行时添加的)的一个很重要的规则就是在布局中必须有一个容器View,fragment的layout将会放在这个View里面。
记住在执行Fragment事务时,如移除或者替换,我们经常要适当地让用于可以向后导航与撤销这次改变。为了让用于向后导航Fragment事务,我们必须在FragmentTransaction提交前调,用addtoBackstack()方法。
当移除或者体船一个Fragment并把它放入返回栈中时,被移除的Fragment的生命周期是stopped(不是destoryed)。当用户返回重新恢复这个Fragment,它的生命周期是restarts。如果没有把fragment放入返回栈中,俺么当它被移除或者替换时,其生命周期是destoryed。
ArticleFragment newFragment =new ArticleFragment; Bundle args =new Bundle();
args.putInt(ArticleFragment .ARG_POSTION,position);newFragment.setArgument(args);
FragmentTransaction transaction = getSupportFragmentManager.beginTransaction();
transaction.replace(R,id.fragment_container,newFragment );transaction.addtoBackStack(null);transaction.commit()
Fragment之间的交互
通常fragment之间可能会需要交互,比如基于用于事件改变fragment的内容,所有fragment之间的交互需要通过他们关联的activity,两个fragment之间不应该直接交互。
传消息给Fragment
宿主Activity通过findFragmentByid()方法获取Fragment的实例,然后直接调用Fragment的public方法来向Fragment传递消息
例如:假设上面所示的activity可能包含另外一个fragment,这个fragment用来展示从上面的回调方法返回的指定的数据。在这种情况下,activity可以从回调方法中接收到的信息传递给这个展示数据的Fragment。
保存到Preference
当有一个相对较小的key-value集合需要保存时,可以使用SharedPreferences APIS。SharedPreferences对象指向一个保存key-value-pairs的文件,并为读写他们提供了简单的方法。每个SharedPreferences文件均由framework管理,其既可以是私有的,也可以是共享的。
Note:SharedPreferences仅仅提供了读写key-value对的功能,请不要与preference APIS相混淆。后者可以帮助我们建立一个设置用户配置的页面(尽管它实际上是使用sharedPreferences来实现保存用户配置的)。
SharedPreferences是一种轻量级的数据存储方式,学过Web开发的同学,可以想象它是一个小小的Cookie。它可以用键值对的方式把简单数据类型(boolean、int、float、long和String)存储在应用程序的私有目录下(data/data/包名/shared_prefs/)自己定义的xml文件中。
SharedPreferences接口主要负责读取应用程序的Preferences数据
我们可以通过以下两种方法之一创建或者访问shared preference文件:
getsharedPreferences()——如果需要多个通过名称参数来区分的shared preference文件,名称可以通过第一个参数来指定,可在app中通过任何一个context执行该方法。
getprefecrences()——当activity仅需要一个shared preference文件时,因为该方法会检索activity下默认的shared preference文件,并不需要提供文件名称。
Internal storage:
1、总是可用的。2、这里的文件默认只能被我们的app所访问。
3、当用户卸载app的时候,系统就会把internal内该app相关的文件都清除干净
4、Internal是我们在想确保不被用户与其他app所访问的最佳存储区域。
External storage:
1、并不总是可用的,因为用户有时会通过USB存储模式挂在外部存储器,当取下挂载的这部分后,就无法对其进行访问了,
2、是大家都可以访问的,因为保存在这里的文件可能被其他程序访问。
3、当用户卸载我们的app时,系统仅仅会删除exteranle根目录下的相关文件
4、external是在不需要严格的访问权限并且希望这些文件能够被其他app所共享或者是允许用户通过电脑访问时的最佳存储区域。
保存到Internal Storage
当保存文件到internal storage时,可以通过执行下面两个方法之一来获取合适的目录作为FIFE的对象:
getiFilsDir();返回一个File,代表了我们app的internal目录。
getCacheDir():返回一个File,代表我们app的internal缓存目录。请确保这个目录下的文件能够一旦不再需要的时候马上就删除,并对其大小进行合理限制,例如1MB。系统的内部存储控件不够时,会自行选择删除缓存文件。
可以使用File()构造器在那些目录下创建一个新的文件,如下:
File file=new File(context.getFilesDir(),filename);
也可以执行openFileOutput()获取一个FileOutputStream用于写文件到internal目录
FileOutputStream outpurstream=openfileOutput(filaname,Context.MODE_PRIVATE);
如果需要缓存一些文件,可以使用creatTempFile(),例如,下面的方法中从URL抽取了一个文件名,然后再在程序的internal缓存目录下创建了一个以这个文件名命名的文件。
String filname=Uri.parse(url).getLastPathSegment();
file=file.creatTempFile(filename,null,context.getCacheDir());
尽管external storage对于用户与其他app是可修改的,我们可能会保存下面两种类型的文件。
Public files:这些文件对与用于与其他app来说是public的,当用户卸载我们的app时,这些文件应该保留。
Private files:这些文件完全被我们的app所私有,它们应该在app被卸载时删除。
想要文件以public形式保存在external storage中,请使用,getExternalStoragePublicDirectory()方法来获取一个file对象,该对象表示存储在external storage的目录。这个方法需要一个特定的参数来指定这些public的文件类型,以便于与其他public文件进行分类,参数类型包括DIRECTORY_MUSIC或者DIRECTORY_PICTURES。
删除文件
如果文件是保存在internal storage ,我们可以通过context来访问并通过执行deleteFile删除。
Intent
如果触发一个intent,而且没有任何一个app会去接受这个intent,则app会crash。
为了验证是否有合适的activity会响应这个activity,需要执行queryIntentActivities() 来获取到能够接受这个Intent的所有activity的list,若返回的list非空,我们才可以安全的使用这个intent。
PackageManager packageManager = getPackageManager();
List<ResolveInfo> activities = packageManager.queryIntentActivities(intent, 0);
boolean isIntentSafe = activities.size() > 0;
为了显示chooser,需要使用createChooser()来创建Intent
Intent intent =new Intent(Intent.ACTION_SEND):
String title =getResources.getText(R.string.chooser_title);
Intent chooser=Intent.createChooser(intent,title);
startactivity(chooser);
启动另一个activity并不一定是单向的,我们也可以启动另外一个activity然后接受一个返回的result。为接受result,我们需要使用startActivityForResult(Intent intent, int requestcode)。
当然被启动的activity需要指定返回的result。它需要把这个result作为另外一个intent对象返回,我们的activity需要在onactivityresult(Intent intent ,int requestcode ,int resultcode ) switch(relustcode!=result_cancleed) case requestcode break;
当用户完成了启动之后activity操作之后,系统会调用我们activity中的onActivityResult() 回调方法。该方法有三个参数:
- 通过startActivityForResult()传递的request code。
- 第二个activity指定的result code。如果操作成功则是
RESULT_OK
,如果用户没有操作成功,而是直接点击回退或者其他什么原因,那么则是RESULT_CANCELED
- 包含了所返回result数据的intent。
可以在getIntent()来获取启动我们activity的那个Intent。我们可以在activity生命周期的任何时候去执行这个方法,但最好是在oncreate()或者onstart()里面去执行。
返回Result
如果向返回一个result给启动的那个Activity,仅仅需要执行setResult(),通过指定一个resultcode与result intent 。操作完成之后,用户需要返回到原来的activity,通过执行finish()关闭来唤起的activity。
Intent result =new Intent("com",Uri.parse("content://result_uri"));
setresult(activity.result_ok,result);
finish();
如果只是纯粹想要返回一个int来表示某些返回的result数据之一,则可以设置resultcode 为任何大于0的数值,如果我们返回的result只是一个Int,那么连intent都可以不需要返回了。可以调用setresult()然后只传递resultcode 如下。
分享二进制内容
分享二进制的数据需要结合设置特定的MIME类型,需要在EXTRA_STREAM里面放置数据的URI。
注意:我们可以使用*/*这样的方式来指定MIME类型,但是仅仅会match到那些能够处理一般数据类型的Activity(即一般的activity无法详尽所有的MIME类型)
接受的程序需要有访问URI资源的权限,下面有一些方法来处理这个问题:
1、将数据存储在contentprovider中,确保其他程序有访问provider的权限,较好的提供访问权限的方法是使用per-URI permissions ,其对接受程序而言只是暂时拥有该许可权限。类似于这样创建contentprovider的一种简单的方法来使用fileprovider helper类。
2、使用media store系统,mediastor系统主要用于音频视频及图片的MIME类型。在安卓3.0之后,也可用于存储非多媒体类型。
发送多块内容
为了同时分享多种不同类型的内容,需要使用ACTION_SEND_MUTIPLE与制定到那些数据的URIs列表。MIME类型会根据分享的混合内容而不同。例如,如果分享3张JPEG的图片,那么MIME类型仍然是image/jpeg。如果是不同图片格式的话,应该是用image/*来匹配那些可以接受任何图片类型的activity。如果需要分享多种不同类型的数据,可以使用*/*来表示MIME。
2.2.1建立文件分享
为了将文件安全地从我们的应用程序共享给其他应用程序,我们需要对自己的应用进行配置提供安全的
文件句柄(Content URI 的形式)。Android的FileProvider组件会基于XML文件中的具体配置为文件配置Content URI 。
如<provider Android:name=".MyContentProviderDemo" android:authorities="com.content.MyUsers"></provider>
name所对应的项为(contentProvider(数据存储))的具体操作的类;
authorities(授权):即访问这个.MyContentProviderDemo类的权限,说明---com.content.MyUsers是可以访问的,别的类可以通过Uri = Uri.parse("content://" + AUTHORITY);
public static final String AUTHORITY = "com.content.MyUsers";
来对这个数据库进行直接的增删改查的操作,如果这个数据库有多个表,则这个Uri需要加上对应的表名;
如:Uri = Uri.parse("content://" + AUTHORITY+"/User");---User为其中一个表
1、指定FileProvider
为了给应用程序定义一个FileProvider,需要在Mainfest清单文件中定义一个entry,该entry指明了需要使用的创建Content URI的Authority。此外,还需要一个xml文件的文件名,该XML文件指定了我们的应用可以共享的目录路径。
<
provider
android:name
=
"android.support.v4.content.FileProvider"
android:authorities
=
"com.example.myapp.fileprovider"
android:grantUriPermissions
=
"true"
android:exported
=
"false"
>
<
meta-data
android:name
=
"android.support.FILE_PROVIDER_PATHS"
/>
</
provider
>
这里,android:authorities字段指定了希望使用的Authority,该Authority针对于FileProvider所生成的content URI。本例中的Authority是“com.example.myapp.fileprovider”。对于自己的应用,要在我们的应用程序包名(android:package的值)之后继续追加“fileprovider”来指定Authority。《provider》下的《meta-data》指向了一个XML文件,该文件指定了我们希望共享的目录路径。“android:resource”属性字段是这个文件的路径和名字(无“.xml”后缀)。
指定给共享目录路径
一旦在Mainfest清单文件中为自己的应用添加了Fileprovider,就需要指定我们希望共享文件的目录路径。为指定该路径,首先要在“res/xml”下创建文件“filepaths.xml”。在这个文件中,为每个想要共享目录添加一个xml标签。下面的是一个“”res/xml/filepaths.xml的内容样例。这个例子也说明了如何在内部存储区域共享一个“files/”目录的子目录。
<
paths
>
<
files-paths
path
=
"images/"
name
=
"myimages"
/>
</
paths
>
在这个例子中,<files-path>标签共享的是在我们应用的内部存储中”files/“目录下的子目录,”path“属性字段指出该子目录为”files/“目录下的子目录”images/“。”name“属性字段告知FileProvider在”files/images/“子目录中的文件的Content URI添加路径分段标记”myimages“。
<paths>标签可以有多个子标签,每个子标签用来指定不同的共享目录。除了<files-path>标签,还可以使用<external-path>来共享位于外部存储的目录;另外,<cache-path>标签用来共享在内部缓存目录下的子目录。
注:xml文件是我们定义共享目录的唯一方式,不可以用代码的形式添加目录。
现在我们有一个完整的fileprovider生命,它在应用程序的内部存储中”files/“目录或其子目录下创建的文件的Content URI。当我们的应用为一个文件创建了Content URI,该Content URI 将会包含如下信息:
1、<provider>标签中指定的Authority(com.example.myapp.fileprovider);
2、路径”myimages/“;3、文件名字
例如:本例子中,fileprovider 会返回如下URI :content://com.example.myapp.fileprovider/myimages/
2.2.2分享文件
对应用程序进行配置,使得它可以使用content uri来共享文件后,其就可以响应其他应用程序的获取文件的请求了。一种响应这些请求的方法是在服务端应用程序提供一个可以由其他引用激活的文件选择接口。该方法可以允许客户端应用程序让用户从服务端应用程序选择一个文件,然后接受这个文件Content URI 。
接受文件请求
为了从客户端应用程序接受一个文件获取请求并以Content URI的形式进行响应,我们的应用程序应该提供一个选择文件的activity。客户端应用程序通过调用startactivityforresult()方法启动这一activity。该方法包含了 一个具有action_pick action的Intent 参数。当客户端应用程序调用了startactivityforresult(),我们的应用可以向客户端应用程序返回一个结果,该结果即用户所选择的文件对应的Content URI 。
在代码中定义文件
选择activity 下面定义了一个activity子类,用于显示在内部存储的”files/images/”目录下可以获得的文件,然后允许用户选择期望的文件。
File dir=getFilesDir();
//获取内部存储文件
File mImagesDir=
new
File(dir,
"images"
);
//获取内部存储中文件中,image文件下全部文件
File[]mImageFiles=mImagesDir.listFiles();
//展示image目录下的全部文件。
响应一个文件选择
一旦用户选择了一个被共享的文件,我们的应用程序必须明确哪个文件被选择了,并为该文件生成一个对应的Content URI。
在onitemClick()中,根据被选中文件的文件名获取一个file对象,然后将其作为参数传递给geturiforfile(),然后还需要传入的参数是<provider>标签中的fileprovider所指定的authority,函数返回的Content URI包含了相应的authority。
fileuri =Fileprovider.getUriForFile(mainactivity.this,“com.example.myapp.fileprovider”,requestfile)。
为文件授权
现在已经有了想要共享给其他应用程序的文件所对应的Content URI ,我们需要允许客户端应用程序访问这个文件。为了达到这一目的,可以通过将Content URI添加至Intent中,然后为该Intent设置权限标记。所授予的权限是临时的,并且当接受文件的应用程序的人物栈终止后,会自动过期。
注:调用setFlags()来为文件授予临时被访问权限是唯一的安全的方法。尽量避免对文件的contenturi调用context.grantUriPermission(),因为通过该方法授予的权限,只能通过调用context.revokeUriPermission来撤销。
与请求应用共享文件。
// Put the Uri and MIME type in the result Intent
mResultIntent.setDataAndType(
fileUri,
getContentResolver().getType(fileUri));
// Set the result
MainActivity.this.setResult(Activity.RESULT_OK,
mResultIntent);
2.2.3获取文件信息
当一个客户端应用程序拥有了文件的Content URI之后,它就可以获取该文件并进行下一步的工作了,但再次之前,客户端应用程序可以向服务端应用程序获取关于文件的信息,包括文件的数据类型和文件大小等等。数据类型可以帮主客户端应用程序确定自己能否处理该文件,文件大小能帮助客户端应用程序文件设置合理的缓冲区。
获取文件的MIME类型
/*
*get the file's content uri from the incoming intent
*then get the file's MIME type
*/
Uri returnuri =returnIntent.getdata();
String mimetype= getContentResolver().getType(returnUri);
获取文件名及文件大小
FileProvider 类有一个query()方法的默认实现,它返回一个Cursor对象,该Cursor对象包含了Content URI所关联的文件的名称和大小。
Display_NAME
文件名
SIZE
文件大小,以字节为单位,long类型。这个值和File.length()所返回的值一样。
/*
* Get the file's content URI from the incoming Intent,
* then query the server app to get the file's display name
* and size.
*/
Uri returnUri = returnIntent.getData();
Cursor returnCursor =
getContentResolver().query(returnUri, null, null, null, null);
/*
* Get the column indexes of the data in the Cursor,
* move to the first row in the Cursor, get the data,
* and display it.
*/
int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
returnCursor.moveToFirst();
TextView nameView = (TextView) findViewById(R.id.filename_text);
TextView sizeView = (TextView) findViewById(R.id.filesize_text);
nameView.setText(returnCursor.getString(nameIndex));
sizeView.setText(Long.toString(returnCursor.getLong(sizeIndex)));
2.3使用NFC分享文件
安卓允许我们通过安卓Beam文件传输功能在设备之间传送大文件。该功能具有简单的API,它是的用户仅需要通过一些简单的触控操作,就能启动文件传输过程。
2.3.1发送文件给其他设备
使用Android Beam文件传输功能必须满足以下条件:
1、安卓Beam文件传输功能传输大文件必须在安卓4.1及以上的版本的安卓系统中使用
2、希望传送的文件必须放置于外部存储。
3、希望传送的文件必须是全局可读。我们可通过file.setreadable(true,false)来为文件设置相应的权限
4、必须提供传输文件的File URI.安卓beam文件传输无法处理由FileProvider.getUriForFile生成的Content URI
在清单文件中声明
声明权限
NFC <uses-permission android:name="android.permission.NFC"/
>
READ_EXTERNAL_STORAGE 允许应用读取外部存储《uses -permission android:name ="android.permission.READ_EXTERNAL_STORAGE"/>
指定NFC功能
通过添加<uses-feature >标签作为一个<mainfest标签>,设置android:required属性字段为true,使得我们的应用程序在NFC可以使用时才能运行
《use- feature android:name ="android.hardware.nfc" android:requires="true">
注意:如果应用程序将NFC作为一个可选的功能,期望在NFC不可使用时程序还能继续执行,我们就应将android :required属性字段设为false 。然后在代码中测试NFC的可用性
2.3.2接受其他设备的文件
Android Beam文件穿出将文件拷贝至接受设备上的某个特殊目录。同时使用Android Media Scanner扫描拷贝的文件,并在MediaStore provider中为媒体文件添加对应的条目记录。
获取拷贝文件的目录
Android Beam文件传输一次性将所有文件拷贝到目标设备的一个目录中,Android Beam 文件传输通知所发出的Intent中含有的Intent指向了第一个被传输的文件的URI。
为了明确应该如何处理接受的Intent,我们要检查它的Scheme和Authority。
可以调用Uri.getScheme()来获得URI的Scheme。
从File URI中获取目录
如果接受的Intent包含一个File URI,则该URI包含了一个文件的绝对文件名,它包括了完整的路径和文件名。对安卓Beam文件传输来说,目录路径指向了其他被传输文件的位置,要获得该目录路径,需要取得URI的路径部分(URI中除去“file:”前缀的部分),根据路径创建一个File对象,然后获取这个file的父目录。
String filename=beamUri.getPath();File copiedFile =new File(fileName) return copied.getParent();
从Content URI 获取目录
如果接受的Intent 包含一个Content URI ,这个URI 可能指向的是存储于MediaStore Content Provider的目录和文件名。我们可以通过检测URI的Authority值判断它是否来自于MediaStore的Content URI 。一个MediaStore 的Content URI可能来自于安卓Beam文件穿出也可能来自于其他应用程序,但不管怎么样,
我们都能根据该Content URI获得一个目录路径和文件名。
我们也可以接收一个含有ACTION_VIEW这一Action的Intent,它包含的Content URI针对于Content Provider,而不是MediaStore,这种情况下,该Content URI不包含MediaStore的Authority,且这个URI一般不指向一个目录。
Note:对于Android Beam文件传输,接收在含有
ACTION_VIEW的Intent中的Content URI时,若第一个接收的文件MIME类型为“audio/
”,“image/”或者“video/*”,Android Beam文件传输会在它存储传输文件的目录内运行Media Scanner,以此为媒体文件添加索引。同时Media Scanner将结果写入
MediaStore的Content Provider,之后它将第一个文件的Content URI回递给Android Beam文件传输。这个Content URI就是我们在通知
Intent中所接收到的。要获得第一个文件的目录,需要使用该Content URI从
MediaStore中获取它。
确定 Content Provider
Uri.getAuthority()获取URI的Authority,以此确定与该URI相关联的Content Provider。其结果有两个可能的值:
MediaStore.AUTHORITY
表明该URI关联了被MediaStore记录的一个文件或者多个文件。可以从MediaStore中获取文件的全名,目录名就自然可以从文件全名中获取。
其他值
来自其他Content Provider的Content URI。可以显示与该Content URI相关联的数据,但是不要尝试去获取文件目录。
要从
MediaStore
的Content URI中获取目录,我们需要执行一个查询操作,它将
Uri
参数指定为收到的ContentURI,将
MediaColumns.DATA
列作为投影(Projection)。返回的
Cursor
对象包含了URI所代表的文件的完整路径和文件名。该目录路径下还包含了由Android Beam文件传输传送到该设备上的其它文件。
// Get the column that contains the file name
String[] projection = { MediaStore.MediaColumns.DATA };
Cursor pathCursor =
getContentResolver().query(beamUri, projection,
null, null, null);
// Check for a valid cursor
if (pathCursor != null &&
pathCursor.moveToFirst()) {
// Get the column index in the Cursor
filenameIndex = pathCursor.getColumnIndex(
MediaStore.MediaColumns.DATA);
// Get the full file name including path
fileName = pathCursor.getString(filenameIndex);
// Create a File object for the filename
copiedFile = new File(fileName);
// Return the parent directory of the file
return new File(copiedFile.getParent())
;