Android 7、ContentResolver的方法-openAssetFileDescriptor(vCardUri, "r") returns AssetFileDescriptor having declaredLength as -1
In Android 7, ContentResolver's method-openAssetFileDescriptor(vCardUri, "r") returns AssetFileDescriptor having declaredLength as -1
在 Android 7 中,getContentResolver().openAssetFileDescriptor(vCardUri, "r")
returns AssetFileDescriptor
将 getDeclaredLength()
返回的 declaredLength 设为 -1。
正在尝试将联系人作为 vcards 导出到 vcf 文件中。我试过的代码如下
Uri uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_VCARD_URI, lookupKey);
AssetFileDescriptor fd = resolver.openAssetFileDescriptor(uri, "r");
FileInputStream fis = fd.createInputStream();
byte[] b = new byte[(int)fd.getDeclaredLength()];
fis.read(b);
以上代码在 Android 6 或 below.But 中完美运行,当 运行 使用 Android 7 时,创建 byte[] 的行导致 NegativeByteArraySizeException
因为 declaredLength 是 -1。
当我调试下载 Android 7 的源代码时,我发现了这个问题。
任何一种健康都会非常可观。
在@pskink 的帮助下,我发现以下方法解决了我的问题。
String lookupKey = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY));
Uri vCardUri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_VCARD_URI, lookupKey);
AssetFileDescriptor assetFileDescriptor;
FileInputStream inputStream;
try {
assetFileDescriptor = getActivity().getContentResolver().openAssetFileDescriptor(vCardUri, "r");
if (assetFileDescriptor != null) {
inputStream = assetFileDescriptor.createInputStream();
return readAsByteArray(inputStream);
}
} catch (FileNotFoundException e) {
Log.e(TAG, "Vcard for the contact " + lookupKey + " not found", e);
} catch (IOException e) {
Log.e(TAG, "Problem creating stream from the assetFileDescriptor.", e);
}
其中 readAsByteArray() 是使用 Mihai Snippet.
中的代码编写的
谢谢@pskink
在您的代码中,您使用的是 openAssestFileDescriptor 而不是 openFileDescriptor,因为 openAssestFileDescriptor 用于读取资产文件夹中的文件而不是文件 Uri
package com.daffo.Whosebugtest;
import android.Manifest;
import android.content.pm.PackageManager;
import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.provider.ContactsContract;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
Cursor cursor;
ArrayList<String> vCard;
String vfile;
private static final int PERMISSIONS_REQUEST_READ_CONTACTS = 100;
/**
* Called when the activity is first created.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
vfile = "Contacts" + "_" + System.currentTimeMillis() + ".vcf";
/**This Function For Vcard And here i take one Array List in Which i store every Vcard String of Every Conatact
* Here i take one Cursor and this cursor is not null and its count>0 than i repeat one loop up to cursor.getcount() means Up to number of phone contacts.
* And in Every Loop i can make vcard string and store in Array list which i declared as a Global.
* And in Every Loop i move cursor next and print log in logcat.
* */
addContactPermissions();
}
/**
* Show the contacts in the ListView.
*/
private void addContactPermissions() {
// Check the SDK version and whether the permission is already granted or not.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && (checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED || checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)) {
requestPermissions(new String[]{Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSIONS_REQUEST_READ_CONTACTS);
//After this point you wait for callback in onRequestPermissionsResult(int, String[], int[]) overriden method
} else {
// Android version is lesser than 6.0 or the permission is already granted.
getVcardString();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions,
int[] grantResults) {
if (requestCode == PERMISSIONS_REQUEST_READ_CONTACTS) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission is granted
getVcardString();
} else {
Toast.makeText(this, "Until you grant the permission, we canot display the names", Toast.LENGTH_SHORT).show();
}
}
}
private void getVcardString() {
// TODO Auto-generated method stub
vCard = new ArrayList<String>();
cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
if (cursor != null && cursor.getCount() > 0) {
cursor.moveToFirst();
for (int i = 0; i < cursor.getCount(); i++) {
get(cursor);
if (vCard.size() > 0) {
Log.d("TAG", "Contact " + (i + 1) + "VcF String is" + vCard.get(i));
}
cursor.moveToNext();
}
} else {
Log.d("TAG", "No Contacts in Your Phone");
}
}
public void get(Cursor cursor) {
//cursor.moveToFirst();
String lookupKey = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY));
Uri uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_VCARD_URI, lookupKey);
ParcelFileDescriptor fd;
try {
fd = this.getContentResolver().openFileDescriptor(uri, "r");
// Your Complex Code and you used function without loop so how can you get all Contacts Vcard.??
/* FileInputStream fis = fd.createInputStream();
byte[] buf = new byte[(int) fd.getDeclaredLength()];
fis.read(buf);
String VCard = new String(buf);
String path = Environment.getExternalStorageDirectory().toString() + File.separator + vfile;
FileOutputStream out = new FileOutputStream(path);
out.write(VCard.toString().getBytes());
Log.d("Vcard", VCard);*/
FileInputStream fis = new FileInputStream(fd.getFileDescriptor());
byte[] buf = new byte[fis.available()];
fis.read(buf);
String vcardstring = new String(buf);
vCard.add(vcardstring);
String storage_path = Environment.getExternalStorageDirectory().toString() + File.separator + vfile;
FileOutputStream mFileOutputStream = new FileOutputStream(storage_path, false);
mFileOutputStream.write(vcardstring.toString().getBytes());
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
在Android牛轧糖中:
byte[] b = new byte[(int)fd.getDeclaredLength()];
fd.getDeclaredLength() return -1.
在这里查看我的回答 link。
替换此
AssetFileDescriptor assetFileDescriptor = activity.getContentResolver().openAssetFileDescriptor(uri, "r");
FileInputStream fis = assetFileDescriptor.createInputStream();
byte[] buf = new byte[(int) assetFileDescriptor.getDeclaredLength()];
有了这个
AssetFileDescriptor assetFileDescriptor = activity.getContentResolver().openAssetFileDescriptor(uri, "r");
FileInputStream fis = assetFileDescriptor.createInputStream();
byte[] buf = new byte[fis.available()];
在 Android 7 中,getContentResolver().openAssetFileDescriptor(vCardUri, "r")
returns AssetFileDescriptor
将 getDeclaredLength()
返回的 declaredLength 设为 -1。
正在尝试将联系人作为 vcards 导出到 vcf 文件中。我试过的代码如下
Uri uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_VCARD_URI, lookupKey);
AssetFileDescriptor fd = resolver.openAssetFileDescriptor(uri, "r");
FileInputStream fis = fd.createInputStream();
byte[] b = new byte[(int)fd.getDeclaredLength()];
fis.read(b);
以上代码在 Android 6 或 below.But 中完美运行,当 运行 使用 Android 7 时,创建 byte[] 的行导致 NegativeByteArraySizeException
因为 declaredLength 是 -1。
当我调试下载 Android 7 的源代码时,我发现了这个问题。
任何一种健康都会非常可观。
在@pskink 的帮助下,我发现以下方法解决了我的问题。
String lookupKey = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY));
Uri vCardUri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_VCARD_URI, lookupKey);
AssetFileDescriptor assetFileDescriptor;
FileInputStream inputStream;
try {
assetFileDescriptor = getActivity().getContentResolver().openAssetFileDescriptor(vCardUri, "r");
if (assetFileDescriptor != null) {
inputStream = assetFileDescriptor.createInputStream();
return readAsByteArray(inputStream);
}
} catch (FileNotFoundException e) {
Log.e(TAG, "Vcard for the contact " + lookupKey + " not found", e);
} catch (IOException e) {
Log.e(TAG, "Problem creating stream from the assetFileDescriptor.", e);
}
其中 readAsByteArray() 是使用 Mihai Snippet.
中的代码编写的谢谢@pskink
在您的代码中,您使用的是 openAssestFileDescriptor 而不是 openFileDescriptor,因为 openAssestFileDescriptor 用于读取资产文件夹中的文件而不是文件 Uri
package com.daffo.Whosebugtest;
import android.Manifest;
import android.content.pm.PackageManager;
import android.content.res.AssetFileDescriptor;
import android.content.res.AssetManager;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.ParcelFileDescriptor;
import android.provider.ContactsContract;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.Toast;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
Cursor cursor;
ArrayList<String> vCard;
String vfile;
private static final int PERMISSIONS_REQUEST_READ_CONTACTS = 100;
/**
* Called when the activity is first created.
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
vfile = "Contacts" + "_" + System.currentTimeMillis() + ".vcf";
/**This Function For Vcard And here i take one Array List in Which i store every Vcard String of Every Conatact
* Here i take one Cursor and this cursor is not null and its count>0 than i repeat one loop up to cursor.getcount() means Up to number of phone contacts.
* And in Every Loop i can make vcard string and store in Array list which i declared as a Global.
* And in Every Loop i move cursor next and print log in logcat.
* */
addContactPermissions();
}
/**
* Show the contacts in the ListView.
*/
private void addContactPermissions() {
// Check the SDK version and whether the permission is already granted or not.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && (checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED || checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED)) {
requestPermissions(new String[]{Manifest.permission.READ_CONTACTS, Manifest.permission.WRITE_EXTERNAL_STORAGE}, PERMISSIONS_REQUEST_READ_CONTACTS);
//After this point you wait for callback in onRequestPermissionsResult(int, String[], int[]) overriden method
} else {
// Android version is lesser than 6.0 or the permission is already granted.
getVcardString();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions,
int[] grantResults) {
if (requestCode == PERMISSIONS_REQUEST_READ_CONTACTS) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission is granted
getVcardString();
} else {
Toast.makeText(this, "Until you grant the permission, we canot display the names", Toast.LENGTH_SHORT).show();
}
}
}
private void getVcardString() {
// TODO Auto-generated method stub
vCard = new ArrayList<String>();
cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
if (cursor != null && cursor.getCount() > 0) {
cursor.moveToFirst();
for (int i = 0; i < cursor.getCount(); i++) {
get(cursor);
if (vCard.size() > 0) {
Log.d("TAG", "Contact " + (i + 1) + "VcF String is" + vCard.get(i));
}
cursor.moveToNext();
}
} else {
Log.d("TAG", "No Contacts in Your Phone");
}
}
public void get(Cursor cursor) {
//cursor.moveToFirst();
String lookupKey = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY));
Uri uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_VCARD_URI, lookupKey);
ParcelFileDescriptor fd;
try {
fd = this.getContentResolver().openFileDescriptor(uri, "r");
// Your Complex Code and you used function without loop so how can you get all Contacts Vcard.??
/* FileInputStream fis = fd.createInputStream();
byte[] buf = new byte[(int) fd.getDeclaredLength()];
fis.read(buf);
String VCard = new String(buf);
String path = Environment.getExternalStorageDirectory().toString() + File.separator + vfile;
FileOutputStream out = new FileOutputStream(path);
out.write(VCard.toString().getBytes());
Log.d("Vcard", VCard);*/
FileInputStream fis = new FileInputStream(fd.getFileDescriptor());
byte[] buf = new byte[fis.available()];
fis.read(buf);
String vcardstring = new String(buf);
vCard.add(vcardstring);
String storage_path = Environment.getExternalStorageDirectory().toString() + File.separator + vfile;
FileOutputStream mFileOutputStream = new FileOutputStream(storage_path, false);
mFileOutputStream.write(vcardstring.toString().getBytes());
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
}
在Android牛轧糖中:
byte[] b = new byte[(int)fd.getDeclaredLength()];
fd.getDeclaredLength() return -1.
在这里查看我的回答 link。
替换此
AssetFileDescriptor assetFileDescriptor = activity.getContentResolver().openAssetFileDescriptor(uri, "r");
FileInputStream fis = assetFileDescriptor.createInputStream();
byte[] buf = new byte[(int) assetFileDescriptor.getDeclaredLength()];
有了这个
AssetFileDescriptor assetFileDescriptor = activity.getContentResolver().openAssetFileDescriptor(uri, "r");
FileInputStream fis = assetFileDescriptor.createInputStream();
byte[] buf = new byte[fis.available()];