Getting nullpointer exception on running the doinbackground method.. This is my error![enter image description here][1]
this is my error :::
FAIAL EXCEPTION: AsyncIask #1
java.1ang.RuntimeException: An error occured while executing doInBa 45
ckground()
at android.os.AsyncIask$3.done(AsyncIask.java:278)
at java.uti1.concurrent.FutureIask$Sync.innerSetException(FutureIa 45
sk.java:273)
at java.uti1.concurrent.FutureIask.setException(FutureIask.java:12 45
4)
at java.uti1.concurrent.FutureIask$Sync.innerRun(FutureIask.java:3 45
07)
at java.uti1.concurrent.FutureTask.run(FutureIask.java:137)
at android.os.AsyncIask$Seria1Executor$1.run(AsyncIask.java:208)
at java.uti1.concurrent.ThreadPoo1Executor.runworker(IhreadPoo1Exe 45
cutor.java:1076)
at java.uti1.concurrent.IhreadPoo1Executor$Worker.run(IhreadPoo1Ex 45
ecutor.java:569)
at java.1ang.Ihread.run(Ihread.java:856)
Caused by: java.lang.NullPointerException
at com.examp1e.outgoingsms.OutgoingSmsListener$OutSmsLogger.doInBa 45
ckground(OutgoingSmsListener.java:45)
at com.examp1e.outgoingsms.OutgoingSmsListener$OutSmsLogger.doInBa 45
ckground(OutgoingSmsListener.java:1)
at android.os.AsyncIask$2.call(AsyncIask.java:264)
at java.uti1.concurrent.FutureIask$Sync.innerRun(FutureIask.java:3 45
05)
5 more
And this is my code..
public class OutgoingSmsListener extends BroadcastReceiver {
public Context context;
#Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
new OutSmsLogger(context).execute();
}
public class OutSmsLogger extends AsyncTask<Void, Void, Void> {
private final Uri SMS_URI = Uri.parse("content://sms");
private final String[] COLUMNS = new String[] {"date", "address", "body", "type"};
private static final String CONDITIONS = "type = 2 AND date > ";
private static final String ORDER = "date DESC";
private SharedPreferences prefs;
private long timeLastChecked;
private Cursor cursor;
public OutSmsLogger(Context context) {
this.prefs = context.getSharedPreferences("some_file_name", Context.MODE_PRIVATE);
}
#Override
protected Void doInBackground(Void... params) {
// TODO Auto-generated method stub
timeLastChecked = prefs.getLong("time_last_checked", -1L);
ContentResolver cr = context.getContentResolver();
// get all sent SMS records from the date last checked, in descending order
cursor = cr.query(SMS_URI, COLUMNS, CONDITIONS + timeLastChecked, null, ORDER);
// if there are any new sent messages after the last time we checked
if (cursor.moveToNext()) {
Set<String> sentSms = new HashSet<String>();
timeLastChecked = cursor.getLong(cursor.getColumnIndex("date"));
do {
long date = cursor.getLong(cursor.getColumnIndex("date"));
String address = cursor.getString(cursor.getColumnIndex("address"));
String body = cursor.getString(cursor.getColumnIndex("body"));
String thisSms = date + "," + address + "," + body;
if (sentSms.contains(thisSms)) {
continue; // skip that thing
}
// else, add it to the set
sentSms.add(thisSms);
Log.d("Test", "date sent: " + date);
Log.d("Test", "target number: " + address);
Log.d("Test", "number of characters: " + body.length());
} while (cursor.moveToNext());
}
cursor.close();
Editor editor = prefs.edit();
editor.putLong("time_last_checked", timeLastChecked);
editor.commit();
return null;
}
}
}
Please help me to find a solution.
I had the same problem and it only showed up on some devices (or maybe I just always had some data before).
Problem is, that when you filter the result to the period where there is no data (for example you only want SMS for the last day and user didn't send any), you get null cursor. I find it strange and I believe on some devises you get properly initialized cursor, only it's empty, but on others you get null,so always check for null pointer before accessing cursor!
BTW "Problem solved" without providing the answer? Not cool dude!
Related
First and foremost, I found this answer particularly helpful. However, it made me wonder how one goes about finding such information.
I can't seem to figure out how to iterate all the messages in my inbox. My current solution uses Uri.parse("content://mms-sms/conversations") in which I give use "_id" and "ct_t". However, it seems I only find the three conversations in my phone despite having 30 msges (20 of them in the save conversation thread and the others divided between two other conversations). Would make sense for such a statement content://mms-sms/conversations. However, the other providers seem to deal only with SMS OR MMS. Isn't there a way to just iterate the entire list of messages in this fashion where I replace "content://mms-sms/conversations" with something else?
public boolean refresh() {
final String[] proj = new String[]{"_id","ct_t"};
cursor = cr.query(Uri.parse("content://mms-sms/conversations"),proj,null,null,null);
if(!(cursor.moveToFirst())) {
empty = true;
cursor.close();
return false;
}
return true;
}
I iterate the messages with a next function
public boolean next() {
if(empty) {
cursor.close();
return false;
}
msgCnt = msgCnt + 1;
Msg msg;
String msgData = cursor.getString(cursor.getColumnIndex("ct_t"));
if("application/cnd.wap.multipart.related".equals(msgData)) {
msg = ParseMMS(cursor.getString(cursor.getColumnIndex("_id")));
} else {
msg = ParseSMS(cursor.getString(cursor.getColumnIndex("_id")));
}
if(!(cursor.moveToNext())) {
empty = true;
cursor.close();
return false;
}
return true;
}
Well, what I am asking doesn't really seem possible.
For those just starting out on such tasks, it's advisable to learn about how content providers work in general. Each Uri value added to the query returns access to specific tables.
Spending some time looking at the different Telephony.Mmssms tables that one can access and it seems, from my testing, that the only table you can access is using "content://mms-sms/conversations as using "content://mms-sms" leads to a null cursor.
Such is life, and it doesn't really make sense to iterate the messages that way since the content and method of extracting the data differ greatly based on whether or not the msg is an SMS or MMS message. It makes sense to iterate and parse SMS and MMS messages separately and store the interesting data into the same class object type for one to manipulate how they would like at a later date.
Useful to such a topic would be the Telephony.Sms documentation. Which is where one can find a descriptions of the column index fields. You can find the same information for Telephony.Mms as well as the sub table Telephony.Mms.Part, with links to each of the base columns to describe the information.
With this being said, here is a solution to the question How can I iterate all the SMS/MMS messages in the phone? and here is the solution that worked for me.
public class Main extends AppCompatActivity {
//Not shown, Overrides, button to call IterateAll();
//implementations to follow
IterateAll();
public void ScanMMS();
public void ScanSMS();
public void ParseMMS(Msg msg);
public Bitmap getMmsImg(String id);
public String getMmsAddr(String id);
}
IterateAll() just calls the two different functions
IterateAll() {
ScanMMS();
ScanSMS();
}
ScanMMS() will iterate through the content://mms table extracting the data from each MMS.
public void ScanMMS() {
System.out.println("==============================ScanMMS()==============================");
//Initialize Box
Uri uri = Uri.parse("content://mms");
String[] proj = {"*"};
ContentResolver cr = getContentResolver();
Cursor c = cr.query(uri, proj, null, null, null);
if(c.moveToFirst()) {
do {
/*String[] col = c.getColumnNames();
String str = "";
for(int i = 0; i < col.length; i++) {
str = str + col[i] + ": " + c.getString(i) + ", ";
}
System.out.println(str);*/
//System.out.println("--------------------MMS------------------");
Msg msg = new Msg(c.getString(c.getColumnIndex("_id")));
msg.setThread(c.getString(c.getColumnIndex("thread_id")));
msg.setDate(c.getString(c.getColumnIndex("date")));
msg.setAddr(getMmsAddr(msg.getID()));
ParseMMS(msg);
//System.out.println(msg);
} while (c.moveToNext());
}
c.close();
}
}
As one can see, a lot of the important MMS data is in this table, such as the date of the message, the message id and the thread id. You need to use that message ID to pull more information from MMS.
The MMS message is divided into smaller parts of data. Each part contains something different, like an image, or a text portion. You have to iterate each part as I do below.
public void ParseMMS(Msg msg) {
Uri uri = Uri.parse("content://mms/part");
String mmsId = "mid = " + msg.getID();
Cursor c = getContentResolver().query(uri, null, mmsId, null, null);
while(c.moveToNext()) {
/* String[] col = c.getColumnNames();
String str = "";
for(int i = 0; i < col.length; i++) {
str = str + col[i] + ": " + c.getString(i) + ", ";
}
System.out.println(str);*/
String pid = c.getString(c.getColumnIndex("_id"));
String type = c.getString(c.getColumnIndex("ct"));
if ("text/plain".equals(type)) {
msg.setBody(msg.getBody() + c.getString(c.getColumnIndex("text")));
} else if (type.contains("image")) {
msg.setImg(getMmsImg(pid));
}
}
c.close();
return;
}
Each part as the mid field which corresponds to the id of the message found earlier. We search the MMS part library only for that mms id and then iterate the different parts found. ct or content_type as described in the documentation described what the part is, i.e. text, image, etc. I scan the type to see what to do with that part. If it's plain text, I add that text to the current message body (apparently there can be multiple text parts, but I haven't seen it, but I believe it) and if it's an image, than load the image into a bitmap. I imagine Bitmaps will be easy to send with java to my computer, but who knows, maybe want to just load it as a byte array.
Anyway, here is how one will get the image data from the MMS part.
public Bitmap getMmsImg(String id) {
Uri uri = Uri.parse("content://mms/part/" + id);
InputStream in = null;
Bitmap bitmap = null;
try {
in = getContentResolver().openInputStream(uri);
bitmap = BitmapFactory.decodeStream(in);
if(in != null)
in.close();
} catch (IOException e) {
e.printStackTrace();
}
return bitmap;
}
You know, I'm not entirely sure how opening an input stream on the content resolver really works and how it is giving me just the image and not like all the other data, no clue, but it seems to work. I stole this one from some different sources while looking for solutions.
The MMS addresses aren't as straight forward to pull as they are for SMS, but here is how you can get them all. The only thing I haven't been able to do is figure out who the sender was. I'd love it if someone knew that.
public String getMmsAddr(String id) {
String sel = new String("msg_id=" + id);
String uriString = MessageFormat.format("content://mms/{0}/addr", id);
Uri uri = Uri.parse(uriString);
Cursor c = getContentResolver().query(uri, null, sel, null, null);
String name = "";
while (c.moveToNext()) {
/* String[] col = c.getColumnNames();
String str = "";
for(int i = 0; i < col.length; i++) {
str = str + col[i] + ": " + c.getString(i) + ", ";
}
System.out.println(str);*/
String t = c.getString(c.getColumnIndex("address"));
if(!(t.contains("insert")))
name = name + t + " ";
}
c.close();
return name;
}
This was all just for MMS. The good news is that SMS is much simpler.
public void ScanSMS() {
System.out.println("==============================ScanSMS()==============================");
//Initialize Box
Uri uri = Uri.parse("content://sms");
String[] proj = {"*"};
ContentResolver cr = getContentResolver();
Cursor c = cr.query(uri,proj,null,null,null);
if(c.moveToFirst()) {
do {
String[] col = c.getColumnNames();
String str = "";
for(int i = 0; i < col.length; i++) {
str = str + col[i] + ": " + c.getString(i) + ", ";
}
//System.out.println(str);
System.out.println("--------------------SMS------------------");
Msg msg = new Msg(c.getString(c.getColumnIndex("_id")));
msg.setDate(c.getString(c.getColumnIndex("date")));
msg.setAddr(c.getString(c.getColumnIndex("Address")));
msg.setBody(c.getString(c.getColumnIndex("body")));
msg.setDirection(c.getString(c.getColumnIndex("type")));
msg.setContact(c.getString(c.getColumnIndex("person")));
System.out.println(msg);
} while (c.moveToNext());
}
c.close();
}
Here is my simple message structure so anyone may compile the above code quickly if wanted.
import android.graphics.Bitmap;
/**
* Created by rbenedict on 3/16/2016.
*/
//import java.util.Date;
public class Msg {
private String id;
private String t_id;
private String date;
private String dispDate;
private String addr;
private String contact;
private String direction;
private String body;
private Bitmap img;
private boolean bData;
//Date vdat;
public Msg(String ID) {
id = ID;
body = "";
}
public void setDate(String d) {
date = d;
dispDate = msToDate(date);
}
public void setThread(String d) { t_id = d; }
public void setAddr(String a) {
addr = a;
}
public void setContact(String c) {
if (c==null) {
contact = "Unknown";
} else {
contact = c;
}
}
public void setDirection(String d) {
if ("1".equals(d))
direction = "FROM: ";
else
direction = "TO: ";
}
public void setBody(String b) {
body = b;
}
public void setImg(Bitmap bm) {
img = bm;
if (bm != null)
bData = true;
else
bData = false;
}
public String getDate() {
return date;
}
public String getDispDate() {
return dispDate;
}
public String getThread() { return t_id; }
public String getID() { return id; }
public String getBody() { return body; }
public Bitmap getImg() { return img; }
public boolean hasData() { return bData; }
public String toString() {
String s = id + ". " + dispDate + " - " + direction + " " + contact + " " + addr + ": " + body;
if (bData)
s = s + "\nData: " + img;
return s;
}
public String msToDate(String mss) {
long time = Long.parseLong(mss,10);
long sec = ( time / 1000 ) % 60;
time = time / 60000;
long min = time % 60;
time = time / 60;
long hour = time % 24 - 5;
time = time / 24;
long day = time % 365;
time = time / 365;
long yr = time + 1970;
day = day - ( time / 4 );
long mo = getMonth(day);
day = getDay(day);
mss = String.valueOf(yr) + "/" + String.valueOf(mo) + "/" + String.valueOf(day) + " " + String.valueOf(hour) + ":" + String.valueOf(min) + ":" + String.valueOf(sec);
return mss;
}
public long getMonth(long day) {
long[] calendar = {31,28,31,30,31,30,31,31,30,31,30,31};
for(int i = 0; i < 12; i++) {
if(day < calendar[i]) {
return i + 1;
} else {
day = day - calendar[i];
}
}
return 1;
}
public long getDay(long day) {
long[] calendar = {31,28,31,30,31,30,31,31,30,31,30,31};
for(int i = 0; i < 12; i++) {
if(day < calendar[i]) {
return day;
} else {
day = day - calendar[i];
}
}
return day;
}
}
Some final comments and notes on this solution.
The person field seems to always be NULL and later I plan to implement a contact look up. I also haven't been able to identify who sent the MMS message.
I am not super familiar with java and I am still learning it. I am positive there is a data container (ArrayList) (Vector?) that could hold a user defined object. And if sortable by a specific field in the object (date), one could iterate that list and have a chronological order of all the message: both MMS/SMS and both sent/received.
Isn't there a way to just iterate the entire list of messages in this fashion where I replace "content://mms-sms/conversations" with something else?
It is possible to get all MMS and SMS messages in a single query using the content://mms-sms/complete-conversations URL. For some odd reason, there is no Uri field for this in the Telephony.MmsSms class, but it's been available since at least Froyo.
Using this single query will certainly be more efficient than querying the tables separately, and any sorting, grouping, or filtering that needs to be done will definitely be faster performed by the SQLite engine than by manipulating Java collections.
Please note that you must use a specific projection for this query. You cannot pass null or the * wildcard. Furthermore, it would be advisable to include MmsSms.TYPE_DISCRIMINATOR_COLUMN ("transport_type") in your projection - which will have a value of either "mms" or "sms" - to easily distinguish the message type.
The selection, selectionArgs, and orderBy arguments work as usual, and null can be passed for any or all of them.
I am populating contact list details to list view successfully.
My code:
String order = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC";
Cursor curLog = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,null,null,order);
How can I avoid the duplicate data In List view as the contact details is repeating if its joined contact i.e. joined with both phone and Google?. The screen is like
I want to select programmatically only 1 name not the both? Any Idea how I can select?
I have used a rough way to avoid this problem which helped me so much and working nicely.
i.e
Use local database (SQLite) to avoid duplicate data by make phone number to unique.
I have made one SQLite DB to handle this problem:
ContactMerger.java:
public class ContactMerger {
private static final String CONTACT_TABLE = "_contact_table";
private static final String CONTACT_ID = "_contactId";
private static final String CONTACT_NAME = "_contactName";
private static final String CONTACT_MOBILE_NUMBER = "_contactNumber";
private static final String CONTACT_DATE = "_contactDate";
private static final int DATABASE_VERSION = 1;
private static final String DATABASE_NAME = "DB_Contact";
private final Context context;
private SQLiteDatabase ourDatabase;
private DbHelper ourHelper;
private class DbHelper extends SQLiteOpenHelper {
public DbHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
// TODO Auto-generated method stub
String contactQuery = "CREATE TABLE " + CONTACT_TABLE + " ("
+ CONTACT_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
+ CONTACT_NAME + " TEXT NOT NULL, " + CONTACT_DATE
+ " TEXT NOT NULL, " + CONTACT_MOBILE_NUMBER
+ " TEXT NOT NULL UNIQUE);";
db.execSQL(contactQuery);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
// TODO Auto-generated method stub
db.execSQL("DROP TABLE IF EXISTS " + CONTACT_TABLE);
onCreate(db);
}
}
public ContactMerger(Context context) {
this.context = context;
}
public ContactMerger open() throws SQLException {
ourHelper = new DbHelper(context);
ourDatabase = ourHelper.getWritableDatabase();
return this;
}
public void close() {
ourHelper.close();
}
// Insert Data to Contact Table
public long insertContacts(String name, String number, String date) throws SQLException {
ContentValues cv = new ContentValues();
cv.put(CONTACT_NAME, name);
cv.put(CONTACT_DATE, date);
cv.put(CONTACT_MOBILE_NUMBER, number);
Log.d("Insert Data", cv.toString());
return ourDatabase.insert(CONTACT_TABLE, null, cv);
}
//Get Contact details from Contact Table
public ArrayList<ContactHolder> getContactDetails() throws Exception{
ArrayList<ContactHolder> contactDetails = new ArrayList<ContactHolder>();
String[] columns = new String[] { CONTACT_ID, CONTACT_NAME, CONTACT_DATE, CONTACT_MOBILE_NUMBER };
Cursor c = ourDatabase.query(CONTACT_TABLE, columns, null, null, null,null, null);
int iContactName = c.getColumnIndex(CONTACT_NAME);
int iContactDate = c.getColumnIndex(CONTACT_DATE);
int iContactMobileNumber = c.getColumnIndex(CONTACT_MOBILE_NUMBER);
for (c.moveToFirst(); !c.isAfterLast(); c.moveToNext()) {
ContactHolder data = new ContactHolder();
data.setName(c.getString(iContactName));
data.setDate(c.getString(iContactDate));
data.setNumber(c.getString(iContactMobileNumber));
contactDetails.add(data);
}
return contactDetails;
}
}
Here ContactHolder is just a getter/setter class to handle contact entities.
First I inserted all Contact information once in my MainActivity by the help of a background thread. It prevents to insert the contact info multiple times.
Something like:
private ArrayList<ContactHolder> contactHolder;
private void setCallLogs(Cursor managedCursor) {
contactHolder = new ArrayList<ContactHolder>();
int _number = managedCursor
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
int _name = managedCursor
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
int _id = managedCursor
.getColumnIndex(ContactsContract.CommonDataKinds.Phone._ID);
while (managedCursor.moveToNext()) {
ContactHolder holder = new ContactHolder();
holder.setNumber(managedCursor.getString(_number));
holder.setName(managedCursor.getString(_name));
holder.setDate(managedCursor.getString(_id));
contactHolder.add(holder);
}
Thread t = new Thread(new Runnable() {
#Override
public void run() {
for(int i=0; i<contactHolder.size(); i++){
try{
ContactMerger merger = new ContactMerger(HomeActivity.this);
merger.open();
merger.insertContacts(contactHolder.get(i).getName(),
contactHolder.get(i).getNumber(),
contactHolder.get(i).getdate());
merger.close();
} catch(Exception e){
e.printStackTrace();
}
}
}
});
t.start();
}
At last I gtt all contact information inside an Asynctask(doInbackground()) and put in adapter/listview in its onPostExecute() method in the class I want to show.
Here:
#Override
protected ArrayList<ContactHolder> doInBackground(String... parameters) {
ArrayList<ContactHolder> filterContacts = new ArrayList<ContactHolder>();
ContactMerger merger = new ContactMerger(Aaja_Contact.this);
merger.open();
try {
filterContacts = merger.getContactDetails();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
merger.close();
return filterContacts;
}
I believe this may happen if the contact number is stored in two different ways/formats: for example in your case the number for Akshay may be saved as 982-0123456 and 9820123456
Did you try displaying the number along with the Name by including the Number as well in the list view?
You need to retrieve the data from the Cursor to HashSet (which don't allows duplicate itmes) and then pass the HashSet object to your ListView's Adapter
This is a dump solution but it will help you:
ListView listView;
Set<String> listItems;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.listView);
listItems = new HashSet<String>();
String order = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC";
Cursor curLog = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,null,null,order);
if(curLog != null) {
while(curLog.moveToNext()) {
String str = curLog.getString(curLog.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME_PRIMARY));
listItems.add(str);
}
}
String listString = listItems.toString();
listString = listString.substring(1,listString.length()-1);
String[] newList = listString.split(", ");
ArrayAdapter<String> adapter = new ArrayAdapter<String>(MainActivity.this, android.R.layout.simple_list_item_1, newList);
listView.setAdapter(adapter);
}
Good luck..
Since you're querying Phone.CONTENT_URI, I'm assuming you're looking for contacts with phone number.. then you can use ContactsContract.Contacts.CONTENT_URI
String order = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC";
Cursor curLog = getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, null,
ContactsContract.Contacts.HAS_PHONE_NUMBER + "=?", new String[] { "1" }, order);
Its because the listview is showing both normal contacts as well as whatsapp( or like this) linked contacts. Best is to store all the contacts in a Database and then retrieve the contacts using "select distinct..." command of SQL.
String order = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC";
Cursor phones = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,null,null, order);
String temp_name="";
while (phones.moveToNext())
{
String name=phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
if (name.equals(temp_name))
continue;
temp_name=name;
//add name to your list or adapter here`enter code here`
}
phones.close();
When you loop through your contacts, here's something you can do in the looping statement while you add your next object to avoid creating a duplicate contact:
UserList object=new UserList(name,number);
if(arrayList.size()==0)
{
arrayList.add(object);
}
if(arrayList.size()>0) {
position = arrayList.size();
if (!(arrayList.get(arrayList.position - 1).getName().equals(number) ||
arrayList.get(position - 1).getNumber().equals(number)))
{
arrayList.add(object); }
}
Here, in my object of 'UserList' class, the name and number would repeat from the contact list, so this code just checks if the previous object has the same name or number before adding in the new one.
Old question but still relevant. I could not find suitable query to skip dupes with contentresolver but it's possible to compare all contacts for duplicates by phone number.
With com.googlecode.libphonenumber library it's really simple. Method public MatchType isNumberMatch(CharSequence firstNumber, CharSequence secondNumber) compares number, coutry code, mask and return one of MatchType enum value.
I am getting all of my contacts details from contactconstract table, and Want to store all my contact data to String array then I would like to pass it to AsyncTask for doing some background task,Currently I am passing single contacts detail to AsyncTask,that would made my code crash because one by one asynctask is being called for each contact detail, I would like to store all my contact detail into array an then I pass this array to AsyncTASK so only one time AsyncTask would call so Please help me in this regard,
Given below is my part of the code:
ContentResolver cr = getContentResolver();
SavingContacts savingcontacts=new SavingContacts();
Cursor = getContentResolver().query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
null, null,
ContactsContract.Contacts.DISPLAY_NAME + " ASC");
Log.d("database1" ,"17");
if (Cursor.getCount() > 0) {
while (Cursor.moveToNext()) {
phone = Cursor.getString(Cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
if (!TextUtils.isEmpty(phone)) {
Log.d("Your Location4", "ok4:");
name = Cursor.getString(Cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
id = Cursor.getString(Cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.CONTACT_ID));
// photouri=Cursor.getString(Cursor.getColumnIndex(ContactsContract.CommonDataKinds.Photo.PHOTO));
email=Cursor.getString(Cursor.getColumnIndex(ContactsContract.CommonDataKinds.Email.TYPE));
System.out.println("contactId="+ id+ ", name=" + name + ", phoneNumber=" + phone+"Email="+email);
}
savingcontacts.savingcontact(id, name, phone, email);
}
}
Cursor.close();
I am doing this work In oncreate function of activity
//////////////////////////////////////////////////////////////////
Activity Class
public class ContactsListActivity extends FragmentActivity implements
ContactsListFragment.OnContactsInteractionListener {
// Defines a tag for identifying log entries
private static final String TAG = "ContactsListActivity";
private Cursor Cursor;
private ContactDetailFragment mContactDetailFragment;
public DBHandler db;
// If true, this is a larger screen device which fits two panes
private boolean isTwoPaneLayout;
String id,name,phone, email;
// True if this activity instance is a search result view (used on pre-HC devices that load
// search results in a separate instance of the activity rather than loading results in-line
// as the query is typed.
private boolean isSearchResultView = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
if (BuildConfig.DEBUG) {
Utils.enableStrictMode();
}
super.onCreate(savedInstanceState);
Log.d("Hope","Hope 8");
// Set main content view. On smaller screen devices this is a single pane view with one
// fragment. One larger screen devices this is a two pane view with two fragments.
setContentView(R.layout.activity_main);
// Getallcontacts();
// Check if two pane bool is set based on resource directories
isTwoPaneLayout = getResources().getBoolean(R.bool.has_two_panes);
// Check if this activity instance has been triggered as a result of a search query. This
// will only happen on pre-HC OS versions as from HC onward search is carried out using
// an ActionBar SearchView which carries out the search in-line without loading a new
// Activity.
if (Intent.ACTION_SEARCH.equals(getIntent().getAction())) {
// Fetch query from intent and notify the fragment that it should display search
// results instead of all contacts.
String searchQuery = getIntent().getStringExtra(SearchManager.QUERY);
ContactsListFragment mContactsListFragment = (ContactsListFragment)
getSupportFragmentManager().findFragmentById(R.id.contact_list);
Log.d("Hope","Hope 47");
// This flag notes that the Activity is doing a search, and so the result will be
// search results rather than all contacts. This prevents the Activity and Fragment
// from trying to a search on search results.
isSearchResultView = true;
mContactsListFragment.setSearchQuery(searchQuery);
// Set special title for search results
String title = getString(R.string.contacts_list_search_results_title, searchQuery);
setTitle(title);
}
if (isTwoPaneLayout) {
// If two pane layout, locate the contact detail fragment
mContactDetailFragment = (ContactDetailFragment)
getSupportFragmentManager().findFragmentById(R.id.contact_detail);
}
ContentResolver cr = getContentResolver();
// SavingContacts savingcontacts=new SavingContacts();
ArrayList<SavingContacts> contacts = new ArrayList<SavingContacts>();
Cursor = getContentResolver().query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,
null, null,
ContactsContract.Contacts.DISPLAY_NAME + " ASC");
Log.d("database1" ,"17");
if (Cursor.getCount() > 0) {
while (Cursor.moveToNext()) {
SavingContacts savingcontacts=new SavingContacts();
phone = Cursor.getString(Cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
if (!TextUtils.isEmpty(phone)) {
Log.d("Your Location4", "ok4:");
name = Cursor.getString(Cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
id = Cursor.getString(Cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.CONTACT_ID));
// photouri=Cursor.getString(Cursor.getColumnIndex(ContactsContract.CommonDataKinds.Photo.PHOTO));
email=Cursor.getString(Cursor.getColumnIndex(ContactsContract.CommonDataKinds.Email.TYPE));
System.out.println("contactId="+ id+ ", name=" + name + ", phoneNumber=" + phone+"Email="+email);
savingcontacts.savingcontact(id, name, phone, email);
contacts.add(savingcontacts);
}
}
}
Cursor.close();
new LoadSavingInDatabase.execute(contacts);
}
public static class LoadSavingInDatabase extends AsyncTask<ArrayList<SavingContacts>,String,String>{
private static final String TAG_SUCCESS = "success";
private static final String URL = "http://amiranzur.com/android_connect/create_product.php";
JSONObject jsonObject= null;
#Override
protected String doInBackground(ArrayList<SavingContacts>... params) {
List<NameValuePair> params = new ArrayList<NameValuePair>();
params.add(new BasicNameValuePair("id", id));
params.add(new BasicNameValuePair("name", name));
params.add(new BasicNameValuePair("phone", phone));
params.add(new BasicNameValuePair("email" , email ));
JSONObject jsonObject= new JSONParser().makeHttpRequest(URL, "POST", params);
if(jsonObject != null){
try {
int success = jsonObject.getInt(TAG_SUCCESS);
if (success == 1) {
Log.d("create","lpc");
// bool = true;
// Log.d("insert","true" + bool);
} else {
}
} catch (JSONException e) {
Log.d("exception","exc "+e);
Log.d("create","lpc");
}
}
else if(jsonObject == null){
Log.d("null", "null1");
//bool = false;
}
return null;
}
protected void onPostExecute(boolean bool){
if(bool == false)
Log.d("Insertion failed", "ID already inserted");
}
}
/* public void Getallcontacts()
{
ContentResolver resolver;
Cursor c = getContentResolver().query(
Data.CONTENT_URI,
null,
Data.HAS_PHONE_NUMBER + "!=0 AND (" + Data.MIMETYPE + "=? OR " + Data.MIMETYPE + "=?)",
new String[]{Email.CONTENT_ITEM_TYPE, Phone.CONTENT_ITEM_TYPE},
Data.CONTACT_ID);
while (c.moveToNext()) {
long id = c.getLong(c.getColumnIndex(Data.CONTACT_ID));
String name = c.getString(c.getColumnIndex(Data.DISPLAY_NAME));
String data1 = c.getString(c.getColumnIndex(Data.DATA1));
System.out.println(id + ", name=" + name + ", data1=" + data1);
}
}*/
/**
* This interface callback lets the main contacts list fragment notify
* this activity that a contact has been selected.
*
* #param contactUri The contact Uri to the selected contact.
*/
public void onContactSelected(Uri contactUri) {
if (isTwoPaneLayout && mContactDetailFragment != null) {
// If two pane layout then update the detail fragment to show the selected contact
mContactDetailFragment.setContact(contactUri);
} else {
// Otherwise single pane layout, start a new ContactDetailActivity with
// the contact Uri
Intent intent = new Intent(this, ContactDetailActivity.class);
intent.setData(contactUri);
startActivity(intent);
}
}
/**
* This interface callback lets the main contacts list fragment notify
* this activity that a contact is no longer selected.
*/
public void onSelectionCleared() {
if (isTwoPaneLayout && mContactDetailFragment != null) {
mContactDetailFragment.setContact(null);
}
}
#Override
public boolean onSearchRequested() {
// Don't allow another search if this activity instance is already showing
// search results. Only used pre-HC.
return !isSearchResultView && super.onSearchRequested();
}
you need create one class for your purpose like following:
public class Contact()
{
private String _name , _phoneNum , _email , _id;
public Contact(String id , String name , String phoneNum , String emailAdd)
{
_name = name;
_phoneNum = phoneNum;
_id = id;
_email = emailAdd;
}
public void SetName(String name)
{
_name = name;
}
public String GetName()
{
return _name;
}
// other getter and setter
}
and for passing to your AsyncTask use:
ArrayList<Contact> contacts = new ArrayList<Contact>()
// add this two line and do this for all your obj
Contact contact = new Contact(id , name , phoneNumber , emailAddress);
contacts.add(contact);
// after putting all data to contacts do following code
TestAsyncTask task= new TestAsyncTask();
task.execute(contacts);
and AsyncTask class:
class TestAsyncTask extends AsyncTask<ArrayList<Contact>, Void, Void>{
#Override
protected Void doInBackground(ArrayList<Contact>... params) {
// TODO Auto-generated method stub
ArrayList<Contact> contactArray = params[0];
return null;
}
}
While declaring the AsyncTask in your class , declare it as follow :
class TestAsyncTask extends AsyncTask<String[], Void, Void>{
#Override
protected Void doInBackground(String[]... params) {
// TODO Auto-generated method stub
String[] strArray = params[0];
return null;
}
}
The first parameter for the accepts the parameter you want to pass to the Asynctask created by you.
Also, call it as :
new TestAsyncTask().execute(myStringArray);
Create an array list like
ArrayList<SavingContact> contactList = new ArrayList<SavingContact>();
and when you are adding into model object add that object tnto array list like
savingcontacts.savingcontact(id, name, phone, email);
contactList.add(savingcontacts);
and then pass this arraylist in constructor of your asyntask class.
Create a object "Contact" and fillt it with set and get method for ID, NAME, PHONE, and EMAIL.
public class Contact()
{
private String _name;
public void setName(String name)
{
_name = name;
}
public String getName()
{
return _name;
}
[...]
}
Store all your contacts in a List:
List<Contact> contacts = new ArrayList<Contact>()
Send your list to your AsyncTask
Best You Can use like this
class TestAsyncTask extends AsyncTask<ArrayList<String>, Void, Void>{
#Override
protected Void doInBackground(ArrayList<String>... params) {
// TODO Auto-generated method stub
for(int i =0 ; i<params.size();i++)
{
String Str = params.get(i);
}
return null;
}
}
you can use like that,its easy way to store values to Array and also get values
I'm writing an application, which have to help me get all information about browser history, so I wrote a simple code:
public class WebHistory {
private Context context;
private Cursor cr;
public StringBuilder sb;
public WebHistory(Context c){
this.context = c;
}
public void takeHistory(){
cr = context.getContentResolver().query(Browser.BOOKMARKS_URI,Browser.HISTORY_PROJECTION, null, null, null);
cr.moveToFirst();
String title = "";
String date = "";
String visits = "";
String url = "";
String info = "";
if(cr.moveToFirst() && cr.getCount() > 0){
while(cr.isAfterLast() == false){
title = cr.getString(Browser.HISTORY_PROJECTION_TITLE_INDEX);
date = cr.getString(Browser.HISTORY_PROJECTION_DATE_INDEX);
url = cr.getString(Browser.HISTORY_PROJECTION_URL_INDEX);
visits = cr.getString(Browser.HISTORY_PROJECTION_VISITS_INDEX);
info = title + " date: " + date + " url: " + url + " visits" + visits + "\n";
Toast.makeText(context, info, Toast.LENGTH_LONG).show();
cr.moveToNext();
}
}
}
}
Method takeHistory() helps me to take some data about browser history, but I need more functionality, like:
- HISTORY_PROJECTION_DATE_INDEX gives my only one date, and I need all dates (and also hours) when the user visited this page
- Browser.HISTORY_PROJECTION_VISITS_INDEX returns all visits which I made, but I want to divide this amount into gruops of visits which took place at the specified timestamp
Can anybody suggest how can I cull this information or recommend a tutorial, in which I can find necessary information? Thank you in advance for your advice.
You will need to start content observor and record all the changes that occur. I have done similar code. Start a content observor and in the onChange(); function, read the history that has changed since last time you read it(you can use shared preferences for that). And you need to do this all in a service
public void onChange(boolean selfChange) {
super.onChange(selfChange);
/**
* Get SharedPreferneces of the user
*/
SharedPreferences pref= myContext.getSharedPreferences("com.tpf.sbrowser",
Context.MODE_PRIVATE);
long wherelong = pref.getLong("Date", 0);
DatabaseManager db=new DatabaseManager(myContext,1);
String[] proj = new String[] { Browser.BookmarkColumns.TITLE,
Browser.BookmarkColumns.URL, BookmarkColumns.DATE,};
String sel = Browser.BookmarkColumns.BOOKMARK + " = 0";
Cursor mCur = myContext.getContentResolver().query(
Browser.BOOKMARKS_URI, proj, sel, null, null);
Log.d("onChange", "cursorCount"+mCur.getCount());
mCur.moveToFirst();
String title = "";
String url = "";
long lastVisitedDate=0;
//You will need to create a database manager to manage your database and use its helper functions
DbMessage msg = new DbMessage(lastVisitedDate,url, title);
/**
* Start reading the user history and dump into database
*/
if(mCur.moveToFirst() && mCur.getCount() > 0) {
while (mCur.isAfterLast() == false) {
title =mCur.getString(0);
url = mCur.getString(1);
lastVisitedDate =mCur.getLong(2);
if ((lastVisitedDate>wherelong) && (!title.equals(url))) {
msg.set(lastVisitedDate, url, title);
db.InsertWithoutEnd(msg);
pref.edit().putBoolean("BrowserHistoryRead", true).commit();
pref.edit().putLong("Date", lastVisitedDate).commit();
myContext.updateTime(wherelong,lastVisitedDate);
wherelong=lastVisitedDate;
}
mCur.moveToNext();
}
}
mCur.close();
}
}
/**
* (non-Javadoc)
* #see android.app.Service#onDestroy()
*/
#Override
public void onDestroy() {
super.onDestroy();
getApplication().getContentResolver().unregisterContentObserver(
observer);
Toast.makeText(this, "Service destroyed ...", Toast.LENGTH_LONG).show();
state = 0;
}
}
I want to access the sms logs also . but I don't find any way , I already accessed the call logs using CallLog.Calls ,it's unable to list sms logs .
below code is listing only call logs , but not all logs even sms logs are not listed (sms logs means logs created because received and sent sms) . please help me to find the way to retrieve the sms logs . please ans if possible sir .
Cursor cursor = managedQuery(CallLog.Calls.CONTENT_URI, null, null,
null, Calls.DATE + " DESC");
// cursor is inited
cursor.moveToFirst();
String name;
String number;
int type;
do {
name = "";
number = "";
type = -1;
try {
number = cursor.getString(cursor
.getColumnIndex(CallLog.Calls.NUMBER));
type = cursor.getInt(cursor.getColumnIndex(CallLog.Calls.TYPE));
try {
name = cursor.getString(cursor
.getColumnIndex(CallLog.Calls.CACHED_NAME));
} catch (Exception e) {
} finally {
if (name == null || name.equals("")) {
name = "UNKNOWN";
}
}
Log.e("My App", name + " : "+number + " : "+type);
} catch (Exception e) {
Log.e("My App", "Error in creation");
}
} while (cursor.moveToNext());
this is just suggestion. you get better answer rather then this...
see if you want to get sms log then use below code.. and you already get call log.. so if you want to mix call and sms log in one list then you must have to do that by date..
in call log you get date & time
in sms also you get date & time
sms log code...
put this in method and use your own way..
CharSequence contentTitle = getString(R.string.app_name);
final ProgressDialog progDailog = ProgressDialog.show(
All_logs_tab.this, contentTitle, "Please wait...", true);
final Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
/* finish sms load */
}
};
new Thread() {
public void run() {
try {
Uri myMessage = Uri.parse("content://sms/");
ContentResolver cr = con.getContentResolver();
Cursor c = cr.query(myMessage, new String[] { "_id",
"address", "date", "body", "read" }, null,
null, null);
startManagingCursor(c);
getSmsLogs(c, con);
} catch (Exception e) {
}
handler.sendEmptyMessage(0);
progDailog.dismiss();
}
}.start();
.................................................
i added all sms details in array list
ArrayList<String> sms_id = new ArrayList<String>();
ArrayList<String> sms_num = new ArrayList<String>();
ArrayList<String> sms_Name = new ArrayList<String>();
ArrayList<String> sms_dt = new ArrayList<String>();
ArrayList<String> sms_body = new ArrayList<String>();
........................................................
public void getSmsLogs(Cursor c, Context con) {
if (sms_num.size() > 0) {
sms_id.clear();
sms_num.clear();
sms_Name.clear();
sms_body.clear();
sms_dt.clear();
}
try {
if (c.moveToFirst()) {
do {
if (c.getString(c.getColumnIndexOrThrow("address")) == null) {
c.moveToNext();
continue;
}
String _id = c.getString(c.getColumnIndexOrThrow("_id"))
.toString();
String Number = c.getString(
c.getColumnIndexOrThrow("address")).toString();
String dat = c.getString(c.getColumnIndexOrThrow("date"))
.toString();
String as = (String) get_dt(dat, "dd/MM/yyyy, hh.mma");
String Body = c.getString(c.getColumnIndexOrThrow("body"))
.toString();
String name = getContactDisplayNameByNumber("" + Number,
con);
if (name.length() <= 0 || name.length() == 1) {
name = "no name";
}
sms_id.add(_id);
sms_num.add(Number);
sms_Name.add("" + name);
sms_body.add(Body);
sms_dt.add(as);
} while (c.moveToNext());
}
c.close();
} catch (Exception e) {
e.printStackTrace();
}
}
You need the URI to the SMS messages's table this will retrieve you the data. It can be found in the base source code, however; it is not recommended by Google to do this.
use this link Android call logs to retrieve call logs. for sms do the same by using SMS_URI="content://sms" , but it is not recommended as it is not public URi.