FireMonkey在Android下通过Intent接收图片:如何访问图片URI?
Android下通过Content URI访问Intent传递的图片
你遇到的问题核心是:content://开头的URI是Content Provider访问标识,不是本地文件系统的物理路径,所以fileexists函数无法识别它。不能直接把URI当作文件路径使用,得通过Android的ContentResolver来访问对应的图片内容。
下面给两种可行的处理方案:
方案一:直接通过输入流加载图片(推荐,无需转路径)
直接利用Android的ContentResolver获取图片的输入流,再加载到Delphi的Bitmap中,无需转换物理路径,步骤如下:
修改你的HandleIntentAction函数:
function TForm1.HandleIntentAction(const Data: JIntent): Boolean; var mytype : STRING; imageUri: Jnet_Uri; ContentResolver: JContentResolver; InputStream: JInputStream; DelphiStream: TStream; begin Result := False; if Data <> nil then begin Memo1.ClearContent; mytype := JStringToString(Data.getType); memo1.Lines.Add('Intenttype: '+mytype); if mytype.StartsWith('image/') then begin Memo1.Lines.Append('is image'); imageUri := Data.getData; Memo1.Lines.Append('URI: '+JStringToString(imageUri.toString)); // 获取ContentResolver实例 ContentResolver := SharedActivity.getContentResolver; try // 打开URI对应的输入流 InputStream := ContentResolver.openInputStream(imageUri); if Assigned(InputStream) then begin try // 将Java输入流转为Delphi流 DelphiStream := TJavaInputStreamAdapter.Create(InputStream); try // 加载图片到Bitmap Image1.Bitmap.LoadFromStream(DelphiStream); Memo1.Lines.Append('图片加载成功'); Result := True; finally DelphiStream.Free; end; finally InputStream.close; end; end else Memo1.Lines.Append('无法打开图片输入流'); except on E: Exception do Memo1.Lines.Append('加载失败:' + E.Message); end; end; Invalidate; end; end;
关键说明:
SharedActivity.getContentResolver:获取当前应用的ContentResolver,用于访问Content Provider提供的内容openInputStream(imageUri):通过URI打开对应的输入流,这是访问Content URI内容的标准方式TJavaInputStreamAdapter:把Java的InputStream转换成Delphi能识别的TStream,方便Bitmap加载
方案二:将图片复制到应用私有目录后访问(需保存文件时用)
如果需要把图片保存到本地再使用,可以将URI对应的内容复制到应用的私有目录(比如getFilesDir或getExternalFilesDir),之后就能用文件路径访问了:
function TForm1.CopyUriToPrivateFile(const Uri: Jnet_Uri): string; var ContentResolver: JContentResolver; InputStream: JInputStream; OutputStream: JOutputStream; FilePath: string; JavaFile: JFile; Buffer: TBytes; ReadCount: Integer; begin Result := ''; ContentResolver := SharedActivity.getContentResolver; try InputStream := ContentResolver.openInputStream(Uri); if not Assigned(InputStream) then Exit; // 创建应用私有目录下的目标文件 JavaFile := TJFile.JavaClass.init(SharedActivity.getFilesDir, 'received_image.jpg'); FilePath := JStringToString(JavaFile.getAbsolutePath); OutputStream := TJFileOutputStream.JavaClass.init(JavaFile); try SetLength(Buffer, 8192); repeat ReadCount := InputStream.read(TJavaArray<Byte>.Create(Buffer), 0, Length(Buffer)); if ReadCount <= 0 then Break; OutputStream.write(TJavaArray<Byte>.Create(Buffer), 0, ReadCount); until False; Result := FilePath; finally OutputStream.close; InputStream.close; end; except on E: Exception do Memo1.Lines.Append('复制文件失败:' + E.Message); end; end; // 在HandleIntentAction中调用该函数 function TForm1.HandleIntentAction(const Data: JIntent): Boolean; var mytype : STRING; imageUri: Jnet_Uri; LocalFilePath: string; begin Result := False; if Data <> nil then begin Memo1.ClearContent; mytype := JStringToString(Data.getType); memo1.Lines.Add('Intenttype: '+mytype); if mytype.StartsWith('image/') then begin Memo1.Lines.Append('is image'); imageUri := Data.getData; Memo1.Lines.Append('URI: '+JStringToString(imageUri.toString)); LocalFilePath := CopyUriToPrivateFile(imageUri); if LocalFilePath <> '' then begin Memo1.Lines.Append('本地文件路径:' + LocalFilePath); if FileExists(LocalFilePath) then begin Image1.Bitmap.LoadFromFile(LocalFilePath); Memo1.Lines.Append('图片加载成功'); Result := True; end else Memo1.Lines.Append('本地文件不存在'); end; end; Invalidate; end; end;
关键说明:
SharedActivity.getFilesDir:获取应用的私有内部存储目录,只有当前应用能访问,无需额外权限- 复制流的过程是标准的文件读写操作,完成后就能用普通的文件路径访问了
注意事项
- Android 10及以上采用Scoped Storage机制,禁止直接访问其他应用的私有文件,必须通过Content Provider的URI+ContentResolver来访问,这也是为什么你直接用URI当路径不行的核心原因
- 确保你的应用声明了必要的权限:如果是访问外部存储的图片,需要在
AndroidManifest.xml中添加<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />(Android 13及以上可以用READ_MEDIA_IMAGES)
内容的提问来源于stack exchange,提问作者Holger Hanschmann
相关产品推荐
相关产品推荐

