I'm very new to android, and programming in general. I've got an email receiver using the K9 email client. I'm checking the email for proper formatting and taking the contents of the email and entering it into an SQLite database on the phone. The receiver is working properly. The problem is that when I send a properly formatted message, it makes 2 records from the first email. If I send another message without deleting the first one, it makes 4 records of the second. The third makes 6 records, etc. I know there is probably something obvious that I'm missing but I can't find the problem.
Here is the code:
public class EmailReceiver extends BroadcastReceiver{
private JobsData jobs;
public static final Uri k9uri = Uri.parse("content://com.fsck.k9.messageprovider/inbox_messages/");
static String[] messages_projection = new String[] {"subject", "preview", "unread"};
#Override
public void onReceive(Context context, Intent intent) {
try {
Context mContext = context;
Cursor curSt = mContext.getContentResolver().query(k9uri, messages_projection, "unread='true'", null, null);
curSt.moveToFirst();
String preview = null;
String subject = null;
jobs = new JobsData(context);
int i = 0;
while (!curSt.isAfterLast()) {
subject = curSt.getString(0);
boolean test = subject.startsWith("JOB# ");
if (test) {
boolean check = true;
try {
for (int k = 5; k < subject.length(); k++) {
if (!Character.isDigit(subject.charAt(k))) {
check = false;
break;
}
}
} catch (Exception e) {
} finally {
}
if (check) {
preview = curSt.getString(1);
compareDb(subject.substring(7), preview, context);
}
}
curSt.moveToNext();
}
curSt.close();
} catch (Exception e) {
Toast toast = Toast.makeText(context, e.toString(), Toast.LENGTH_LONG);
toast.show();
}
if (emails != null) {
}
}
private void compareDb (String jobNo, String preview, Context context) {
try {
String[] dbJobs = new String[] {"JobNo"};
SQLiteDatabase db = jobs.getReadableDatabase();
Cursor dbCur = db.query(tableName, dbJobs, null, null, null, null, null);
dbCur.moveToFirst();
while (!dbCur.isAfterLast()) {
if (!jobNo.equals(dbCur.getString(0))) {
jobExtractor(preview, jobNo, context);
}
dbCur.moveToNext();
}
dbCur.close();
} catch (Exception e){
Toast toast = Toast.makeText(context, e.toString(), Toast.LENGTH_LONG);
toast.show();
}
}
private void addJobs(Job job){
SQLiteDatabase db = jobs.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(custName, job.getCustName());
values.put(jobNumber, job.getJobNumber());
values.put(jobType, job.getJobType());
values.put(address, job.getAddress());
values.put(zip, job.getZip());
values.put(contact, job.getContact());
values.put(contactNumber, job.getContactNumber());
values.put(problem, job.getProblem());
db.insertOrThrow(tableName, null, values);
db.close();
}
The "jobextractor" method works fine so I didn't include it. If someone can please help me I would appreciate it.
Thanks
Just a side note. I also want it to only look at unread email but that's not working either. Not a major problem at this point but if you have an answer to that I would be very grateful.
I foundthe problem.
while (!dbCur.isAfterLast()) {
if (!jobNo.equals(dbCur.getString(0))) {
jobExtractor(preview, jobNo, context);
}
dbCur.moveToNext();
}
The problem was here. I was checking to see if the job number matched existing records in the database. It went through each record in the table and added a new job for every record that didn't match. I replaced the jobExctractor line with a boolean check and if the check returned true after the loop I didn't add the job.
Related
I am creating a simple, sort of login app in Android. The point of the app (for now) is to open a new activity if the username and password are correct.
The username and password are stored in a database. The log in is done after comparing the username and password that are entered in the EditText fields with the ones in the database. If they are a match, than new activity is opened.
The issue that I am having is that only the last user can log in, meaning that the new activity is opened only if username and password of the last user in the table are entered as log in information. In my table I have created 5 users each one having a different user and password. But, when I enter the information for the first user in the login in screen (if I enter user and pass of some other user in the EditText field), nothing happens. It is displaying a toast that I have programmed as if the info about that user is not stored in the table.
Here is the code that I am using for this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
user = findViewById(R.id.userEditTextField);
pass = findViewById(R.id.passEditTextField);
}
public void loginButtonClick(View view) {
if (drSchDBHelper == null) {
drSchDBHelper = new DrSchDBHelper(this);
}
db = drSchDBHelper.getReadableDatabase();
Cursor cursor = null;
String savedUser = null;
String savedPass = null;
try {
cursor = db.rawQuery("SELECT * FROM LoginTable", null);
while (cursor.moveToNext()) {
savedUser = cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_NAME_USER));
savedPass = cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_NAME_PASSWORD));
}
if (user.getText().toString().equals(savedUser) && pass.getText().toString().equals(savedPass)) {
Intent userLoginIntent = new Intent(this, UserLoginPage.class);
startActivity(userLoginIntent);
} else {
Toast.makeText(this, "Please,check your Username and Password, or create an account", Toast.LENGTH_LONG).show();
}
} catch (Exception e) {
Log.e("Error:", e.toString());
} finally {
cursor.close();
db.close();
}
}
If anyone has an idea, or an advice, link or anything that could point me in the desired direction, I would appreciate it. Cheers!
It's because you are only comparing the last username and password. Change it to this (Also you need to call this on background thread, as this is currently doing disk read on UI thread, aka main thread):
try {
cursor = db.rawQuery("SELECT * FROM LoginTable", null);
boolean loggedIn = false;
while (cursor.moveToNext()) {
savedUser = cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_NAME_USER));
savedPass = cursor.getString(cursor.getColumnIndexOrThrow(COLUMN_NAME_PASSWORD));
if (user.getText().toString().equals(savedUser) && pass.getText().toString().equals(savedPass)) {
loggedIn = true;
Intent userLoginIntent = new Intent(this, UserLoginPage.class);
startActivity(userLoginIntent);
break;
}
}
if (!loggedIn) {
Toast.makeText(this, "Please,check your Username and Password, or create an account", Toast.LENGTH_LONG).show();
}
} catch (Exception e) {
Log.e("Error:", e.toString());
} finally {
cursor.close();
db.close();
}
I guess it would be better if you do this in such a way that store data from EditTexts in some variable then perform validation.
For Example
public boolean isLoginValid(String username, String password) {
String sql = "Select count(*) from user where username='" + username + "' and password='" + password + "'";
SQLiteStatement sqLiteStatement = getReadableDatabase().compileStatement(sql);
long l = sqLiteStatement.simpleQueryForLong();
sqLiteStatement.close();
return l == 1;
}
If method returns true, then data exists and new activity should appear.
Summary
SQLiteDatabase.insertOrThrow() executes, does not throw an exception, and returns a positive integer; however, the record is not written to the database.
Details
I am implementing the repository pattern, and have a generic base repository.
public class BaseRepository<T> implements Repository<T> {
private enum Operation {
Add, Update, Delete
}
private final SQLiteOpenHelper openHelper;
private final String tableName;
private final Mapper<T, ContentValues> toContentValues;
private final Mapper<Cursor, T> toTypeMapper;
public BaseRepository(Context context, String tableName, Mapper<T, ContentValues> toContentValues,
Mapper<Cursor, T> toTypeMapper) {
this.openHelper = new DbOpenHelper(context);
this.tableName = tableName;
this.toContentValues = toContentValues;
this.toTypeMapper = toTypeMapper;
}
#Override
public void add(T item) {
transaction(Operation.Add, item, null);
}
#Override
public void update(T item, String filter) {
transaction(Operation.Update, item, filter);
}
#Override
public void delete(String filter) {
transaction(Operation.Delete, null, filter);
}
private void transaction(Operation operation, T item, String filter) {
final SQLiteDatabase database = openHelper.getWritableDatabase();
database.beginTransaction();
try {
switch (operation) {
case Add:
try { // For debugging, to catch any possible exception
ContentValues values = toContentValues.map(item);
long result = database.insertOrThrow(tableName, null, values);
String temp = ""; // For debugging
} catch (Exception e) {
String message = e.getMessage(); // For debugging
}
break;
case Update:
database.update(tableName, toContentValues.map(item), filter, null);
break;
case Delete:
database.delete(tableName, filter, null);
break;
}
} finally {
database.endTransaction();
database.close();
}
}
}
It gets into the transaction() method, and runs the database.insert() method. I have set breakpoints and have examined the table name and the values. The table name is correct and the values is correct. The method runs and returns a positive integer, indicating that the insert was successful. However, when I examine the database, the record is not inserted.
I have methods to get data and they are working correctly. If I manually add a row, the get method works successfully.
Any thoughts on what is going on here? I've been stuck on this for hours.
Thanks!
Figured it out. I forgot to run database.setTransactionSuccessful():
private void transaction(Operation operation, T item, String filter) {
final SQLiteDatabase database = openHelper.getWritableDatabase();
database.beginTransaction();
try {
switch (operation) {
case Add:
try { // For debugging, to catch any possible exception
ContentValues values = toContentValues.map(item);
long result = database.insertOrThrow(tableName, null, values);
String temp = ""; // For debugging
} catch (Exception e) {
String message = e.getMessage(); // For debugging
}
break;
case Update:
database.update(tableName, toContentValues.map(item), filter, null);
break;
case Delete:
database.delete(tableName, filter, null);
break;
}
database.setTransactionSuccessful(); // Added this.
} finally {
database.endTransaction();
database.close();
}
}
I am developing an application in which i am working on Android Contacts and not able to move ahead. In app the need of application is that the contact which is updated should send to server or the contact which is deleted should send to server for sync.
I am using the contact service as:
public class ContactService extends Service {
private int mContactCount;
Cursor cursor = null;
static ContentResolver mContentResolver = null;
// Content provider authority
public static final String AUTHORITY = "com.android.contacts";
// Account typek
public static final String ACCOUNT_TYPE = "com.example.myapp.account";
// Account
public static final String ACCOUNT = "myApp";
// Instance fields
Account mAccount;
Bundle settingsBundle;
#Override
public void onCreate() {
super.onCreate();
// Get contact count at start of service
mContactCount = getContactCount();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
// Get contact count at start of service
this.getContentResolver().registerContentObserver(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, true, mObserver);
return Service.START_STICKY;
}
#Override
public IBinder onBind(Intent arg0) {
return null;
}
private int getContactCount() {
try {
cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
if (cursor != null) {
return cursor.getCount();
} else {
cursor.close();
return 0;
}
} catch (Exception ignore) {
} finally {
cursor.close();
}
return 0;
}
private ContentObserver mObserver = new ContentObserver(new Handler()) {
#Override
public void onChange(boolean selfChange) {
this.onChange(selfChange, null);
}
#Override
public void onChange(boolean selfChange, Uri uri) {
new changeInContact().execute();
}
};
public class changeInContact extends AsyncTask<String, Void, String> {
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected String doInBackground(String... arg0) {
ArrayList<Integer> arrayListContactID = new ArrayList<Integer>();
int currentCount = getContactCount();
if (currentCount > mContactCount) {
// Contact Added
} else if (currentCount < mContactCount) {
// Delete Contact
} else if (currentCount == mContactCount) {
// Update Contact
}
mContactCount = currentCount;
return "";
}
#Override
protected void onPostExecute(String result) {
contactService = false;
} // End of post
}
}
The issues i am facing are as follows :
A: In the above code for getting the recently updated contact i need to check the Version of each contact from device with my database stored version of contacts. Which took much time for large amount of contacts.
B. For getting deleted contact i need to check that the data for the Raw id stored in my database is present in device or not. If not then the contact is deleted. It also take too much time to check whole contacts.
But the same thing contact refresh is done in whats app in very few seconds like 2 to three seconds...
EDIT :
In the above code in following module :
if (currentCount > mContactCount) {
// Contact Added
Log.d("In","Add");
} else if (currentCount < mContactCount) {
// Delete Contact
Log.d("In","Delete");
} else if (currentCount == mContactCount) {
// Update Contact
Log.d("In","Update");
}
I put the log. So the update module is called many times, and also when i do add or delete that time too...
Please guide me and suggest me what to do to reduce the timing for the above tasks...
use the below query to get all the deleted and updated contacts.
public static final String ACCOUNT_TYPE = "com.android.account.youraccounttype"
public static final String WHERE_MODIFIED = "( "+RawContacts.DELETED + "=1 OR "+
RawContacts.DIRTY + "=1 ) AND "+RawContacts.ACCOUNT_TYPE+" = '"+ ACCOUNT_TYPE+"'";
c = contentResolver.query(ContactsContract.RawContacts.CONTENT_URI,
null,
WHERE_MODIFIED,
null,
null);
I am trying to develop a function that gives my android application a test to see if the data on the phone matches that on the server.
I have every part of the function working fine apart from I want the message to come back from the server to the handler then I want the handler to return false or true and pass the value to function which returns a boolean.
A point in the right direction would be greatly appreciated.
here is the android code so far.
public boolean isTripUpladedToServer(int tripId)
{
if(isServiceRunning()&&tripId==currentTripId){return false;}
SQLiteDatabase db;
db=this.openOrCreateDatabase(DATABASE_NAME, SQLiteDatabase.OPEN_READWRITE, null);
String Qu="SELECT COUNT(tripid) from TRIP_DATA WHERE TRIPID="+tripId+";";
Cursor c= db.rawQuery(Qu, null);
int count=0;
if(c!=null &&c.moveToFirst())
{
count=c.getInt(0);
}
JSONArray parcel =new JSONArray();
JSONObject header =new JSONObject();
JSONObject message =new JSONObject();
try {
header.put("tablename", "isTripUploaded");
header.put("userid", userid);
parcel.put(header);
message.put("count", count);
message.put("tripid", tripId);
parcel.put(message);
Log.i(tag, parcel.toString());
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Handler inner=new Handler()
{
#Override
public void handleMessage(Message msg)
{
try {
JSONObject ret=new JSONObject(msg.obj.toString());
Log.i(tag,ret.toString());
// I want the function to return the boolean value that the server has sent to phone.
} catch (JSONException e) {
e.printStackTrace();
}
}
};
new uploadero(inner).execute(parcel);
//the below return value is here to prevent the error, ideally I want to remove it
return false;
}
If I have approached this in the wrong way please say, thanks in advance Mark
Use a class variable for the boolean and use a getter in the handler to get it.
When my app is started, I get tiket from server that I use for sign response to server. This ticket (string) I save in database and when I run new response I get this tiket from database and attach to response. All was fine when I run responses from same activity where I save my ticket. I mean that when I am saving tiket, I also releases context of activity where I am executing this actions with database. BUT when I save tiket in one activity, launch another activity and try to get ticket from database in second activity, I get null (rown didn't contain item). So, can anybody tell me, where I'm erred?
I appreciate any help. Thank you.
Here code:
public long setTicket(Ticket ticket) throws SQLException {
ContentValues insertValues = new ContentValues();
insertValues.put(TicketTable.KEY_TICKET, ticket.getTicket());
insertValues.put(TicketTable.KEY_RESULT_CODE, ticket.getResultCode());
long result = m_db.insert(DATABASE_TABLE_TICKET, null, insertValues);
return result;
}
public Ticket getTicket() throws SQLException {
String[] columns = { TicketTable.KEY_ID, TicketTable.KEY_TICKET,
TicketTable.KEY_RESULT_CODE };
Cursor cursor = getCursor(DATABASE_TABLE_TICKET, columns);
Ticket result = new Ticket();
result.setTicket(cursor.getString(TicketTable.TICKET_COLUMN));
result.setResultCode(cursor.getString(TicketTable.RESULT_CODE_COLUMN));
cursor.close();
return result;
}
Here methods where I set access to database:
public String getTicket(){
DBAdapter adapter = new DBAdapter(m_context);
adapter.open();
String ticketEncoded = null;
Ticket ticket = null;
try {
ticket = adapter.getTicket();
ticketEncoded = java.net.URLEncoder.encode(ticket.getTicket());
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}finally{
adapter.close();
}
return ticketEncoded;
}
public void saveTicketFromServer(){
GetTicketHandler handler = new GetTicketHandler(m_context);
Ticket ticket = new Ticket();
ticket.setCommand("getTicket");
TicketTask task = new TicketTask(ticket);
createTask(task, handler);
}
And here I have caught null insted of ticket:
String comment = java.net.URLEncoder.encode(strToEncode, "UTF-8");
String barcodeId = "4605246006340";
String ball = "10";
String sign = account.getTicket();//here!
CreateCommentTask task = new CreateCommentTask(barcodeId, ball,
comment, sign);
//TODO create handler
HttpService httpService = new HttpService();
httpService.createTask(task, null);
But in another response all fine:
String sign = account.getTicket();
try {
task = new SearchBarcodeTask(searchForm, sign);
} catch (NoSuchAlgorithmException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
SearchBarcodeHandler handler = new SearchBarcodeHandler(m_activity);
HttpService httpService = new HttpService();
httpService.createTask(task, handler);
Alright the problem that I see is that String sign = account.getTicket();//here!
The account has to be null. So check what you are doing differently between the two other method calls you mentioned. You are doing something different with whatever account is.