Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby-on-rails-4/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android共享位图的意图-在共享之前是否可以不保存?_Android_Android Intent - Fatal编程技术网

Android共享位图的意图-在共享之前是否可以不保存?

Android共享位图的意图-在共享之前是否可以不保存?,android,android-intent,Android,Android Intent,我尝试使用共享意图从我的应用程序中导出位图,而不保存临时位置的文件。我找到的所有例子都是两步走的 1) 保存到SD卡并为该文件创建Uri 2) 用这个Uri启动intent 是否可以在不需要写_外部_存储权限、保存文件[并随后删除]的情况下进行此操作?如何在没有外部存储的情况下寻址设备 我尝试使用共享意图从我的应用程序中导出位图,而不保存临时位置的文件 理论上,这是可能的。实际上,这可能是不可能的 理论上,您只需要共享一个将解析为位图的Uri。最简单的方法是,如果该文件是可由其他应用程序直接访问

我尝试使用共享意图从我的应用程序中导出位图,而不保存临时位置的文件。我找到的所有例子都是两步走的 1) 保存到SD卡并为该文件创建Uri 2) 用这个Uri启动intent

是否可以在不需要写_外部_存储权限、保存文件[并随后删除]的情况下进行此操作?如何在没有外部存储的情况下寻址设备

我尝试使用共享意图从我的应用程序中导出位图,而不保存临时位置的文件

理论上,这是可能的。实际上,这可能是不可能的

理论上,您只需要共享一个将解析为位图的
Uri
。最简单的方法是,如果该文件是可由其他应用程序直接访问的文件,例如在外部存储上

要完全不将其写入闪存,您需要实现自己的
ContentProvider
,了解如何实现
openFile()
以返回内存中的位图,然后在
操作中传递表示位图的
Uri
。由于
openFile()
需要返回一个
ParcelFileDescriptor
,我不知道如果没有磁盘上的表示,您将如何执行该操作,但我没有花太多时间搜索

是否可以在不需要写_外部_存储权限、保存文件[并随后删除]的情况下进行此操作


如果您只是不想将其放在外部存储上,您可以使用内部存储上的文件执行
ContentProvider
路径。演示一个
ContentProvider
,它通过
ACTION\u VIEW
向设备上的PDF查看器提供PDF文件;同样的方法也可以用于
操作\u SEND

我也有同样的问题。我不想要求获得读写外部存储权限。此外,有时手机没有SD卡或卡被卸下时会出现问题

下面的方法使用一个调用的。从技术上讲,在共享之前,您仍然保存位图(在内部存储器中),但不需要请求任何权限。此外,每次共享位图时,图像文件都会被覆盖。由于它位于内部缓存中,因此在用户卸载应用程序时将被删除。所以在我看来,这和不保存图像一样好。此方法也比将其保存到外部存储器更安全

文档非常好(请参阅下面的进一步阅读),但有些部分有点棘手。这是一个对我有用的总结

在清单中设置文件提供程序 这将告诉文件提供程序从何处获取要共享的文件(在本例中使用缓存目录)

将映像保存到内部存储器 分享图像 进一步阅读

此选项用于将CardView作为图像共享,然后将其保存在应用程序内部存储区域的缓存子目录中。 希望这会有帮助

        @Override
        public void onClick(View view) {

            CardView.setDrawingCacheEnabled(true);
            CardView.buildDrawingCache();
            Bitmap bitmap = CardView.getDrawingCache();

            try{
                File file = new File(getContext().getCacheDir()+"/Image.png");
                bitmap.compress(Bitmap.CompressFormat.PNG,100,new FileOutputStream(file));
                Uri uri = FileProvider.getUriForFile(getContext(),"com.mydomain.app", file);

                Intent shareIntent = new Intent();
                shareIntent.setAction(Intent.ACTION_SEND);
                shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
                shareIntent.setType("image/jpeg");
                getContext().startActivity(Intent.createChooser(shareIntent, "Share"));

            }catch (FileNotFoundException e) {e.printStackTrace();}

        }
    });
这里有一种工作方法,可以为自己的应用程序制作一个屏幕截图,并通过任何messanger或电子邮件客户端将其作为图像共享。 为了解决位图不更新的问题,我改进了Suragch的答案,使用了Gurupad Mamadapur的注释并添加了自己的修改


以下是Kotlin
语言的代码:

private lateinit var myRootView:View // root view of activity
@SuppressLint("SimpleDateFormat")
private fun shareScreenshot() {
    // We need date and time to be added to image name to make it unique every time, otherwise bitmap will not update
    val sdf = SimpleDateFormat("yyyyMMdd_HHmmss")
    val currentDateandTime = sdf.format(Date())
    val imageName = "/image_$currentDateandTime.jpg"       

    // CREATE
    myRootView = window.decorView.rootView
    myRootView.isDrawingCacheEnabled = true
    myRootView.buildDrawingCache(true) // maybe You dont need this
    val bitmap = Bitmap.createBitmap(myRootView.drawingCache)
    myRootView.isDrawingCacheEnabled = false

    // SAVE
    try {
        File(this.cacheDir, "images").deleteRecursively() // delete old images
        val cachePath = File(this.cacheDir, "images")
        cachePath.mkdirs() // don't forget to make the directory
        val stream = FileOutputStream("$cachePath$imageName")
        bitmap.compress(Bitmap.CompressFormat.JPEG, 90, stream) // can be png and any quality level
        stream.close()
    } catch (ex: Exception) {
        Toast.makeText(this, ex.javaClass.canonicalName, Toast.LENGTH_LONG).show() // You can replace this with Log.e(...)
    }

    // SHARE
    val imagePath = File(this.cacheDir, "images")
    val newFile = File(imagePath, imageName)
    val contentUri = FileProvider.getUriForFile(this, "com.example.myapp.fileprovider", newFile)
    if (contentUri != null) {
        val shareIntent = Intent()
        shareIntent.action = Intent.ACTION_SEND
        shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) // temp permission for receiving app to read this file
        shareIntent.type = "image/jpeg" // just assign type. we don't need to set data, otherwise intent will not work properly
        shareIntent.putExtra(Intent.EXTRA_STREAM, contentUri)
        startActivity(Intent.createChooser(shareIntent, "Choose app"))
    } 
}

如果任何人仍在寻找简便快捷的解决方案,而没有任何存储许可
(也支持牛轧糖7.0)。给你

将此添加到清单中

<provider
     android:name="android.support.v4.content.FileProvider"
     android:authorities="${applicationId}.provider"
     android:exported="false"
     android:grantUriPermissions="true">
     <meta-data
          android:name="android.support.FILE_PROVIDER_PATHS"
          android:resource="@xml/provider_paths" />
 </provider>
更新:

正如@Kathir在评论中提到的


DrawingCache
已从API 28+中弃用。使用下面的代码来使用
画布

 Bitmap bitmap = Bitmap.createBitmap(rootView.getWidth(), rootView.getHeight(), quality);
    Canvas canvas = new Canvas(bitmap);

    Drawable backgroundDrawable = view.getBackground();
    if (backgroundDrawable != null) {
        backgroundDrawable.draw(canvas);
    } else {
        canvas.drawColor(Color.WHITE);
    }
    view.draw(canvas);

    return bitmap;

不能像中建议的那样使用
getCacheDir()
?@Suragch:在应用程序的内部存储上创建世界可读文件不是一个好主意。这是有道理的。在发表评论后,我阅读了您建议使用的内容,这就是我现在正在努力的方向。每次我共享屏幕快照时,缓存内存大小都会增加,但从另一个答案来看,它将替换以前的图像,因此不应增加缓存内存大小。请解释一下,很好的解决方案!为什么要使用getCacheDir()而不是GetFileDir(),或者甚至使用getExternalCacheDir()?另外,这需要异步任务或IntentService?你认为什么最适合这种情况?您是否有(或知道)任何将您的解决方案打包到AsyncTask或IntentService中的完整代码?@Jamrelian,因为其目的只是共享映像,而不是保存映像,所以我选择了缓存目录。缓存目录中的内容不会持久。不过,我想使用另一个目录会很好。答案很好!对于未来的读者-大多数应用程序都会保存一个相对于图像文件名的缩略图缓存。如果文件名保持不变,则不会更新缓存。我通过删除目录的内容并以毫秒为单位将文件名设置为当前日期来解决这个问题。@GurupadMamadapur您是对的。您需要删除缓存并使用其他文件名保存…
DrawingCache
已从API 28+中弃用。使用或完成此任务。另外,不要忘记设置背景颜色(无论是您的
视图
还是
位图
),否则您将获得黑色背景。请解释您的代码以帮助其他人使用它。顺便说一句,可以说Kotlin和Java代码可以在同一个Android Studio项目中使用。有些人可能不考虑你的解决方案,因为他们不知道。谢谢嗨,zakir,你能提供java代码吗。我需要捕获scrollview数据。成功捕获图像并能够存储在/存储器中,但共享时无法获取文件路径。你能帮帮我吗
        @Override
        public void onClick(View view) {

            CardView.setDrawingCacheEnabled(true);
            CardView.buildDrawingCache();
            Bitmap bitmap = CardView.getDrawingCache();

            try{
                File file = new File(getContext().getCacheDir()+"/Image.png");
                bitmap.compress(Bitmap.CompressFormat.PNG,100,new FileOutputStream(file));
                Uri uri = FileProvider.getUriForFile(getContext(),"com.mydomain.app", file);

                Intent shareIntent = new Intent();
                shareIntent.setAction(Intent.ACTION_SEND);
                shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
                shareIntent.setType("image/jpeg");
                getContext().startActivity(Intent.createChooser(shareIntent, "Share"));

            }catch (FileNotFoundException e) {e.printStackTrace();}

        }
    });
private lateinit var myRootView:View // root view of activity
@SuppressLint("SimpleDateFormat")
private fun shareScreenshot() {
    // We need date and time to be added to image name to make it unique every time, otherwise bitmap will not update
    val sdf = SimpleDateFormat("yyyyMMdd_HHmmss")
    val currentDateandTime = sdf.format(Date())
    val imageName = "/image_$currentDateandTime.jpg"       

    // CREATE
    myRootView = window.decorView.rootView
    myRootView.isDrawingCacheEnabled = true
    myRootView.buildDrawingCache(true) // maybe You dont need this
    val bitmap = Bitmap.createBitmap(myRootView.drawingCache)
    myRootView.isDrawingCacheEnabled = false

    // SAVE
    try {
        File(this.cacheDir, "images").deleteRecursively() // delete old images
        val cachePath = File(this.cacheDir, "images")
        cachePath.mkdirs() // don't forget to make the directory
        val stream = FileOutputStream("$cachePath$imageName")
        bitmap.compress(Bitmap.CompressFormat.JPEG, 90, stream) // can be png and any quality level
        stream.close()
    } catch (ex: Exception) {
        Toast.makeText(this, ex.javaClass.canonicalName, Toast.LENGTH_LONG).show() // You can replace this with Log.e(...)
    }

    // SHARE
    val imagePath = File(this.cacheDir, "images")
    val newFile = File(imagePath, imageName)
    val contentUri = FileProvider.getUriForFile(this, "com.example.myapp.fileprovider", newFile)
    if (contentUri != null) {
        val shareIntent = Intent()
        shareIntent.action = Intent.ACTION_SEND
        shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION) // temp permission for receiving app to read this file
        shareIntent.type = "image/jpeg" // just assign type. we don't need to set data, otherwise intent will not work properly
        shareIntent.putExtra(Intent.EXTRA_STREAM, contentUri)
        startActivity(Intent.createChooser(shareIntent, "Choose app"))
    } 
}
<provider
     android:name="android.support.v4.content.FileProvider"
     android:authorities="${applicationId}.provider"
     android:exported="false"
     android:grantUriPermissions="true">
     <meta-data
          android:name="android.support.FILE_PROVIDER_PATHS"
          android:resource="@xml/provider_paths" />
 </provider>
<paths>
    <external-path name="external_files" path="."/>
</paths>
 private void ShareIt(View rootView){
        if (rootView != null && context != null && !context.isFinishing()) {
            rootView.setDrawingCacheEnabled(true);
            Bitmap bitmap = Bitmap.createBitmap(rootView.getDrawingCache());
            if (bitmap != null ) {
                 //Save the image inside the APPLICTION folder
                File mediaStorageDir = new File(AppContext.getInstance().getExternalCacheDir() + "Image.png");

                try {
                    FileOutputStream outputStream = new FileOutputStream(String.valueOf(mediaStorageDir));
                    bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);
                    outputStream.close();

                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                }

                if (ObjectUtils.isNotNull(mediaStorageDir)) {

                    Uri imageUri = FileProvider.getUriForFile(getActivity(), getActivity().getApplicationContext().getPackageName() + ".provider", mediaStorageDir);

                    if (ObjectUtils.isNotNull(imageUri)) {
                        Intent waIntent = new Intent(Intent.ACTION_SEND);
                        waIntent.setType("image/*");
                        waIntent.putExtra(Intent.EXTRA_STREAM, imageUri);
                        startActivity(Intent.createChooser(waIntent, "Share with"));
                    }
                }
            }
        }
    }
 Bitmap bitmap = Bitmap.createBitmap(rootView.getWidth(), rootView.getHeight(), quality);
    Canvas canvas = new Canvas(bitmap);

    Drawable backgroundDrawable = view.getBackground();
    if (backgroundDrawable != null) {
        backgroundDrawable.draw(canvas);
    } else {
        canvas.drawColor(Color.WHITE);
    }
    view.draw(canvas);

    return bitmap;