Java Question GetAllContacts too slow

D

Deleted member 103

Guest
Hi,

my code is too slow. The Procedure "GetAllContacts" used to store about 5 sec to 150 contacts in one list.

Is it possible to optimize the code to something?

B4X:
package fg.Contacts;

import android.provider.ContactsContract;
import android.provider.ContactsContract.RawContacts;
import android.content.ContentProviderOperation;
import android.content.ContentResolver;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.util.Log;
import anywheresoftware.b4a.BA;
import anywheresoftware.b4a.objects.collections.List;
import java.util.ArrayList;

@BA.ActivityObject
@BA.ShortName("fgContacts")
@BA.Author("Filippo Gozza")
@BA.Version(1.0F)
public class FgContacts
{
  public static final String TAG = "fg.Contacts";
  private BA m_ba;

  public void Initialize(BA ba)
  {
    this.m_ba = ba;
  }

  public String GetPhoneNumberByID(String id)
  {
     List allPhone = new List();
     allPhone.Initialize();
      
     allPhone=GetAllPhoneNumberByID(id);
     if (allPhone.getSize() > 0 ){
        return allPhone.Get(0).toString();        
     }
     else{
        return "";
     }
  }

  public List GetAllPhoneNumberByID(String id)
  {
     List lstPhonMobil = new List();
     List lstPhonOter = new List();
     List allPhone = new List();
     lstPhonMobil.Initialize();
     lstPhonOter.Initialize();
     allPhone.Initialize();
  
     Uri Phones = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
     String[] projection = new String[] { "data1", "data2" };

     String selection = "contact_id = '" + id + "'";
     Cursor Phonecur = this.m_ba.activity.managedQuery(Phones, projection, selection, null, null);

     while (Phonecur.moveToNext()) {
        if (Integer.valueOf(Phonecur.getInt(1))== 2){
           lstPhonMobil.Add(Phonecur.getString(0));              
        }
        else{
           lstPhonOter.Add(Phonecur.getString(0));
        }
     }
     Phonecur.close();
     allPhone.AddAll(lstPhonMobil); //als erst alle Mobile telefonnummer
     allPhone.AddAll(lstPhonOter);  //und dann alle anderen
     return allPhone;
  }
  
  public Bitmap GetContactPhotoByID(String id)
  {
    Uri photo = ContactsContract.Data.CONTENT_URI;
    String[] projection = { "data15" };

    String selection = "contact_id = '" + id + "'";

    Cursor cur = this.m_ba.activity.managedQuery(photo, projection, selection, null, null);

    cur.moveToFirst();
    while (!cur.isAfterLast()) {
      for (int i = 0; i < cur.getColumnCount(); i++)
      {
        byte[] photodata = cur.getBlob(i);
        if (photodata != null) {
          Log.i("fg.Contacts", "Empfange Photo: " + photodata.length);
          Bitmap bmp = BitmapFactory.decodeByteArray(photodata, 0, photodata.length);
          cur.close();
          return bmp;
        }
      }
      cur.moveToNext();
    }
    cur.close();
    return null;
  }

  public Boolean DeleteAllContacts()
  {
    ContentResolver cr = this.m_ba.context.getContentResolver();
    Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI, 
      null, null, null, null);
    while (cur.moveToNext()) {
      try {
        String lookupKey = cur.getString(cur.getColumnIndex("lookup"));
        Uri uri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_LOOKUP_URI, lookupKey);
        cr.delete(uri, null, null);
      }
      catch (Exception e)
      {
        return Boolean.valueOf(false);
      }
    }
    return Boolean.valueOf(true);
  }
  
  public Boolean DeleteContactById(String id)
  {
     ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
     ops.add(ContentProviderOperation.newDelete(RawContacts.CONTENT_URI)
         .withSelection(RawContacts._ID + " = ?", new String[]{id})
         .build());
      ContentResolver cr = this.m_ba.context.getContentResolver();
        try {
            cr.applyBatch(ContactsContract.AUTHORITY, ops);
        }
        catch (Exception e)
         {
           return Boolean.valueOf(false);
         }
       return Boolean.valueOf(true);
  }
  
  private String[] getFirstLastNameById(String id)
    {
      String[] retValue = new String[2];  
      retValue[0] = "";  
      retValue[1] = "";
 
        // NAME: FIRST AND LAST
       String nameWhere = ContactsContract.Data.CONTACT_ID + " = ? AND " + ContactsContract.Data.MIMETYPE + " = ?";
       String[] nameWhereParams = new String[]{id, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE};
       Cursor nameCur = this.m_ba.context.getContentResolver().query(ContactsContract.Data.CONTENT_URI, null, nameWhere, nameWhereParams, null);
       //boolean valid = false;
       while (nameCur.moveToNext()) {
          String firstName = nameCur.getString(nameCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME));
          String lastName = nameCur.getString(nameCur.getColumnIndex(ContactsContract.CommonDataKinds.StructuredName.FAMILY_NAME));
       
          if (firstName!=null && lastName!=null && (firstName.length()>0 || lastName.length()>0)) {
             retValue[0]=firstName;
             retValue[1]=lastName;
             break;
          }
       }
       nameCur.close();     
       return retValue;
    }
   
   public List GetAllContacts()
   {
      List allContacts = new List();
      allContacts.Initialize();
            
      ContentResolver cr = this.m_ba.context.getContentResolver();
      Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI,null, null, null, null);
         
      if (cur.getCount() > 0) {
         while (cur.moveToNext()) {
            
              String[] retValue = new String[5];  
            retValue[0] = "";  
            retValue[1] = "";
            retValue[2] = ""; 
            retValue[3] = ""; 
            retValue[4] = ""; 
            
              String[] retValue1 = new String[2];  
            retValue1[0] = ""; 
            retValue1[1] = "";

            String id = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID));
            String name = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
         
            retValue1=getFirstLastNameById(id);
            
            String phone=GetPhoneNumberByID(id);
            //Cursor pCur = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null,ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = ?",new String[]{id}, null);
            //while (pCur.moveToNext()) {
            //   phone = pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
            //   break;
            //}
            //pCur.close();   
   
            retValue[0]=id;
            retValue[1]=name;
            retValue[2]=phone;
            retValue[3]=retValue1[0];
            retValue[4]=retValue1[1];
            
            allContacts.Add(retValue);
         }
      }
      return allContacts;
   }   
}

Thanks in advance
Filippo
 
D

Deleted member 103

Guest
Can anyone help me or is my source code so well that no longer can be optimized? :confused:
 

mlc

Active Member
Licensed User
Longtime User
Hello Filippo

It would be interesting to add a function that only returns name and ID, this will accelerate the process.

Later, you could access the contact through the ID, but display all contacts would be faster.

Something like :

B4X:
public List GetAllContactsSimple(Boolean sort)
    {
        List allContacts = new List();
        allContacts.Initialize();
                
        ContentResolver cr = this.m_ba.context.getContentResolver();
        Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI,null, null, null, null);
           
        if (cur.getCount() > 0) {
            while (cur.moveToNext()) {
                
                  String[] retValue = new String[2];  
                retValue[0] = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)); 
                retValue[1] = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID));

                allContacts.Add(retValue);
            }
        }
        //sort the list
        return allContacts;
    }

I need it. :)

Thanks
 

warwound

Expert
Licensed User
Longtime User
If a method blocks the UI Thread then you can use an instance of the Runnable Class to execute the same code as your method.
The code in the Runnable will execute in it's own Thread and not block the UI.
Once the code in the Runnable has completed you'd raise a B4A Event:

B4X:
@Events(values = { "MyEventName(AllContacts As List)" })
public class ExampleClass {
   public void GetAllContacts(final BA pBA, final String EventName){
      Runnable runnable1 =new Runnable(){
         @Override
         public void run() {
            //   put the body of your GetAllContacts method here
            
            //   once the method has completed raise an event and return the result to B4A
            pBA.raiseEvent(ExampleClass.this, EventName.toLowerCase(BA.cul)+"_myeventname", new Object[]{allContacts});
         }};
      BA.submitRunnable(runnable1, null, 0);
   }
}

Martin.
 
Top