1

В Android 7 getContentResolver().openAssetFileDescriptor(vCardUri, "r") возвращает AssetFileDescriptor, имеющий declaredLength, как -1, возвращаемый getDeclaredLength().В Android 7, метод-openAssetFileDescriptor ContentResolver (в vCardUri, "г") возвращает AssetFileDescriptor, имеющий 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, я наблюдал эту проблему. Любое здоровье будет действительно ощутимым.

+0

попробовать 'GetLength()' – pskink

+0

@pskink AssetFileDescriptor что я получаю оказывает длина собственность как -1.I пытался GetLength() и результат такой же, как предыдущий - NegativeByteArraySizeException –

+1

тогда просто не использовать его: вместо того, чтобы читать ваши данные в петля – pskink

ответ

3

С помощью @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

+1

Кстати, я думаю, вы также можете использовать 'ContentResolver # openInputStream (Uri uri)' непосредственно – pskink

+0

Да. что даже упростит мой код. Это также помогает –

0

В своем коде вы вы используете openAssestFileDescriptor вместо этого использовать openFileDescriptor потому openAssestFileDescriptor это использовать для чтения файла в папке активов не файл Uri

package com.daffo.stackoverflowtest; 

    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(); 
    } 
} 
} 
+0

Следуя предложению pskink - btw, я думаю, вы также можете использовать ContentResolver # openInputStream (Uri uri) напрямую - pskink, теперь я не использую ни один из дескрипторов. Однако это не проблема с моим кодом. Я пробовал это, прежде чем задавать этот вопрос. Спасибо за ваш интерес к ответу на вопрос. Ваш код выглядит хорошо –

+0

Спасибо, человек, ваш код работает для меня. – codeHunter

0

В Android Нуга:

byte[] b = new byte[(int)fd.getDeclaredLength()]; 

fd.getDeclaredLength() возврата -1.

Отметьте здесь мой ответ link.