how to fix an "IllegalStateException" error? - android

I want to ask that why it isn't working so I can better help myself next time. How to fix IllegalStateException error in android studio. I'm getting this error while the data is being retrieved from the database. The error I'm getting is an Illegal State Exception as described below.
Fatal Exception: java.lang.IllegalStateException
Couldn't read row 6023, col 0 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it.
com.navdemo.ui.forms.FormDetailViewModel$10.run
The code, I'm getting this error on is:
private void initScansForForm() {
if (form == null) {
return;
}
final String formId = form.getFormId();
new Thread() {
public void run() {
List<Scan> scans = new ArrayList<>();
Cursor c = db.fetchFormScans(formId);
int id = 0;
while (c.moveToNext()) {
if (!c.isNull(0)){
id = c.getInt(0);
}
else {
Log.d(TAG, "run: "+id);
}
int formId = c.getInt(1);
String scanTime = c.getString(2);
String locationName = c.getString(3);
double latitude = c.getDouble(4);
double longitude = c.getDouble(5);
scans.add(new Scan(id, formId, scanTime, locationName, latitude, longitude));
}
setScans(scans);
}
}.start();
}
public Cursor fetchFormScans(#NonNull String formId) {
return fetchFormScans(Integer.parseInt(formId));
}
public Cursor fetchFormScans(#NonNull String formId) `enter code here`{
return fetchFormScans(Integer.parseInt(formId));
}

Try to check that !cursor.isAfterLast() before doing moveToNext

Kindly make sure that you are getting a number in
String formId = form.getFormId();
As your fetchFormScans() method is parsing string formId to integer so it can be problematic if your formId contains alphabets in it.

Related

Find and interate all SMS/MMS messages in android

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.

How to compare an Array List with mobile Contact

I have an array list.
1) my first ArrayList<String> some_num = new ArrayList<String>(); which contain the value like this.
[1111111111, 2222222222]
Now I am trying to compare this with my mobile contact like this.
Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
String[] projection = new String[] {ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Phone.NUMBER};
Cursor people = getActivity().getContentResolver().query(uri, projection, null, null, null);
int indexName = people.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME);
int indexNumber = people.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
int j_count=0;
String number;
people.moveToFirst();
do {
String name = people.getString(indexName);
number = people.getString(indexNumber);
j_count++;
// Do work...
} while (people.moveToNext());
for(int j=0;j<=j_count;j++){
if (some_num.contains(number)){
// do nothing
}
else{
Log.e("num",number);
}
}
I am trying to get those number which is not present in my ArrayList from the mobile phone book. I know that in for condition i have to get the value of array but when i try to do this i am not getting the rest of my contact.
Thanks in advance
dont use any other loop to compare the numbers. What's wrong with your code then?
You are comparing your array with number variable which holds the last number reference. because of which your are getting only single result.
if your still want to use your code then create another arrayList in which you store all the number like this:
ArrayList<String> numberList = new ArrayList<String>();
and to add the number in this list use below line before j++;
numberList.add(number);
Now update your last iterator block to work like this:
for(int j=0;j<numberList.siz();j++){
if (some_num.contains(numberList.get(i)){
// do nothing
}
else{
Log.e("num",numberList.get(i));
}
}
To get complete detail of User you can create the Model class which contains the user details like this:
public class UserDetails{
private String userName;
private String userPhone;
private String userImage;
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserPhone() {
return userPhone;
}
public void setUserPhone(String userPhone) {
this.userPhone = userPhone;
}
public String getUserImage() {
return userImage;
}
public void setUserImage(String userImage) {
this.userImage = userImage;
}
}
Now you have to use this model in your activity to get and set the details of user:
ArrayList<UserDetails> mUserDetailList = new ArrayList<UserDetails>();
and to get the contacts name use this code:
String name = people.getString(indexName);
now store name and phonenumber like this:
UserDetails mUserModel = new UserDetails();
mUserModel.setUserPhone(number);
mUserModel.setUserName(name);
mUserDetailList.add(mUserModel);
Now to check whether the number exists or not:
for(int j=0;j<mUserDetailList.siz();j++){
if (some_num.contains(mUserDetailList.get(i).getUserPhone()){
// do nothing
}
else{
Log.e("num",numberList.get(i).getUserPhone());
Log.e("name",numberList.get(i).getUserName());
}
}
Hope this will solve your problem.
One ideal solution could be to use a hasp map.
Store the entire contact in a hash map as the key
and check if your list has those number by simply trying to put the value to the hash map.
This will work as hash map wont have duplicatesand when u try to insert a duplicate key you will know that
EDIT
I think your code might work with this fix
String number;
people.moveToFirst();
do {
String name = people.getString(indexName);
number = people.getString(indexNumber);
// for(int j=0;j<=j_count;j++){
if (some_num.contains(number)){
// do nothing
}
else{
Log.e("num",number);
//}
j_count++;
// Do work...
} while (people.moveToNext());
}
try as follows and dont forget to clear the list when ever reusing it
ArrayList<String> list = new ArrayList<String>();
people.moveToFirst();
do {
String name = people.getString(indexName);
number = people.getString(indexNumber);
list.add(number);
j_count++;
// Do work...
} while (people.moveToNext());
for(String str:list)
{
if(yournumber.equalsIgnoreCase(str))
{
//do your stuff
}
}

Android cursor sometimes returns empty even when the data exists

I have an android application that first fetch some data from the web (any updates that might available for an Item) and write the data and after that read the fetched data from the database.
The problem is in some cases the reading operation with android cursor returns an empty cursor but we know that the data exist because you updated that exact row some seconds ago!
In fact you can't request an online update for some data that not exist. I searched a lot but no result. I thought I might be from reading and writing at the same time but It wasn't.
below is the code that do this work :
protected Biz doInBackground(Void... params) {
Bundle bundle = BizDetailsActivity.this.getIntent().getExtras();
// bizID = bundle.getLong(BIZ);
BizDataSource ds = new BizDataSource(BizDetailsActivity.this);
ds.openWritable();
long ID = bundle.getLong(BIZ);
if (NetworkHelper.IsConnected(BizDetailsActivity.this)) {
// HERE we write data if avaiable
getBizOnline(ID, ds);
}
//read data from database
biz = ds.getBiz(ID, data.getCurrentUser());
ds.close();
return biz;
}
Code for writing/updating data :
public long updateBiz(long ID, String title, String description,
String address, String phone, String mobile, String fax,
String owner, long city, String website, double latitude,
double longitude, int addDate, String expireDate, long gallery,
String logo, float rate) {
ContentValues values = new ContentValues();
values.put(columns[1], title);
values.put(columns[3], description);
values.put(columns[4], address);
values.put(columns[5], city);
if (gallery > 0) {
values.put(columns[6], gallery);
}
values.put(columns[7], latitude);
values.put(columns[8], longitude);
values.put(columns[9], phone);
values.put(columns[10], mobile);
values.put(columns[11], fax);
values.put(columns[12], website);
values.put(columns[13], owner);
values.put(columns[14], logo);
values.put(columns[15], addDate);
values.put(columns[16], expireDate);
values.put(columns[19], rate);
long result;
try {
result = database.updateWithOnConflict("Bizes", values, "ID = ?",
new String[] { ID + "" },SQLiteDatabase.CONFLICT_FAIL);
} catch (Exception e) {
Log.d("UPDATE_BIZ", e.getMessage());
result = -1;
}
return result;
}
Code for getting data :
public Biz getBiz(long id, long UserId) {
Gallery gallery = null;
City city = null;
BizCategory category = null;
Cursor c = database.query("Bizes", columns, "ID=?", new String[] { id + "" }, null, null, null);
if (c.moveToFirst() == false) {
// here we got empty cursor !!!!
c.close();
return null;
} else {
....
}
}
Can you please try the following code to read your cursor
if(c != null){
c.moveToFirst();
while (cursor.isAfterLast() == false) {
c.moveToNext();
}
}
I found the problem. My delete query was wrong and before getting data the was deleted.

Why does the variable return 0 always?

I am trying to retrieve the count from a Sqlite database. But the variable number is always returning zero even if I adda values in the database. can anyone tell me step by step what am I doing wrong. Here is my code.
public int isUserAvailable(Double latitude,Double longitude)
{
int number = 0;
Cursor c = null;
try
{
c = db.rawQuery("select latitude,longitude from savedlocation where latitude = ? and longitude = ? ", new String[] {String.valueOf(latitude),String.valueOf(longitude)});
if(c.getCount() != 0)
number = c.getCount();
}
catch(Exception e) {
e.printStackTrace();
} finally {
if(c!=null) c.close();
}
return number;
}
I think its because I have initialized number=0; so its returning that value. I am not able to access number outside try.
{String.valueOf(latitude),String.valueOf(longitude)} may be the problem
it doesnt happen EVERY time, but sometimes String.valueOf returns an unexpected value
something like u - s - e - r - a - r - r - y
try latitude+"" , longitude+"" to convert them to string.
cursor.moveToFirst should not affect cursor.getCount()
public int isUserAvailable(Double latitude,Double longitude)
{
int number = 0;
Cursor c = null;
try
{
c = db.rawQuery("select latitude,longitude from savedlocation where latitude = ? and longitude = ? ", new String[] {latitude+"",longitude+""});
if(c.getCount() != 0)
number = c.getCount();
}
catch(Exception e) {
e.printStackTrace();
} finally {
if(c!=null) c.close();
}
return number;
}
On a side note, if you want to just get the number of rows that match a query try this:
public int isUserAvailable(Double latitude,Double longitude)
{
int number = 0;
Cursor c = null;
try
{
c = db.rawQuery("select count(*) from savedlocation where latitude = ? and longitude = ? ", new String[] {latitude+"",longitude+""});
if(c.moveToFirst())
number = c.getInt(0);
}
catch(Exception e) {
e.printStackTrace();
} finally {
if(c!=null) c.close();
}
return number;
}

Android fetch email from contacts doesn't work

I am trying to create a button that opens up contacts and then when you select one contact it fetches the email and adds it to a field in the application.
I've been using the solution found here:
How to call Android contacts list AND Select one phone number from its details screen?
I have changed the code to select the email, but i still get the phone number.
The code is the following:
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (data != null) {
Uri uri = data.getData();
if (uri != null) {
Cursor c = null;
try {
c = getContentResolver().query(uri, new String[]{
ContactsContract.CommonDataKinds.Email.CONTACT_ID,
ContactsContract.Contacts.DISPLAY_NAME,
ContactsContract.CommonDataKinds.Email.ADDRESS},
null, null, null);
if (c != null && c.moveToFirst()) {
long number = c.getLong(0);
String type = c.getString(1);
String mail = c.getString(2);
showSelectedNumber(type, number, mail);
}
} finally {
if (c != null) {
c.close();
}
}
}
}
}
public void showSelectedNumber(String number, long type, String email) {
Toast.makeText(this, type + ": " + number+ ": " + email, Toast.LENGTH_LONG).show();
}
EDIT:
The problem was on the initial query on the onClick call. I am posting the right function
private static final int CONTACT_PICKER_RESULT = 1001;
private static final String DEBUG_TAG = null;
public void doLaunchContactPicker(View view) {
Intent intent = new Intent(Intent.ACTION_PICK);
intent.setType(ContactsContract.CommonDataKinds.Email.CONTENT_TYPE);
startActivityForResult(intent, 1);
}
Sorry,I do not know why it still get the phone number. But , you can screen the results from contacts again by regular expression , if match to email address ,save and if not ,remove
I am sorry for my bad english!
Add a method like this:
private boolean checkMailAddress(String mailAddress){
final String MAIL_ADDR_REGEX = "([\\w-\\.\\\\+]+)#((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.)|(([\\w-]+\\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\\]?)$";
return mailAddress.matches(MAIL_ADDR_REGEX);
}
and I think that you should use "while" , not "if":
while(c != null && c.moveToNext()) {
long number = c.getLong(0);
String type = c.getString(1);
String mail = c.getString(2);
if(checkMailAddress(mail)){
showSelectedNumber(type, number, mail);
}
}

Categories

Resources