For background download should i use service? - android

i'm developing my first Android app and i created a class (not Activity) that downloads a JSON file and writes content to SQLite database at every start-up of the application.
I then use an instance of this class in the main activity class.
If the download takes few seconds the home page of my app hangs on a blank screen.
Do you think i should use service instead of a class to handle download and writing of the db?
Could it be a good idea? If it could, what are the advantages?

If you are writing to a database I would recommend using an IntentService
The intent service runs in it's own thread.
When the download is complete you can use LocalBroadcastManager to notify the activity.
It could also work with ContentProvider and Loaders.

I also wanted to download the list of images in background so I used Services with SharedPreferences and I also Used AQuery With the Service.Here the ConnectionDetector is my Java class which checks the Internet Connection is available or not. It works for me. I hope it will give u some help.
public class MyService extends Service {
String f;
String path;
File file;
Bitmap bm;
String url1;
ArrayList<String> url_img;
AQuery aq;
int count = 1;
String val;
ArrayList<String> completed_url_list;
ArrayList<Integer> _index;
FileOutputStream out;
static ArrayList<String> list;
private Thread updateTask = new Thread(new Runnable() {
#Override
public void run() {
while (count < url_img.size()) {
try {
Log.e("Counter", "" + count);
val = url_img.get(count).toString();
final AjaxCallback<Bitmap> cb = new AjaxCallback<Bitmap>() {
#Override
public void callback(String url, Bitmap bm,
AjaxStatus status) {
try {
System.out.println("url is" + url);
String urll = url.substring(url
.lastIndexOf("/") + 1);
Log.e("Image name", "" + urll);
System.out.println("url111" + urll);
File f = new File(path + urll);
f.createNewFile();
System.out.println(f.getAbsolutePath());
try {
out = new FileOutputStream(f);
bm.compress(Bitmap.CompressFormat.JPEG, 40,
out);
if (out != null) {
out.flush();
out.close();
Log.e("download", "Complete");
completed_url_list.add(url);
System.out
.println("Completed Dowmload Image"
+ completed_url_list);
}
} catch (Exception e) {
boolean del_file = f.delete();
if (del_file == true){
Log.e("File", "deleted");
System.out.println("exception");
}
else{
System.out.println("file not deleted");
}
} finally {
out.close();
if (bm != null) {
bm.recycle();
bm = null;
}
System.gc();
}
} catch (FileNotFoundException e) {
} catch (IOException e) {
} catch (Exception e) {
}
}
};
final AQuery aq = new AQuery(getApplicationContext());
aq.ajax(val, Bitmap.class, 0, cb);
} catch (Exception e) {
}
count++;
}
}
});
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
try {
url_img = getArrayList();
completed_url_list = new ArrayList<String>();
_index = new ArrayList<Integer>();
aq = new AQuery(MyService.this);
System.out.println("I am in super");
if (url_img.size() > 0) {
updateTask.start();
}
} catch (Exception e) {
e.printStackTrace();
}
return START_STICKY;
}
#Override
public void onCreate() {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder()
.permitAll().build();
StrictMode.setThreadPolicy(policy);
super.onCreate();
try {
System.out.println("Service Creating");
f = Environment.getExternalStorageDirectory().getAbsolutePath();
path = f + "/HRI3mages/";
file = new File(path);
if (!file.exists()) {
file.mkdir();
}
} catch (Exception e) {
}
}
#Override
public void onDestroy() {
try {
for (int index = 0; index < completed_url_list.size(); index++) {
for (int index1 = 0; index1 < url_img.size(); index1++) {
if (completed_url_list.get(index).equals(
url_img.get(index1))) {
_index.add(index1);
}
}
}
Collections.sort(_index, new MyIntComparable());
System.out.println("next_download" + _index);
for(int index=0;index<_index.size();index++){
url_img.remove(index);
}
System.out.println("After_Deletion_of_Image"+url_img);
_addArray(url_img);
updateTask.interrupt();
} catch (Exception e) {
}
System.out.println("Service destroy");
super.onDestroy();
}
public class MyIntComparable implements Comparator<Integer>{
#Override
public int compare(Integer o1, Integer o2) {
return (o1>o2 ? -1 : (o1==o2 ? 0 : 1));
}
}
public ArrayList<String> getArrayList() {
ArrayList<String> list_url = new ArrayList<String>();
SharedPreferences SharedPref = getSharedPreferences("SSO", MODE_PRIVATE);
int size = SharedPref.getInt("list_size", 0);
for (int i = 0; i < size; i++) {
list_url.add(SharedPref.getString("list_" + i, ""));
}
System.out.println(list_url);
return list_url;
}
public void _addArray(ArrayList<String> list) {
SharedPreferences SharedPref = getSharedPreferences("SSO", 0);
SharedPreferences.Editor editor = SharedPref.edit();
int size = list.size();
editor.putInt("list_size", size);
for (int i = 0; i < size; i++) {
editor.putString("list_" + i, list.get(i));
}
editor.commit();
}
}

You might want to use an AsyncTask.
This will do the work in a background thread, so if it takes long your screen won't hang.
While the work is in progress, you can show a ProgressDialog (optional) to inform the user. You can also add a button to that ProgressDialog to cancel the task if needed.
See this: http://developer.android.com/intl/es/reference/android/os/AsyncTask.html
In this case I prefer an AsyncTask and not a Service so it seems easier and simpler to do what you want.
Good luck =)

Related

Android: Unable to update custom notification when I kill my app

I am downloading multiple files one after the other in service. I want to update download progress in notification. But my notification doesn't update when I kill my app. Download works on different thread. Download works fine in when app is running. When I kill app from recent section, I am unable to update notification.
Here is my DownloadService class
public class DownloadService extends Service {
public static DownloadMap<String, Downloadables> map = new DownloadMap<String, Downloadables>();
private static Thread thread;
private DownloadCancelReceiver receiver;
public DownloadService() {
}
public class BackgroundThread extends Thread {
int serviceId;
private DownloadMap<String, Downloadables> map;
private SpeedRevisionDatabase helper;
private final int notificationId = 1;
private RemoteViews remoteViewsSmall, remoteViewsBig;
private NotificationManagerCompat notificationManager;
private NotificationCompat.Builder mBuilder, mBuilderComplete, downloadFailBuilder;
public BackgroundThread(int serviceId, DownloadMap<String, Downloadables> map) {
this.serviceId = serviceId;
this.map = new DownloadMap<>();
this.map.putAll(map);
}
#Override
public void run() {
remoteViewsSmall = new RemoteViews(getApplicationContext().getPackageName(), R.layout.download_notification_small);
remoteViewsBig = new RemoteViews(getApplicationContext().getPackageName(), R.layout.download_notification);
Intent cancelDownload = new Intent("CANCEL_DOWNLOAD");
PendingIntent pendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 100, cancelDownload, 0);
remoteViewsBig.setOnClickPendingIntent(R.id.tvCancel, pendingIntent);
notificationManager = NotificationManagerCompat.from(DownloadService.this);
mBuilder = new NotificationCompat.Builder(DownloadService.this, "default");
initChannels(DownloadService.this);
mBuilder.setContentTitle("Download is in progress")
.setContentText("Please wait...")
.setSmallIcon(R.mipmap.download)
.setOngoing(true)
.setCustomContentView(remoteViewsSmall)
.setCustomBigContentView(remoteViewsBig)
.setPriority(NotificationCompat.PRIORITY_HIGH);
notificationManager.notify(notificationId, mBuilder.build());
if (android.os.Build.VERSION.SDK_INT > 9) {
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
}
try {
String path = getApplicationContext().getApplicationInfo().dataDir + "/" + "UEP";
File uepFolder = new File(path);
if (!uepFolder.exists()) {
uepFolder.mkdir();
}
int i = 0;
while (map.entrySet().iterator().hasNext()) {
Log.e("WhileCheck", "Now i is " + i);
Map.Entry data = (Map.Entry) map.entrySet().iterator().next();
try {
Downloadables download = (Downloadables) data.getValue();
if (NetworkUtil.getConnectivityStatus(getApplicationContext()) == 0) {
throw new InternetDisconnectedException("Internet Disconnected");
}
HttpURLConnection urlConnection;
InputStream inputStream;
//finding file on internet
try {
URL url = new URL(download.URL);
if (url.toString().endsWith(".xps")) {
url = new URL(url.toString().replace(".xps", ".pdf"));
}
urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.connect();
inputStream = urlConnection.getInputStream();
} catch (IOException e) {
Log.e("IOException", "" + e.getMessage());
i++;
map.remove(data.getKey());
notificationManager.notify(notificationId, mBuilder.build());
continue;
}
//Downloading file over internet
File file = new File(uepFolder + "/" + download.FileName + "" + download.Format + ".download");
try {
int fileSize = urlConnection.getContentLength();
FileOutputStream fileOutput = new FileOutputStream(file);
byte[] buffer = new byte[1024];
int bufferLength = 0;
int count = 0;
int previousProgress = 0;
while ((bufferLength = inputStream.read(buffer)) > 0) {
if (this.isInterrupted()) {
throw new InterruptedException("Thread has been kill (Destroyed)");
}
fileOutput.write(buffer, 0, bufferLength);
count += bufferLength;
int progress = (int) (count * 100L / (float) fileSize);
if (previousProgress > 999) {
updateProgress(map.insertedCount, i, progress, download.Name);
notificationManager.notify(notificationId, mBuilder.build());
previousProgress = 0;
}
previousProgress++;
}
fileOutput.close();
} catch (IOException e) {
Log.e("IOException", "" + e.getMessage());
i++;
map.remove(data.getKey());
continue;
}
File actualFile = new File(uepFolder + "/" + download.FileName + "" + download.Format);
file.renameTo(actualFile);
Log.e("Downloaded",""+actualFile.getAbsoluteFile());
} catch (InterruptedException | InternetDisconnectedException e) {
throw e;
}
i++;
map.remove(data.getKey());
Log.e("Downloaded", "Remaining files are "+map.size());
}
Log.e("WhileCheck", "While End");
// Due to thread, sometime the sequence of code flow is not in correct flow, and "Download complete" Notifaction is getting shown
// Hence this check is required.
if (this.isInterrupted()) {
throw new InterruptedException("Thread has been kill (Destroyed)");
}
notificationManager.cancel(notificationId);
mBuilderComplete = new NotificationCompat.Builder(DownloadService.this, "default");
initChannels(DownloadService.this);
mBuilderComplete.setOngoing(false)
.setContentTitle("Download Complete")
.setColor(Color.WHITE)
.setSmallIcon(R.drawable.download);
notificationManager.notify(2, mBuilderComplete.build());
Log.e("DownloadingService", "File downloaded successfully");
stopSelf();
map.insertedCount = 0;
} catch (InterruptedException e) {
closeNotification();
Log.e("InterruptedException", "" + e.getMessage());
} catch (InternetDisconnectedException e) {
stopSelf();
closeNotification();
showNotification("Internet disconnected", "Download failed. Try again later.");
Log.e("InternetDisconnect", "" + e.getMessage());
}
}
private void updateProgress(int totalFiles, int currentFileCount, int currentProgress, String fileName) {
remoteViewsSmall.setTextViewText(R.id.tvOverAll, currentFileCount + "/" + totalFiles);
remoteViewsSmall.setProgressBar(R.id.overallProgress, totalFiles, currentFileCount, false);
remoteViewsBig.setTextViewText(R.id.tvOverAll, currentFileCount + "/" + totalFiles);
remoteViewsBig.setTextViewText(R.id.tvFileName, "Downloading " + fileName);
remoteViewsBig.setTextViewText(R.id.tvCurrentProgress, currentProgress + "%");
remoteViewsBig.setProgressBar(R.id.overallProgress, totalFiles, currentFileCount, false);
remoteViewsBig.setProgressBar(R.id.currentProgress, 100, currentProgress, false);
}
public void closeNotification() {
if (notificationManager != null)
notificationManager.cancel(notificationId);
}
public void showNotification(String title, String message) {
downloadFailBuilder = new NotificationCompat.Builder(DownloadService.this, "default");
initChannels(DownloadService.this);
downloadFailBuilder.setOngoing(false)
.setContentTitle(title)
.setContentText(message)
.setColor(Color.WHITE)
.setSmallIcon(android.R.drawable.stat_sys_warning);
notificationManager.notify(3, downloadFailBuilder.build());
}
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null) {
ArrayList<Downloadables> list = (ArrayList<Downloadables>) intent.getSerializableExtra("downloadList");
for (Downloadables d : list) {
String key = d.Name + "" + d.FileName;
map.put(key, d);
}
if (thread == null || !thread.isAlive()) {
thread = new BackgroundThread(startId, map);
receiver = new DownloadCancelReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addCategory(Intent.CATEGORY_DEFAULT);
intentFilter.addAction("CANCEL_DOWNLOAD");
registerReceiver(receiver, intentFilter);
thread.start();
}
}
return START_STICKY;
}
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onDestroy() {
Log.e("Service", " Stop");
try {
thread.interrupt();
} catch (Exception e) {
Log.e("Exception", "" + e.getMessage());
}
map.clear();
unregisterReceiver(receiver);
//closeNotification();
}
public static class DownloadCancelReceiver extends BroadcastReceiver {
public DownloadCancelReceiver() {
}
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (action.equalsIgnoreCase("CANCEL_DOWNLOAD")) {
Intent intent1 = new Intent(context, DownloadService.class);
context.stopService(intent1);
}
}
}
public void initChannels(Context context) {
if (Build.VERSION.SDK_INT < 26) {
return;
}
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationChannel channel = new NotificationChannel("default", "Channel name", NotificationManager.IMPORTANCE_LOW);
channel.setDescription("Channel description");
channel.setImportance(NotificationManager.IMPORTANCE_LOW);
channel.setSound(null, null);
notificationManager.createNotificationChannel(channel);
}
private class InternetDisconnectedException extends Exception {
public InternetDisconnectedException(String message) {
super(message);
}
}
public static class DownloadMap<String, Downloadables> extends HashMap<String, Downloadables> {
public int insertedCount;
#Override
public Downloadables put(String key, Downloadables value) {
insertedCount++;
return super.put(key, value);
}
}
}
And From activity I start service like this.
ArrayList<Downloadables> list = helper.GetVideoFileList();
Intent intent1 = new Intent(SRDownloadActivity.this, DownloadService.class);
intent1.putExtra("downloadList", list);
startService(intent1);
I can even Add files to HashMap while downloading is in progress. It also worked fine.
I am unable to figure it out why it is not running in background since it is on different thread.
Here is my notification look like
Threads are killed by the Android OS even if the main app is still working and they dont have access to the UI thats why u should use AsyncTask class its a like a thread that works in background but it has access to the UI of the main. And the jobdispatcher class can help u assign jobs in the background
Here is a good tutorial https://youtu.be/das7FmQIGik

Unable to intercept ANR on all devices

I am trying to intercept ANR (Application Not Responding) in android devices. I am implementing FileObserver on /data/anr/traces.txt file and capture the logs.
I am able to read this file in Samsung Galaxy J7(Android 6.0.1) but not on other devices ex: Nexus 4 (Android 5) and Moto G5 plus (Android 7).
I want FileObserver to read traces.txt on all devices. Any help will be appreciated.
Following is my code:
public class MainActivity extends AppCompatActivity {
private FileObserver fileObs;
private File anrFile = new File("/data/anr/traces.txt");
private File newFile;
int count=0;
long epochTimeCurrent=0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(Build.VERSION.SDK_INT >= 23){
ActivityCompat.requestPermissions(MainActivity.this,
new String[]{Manifest.permission.INTERNET,
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE},
100);
}
fileObs = new FileObserver("/data/anr") {
#Override
public void onEvent(int i, #Nullable String s) {
if(i == FileObserver.CLOSE_WRITE) {
if (anrFile.exists()) {
System.out.println("ANR file available");
//boolean read = anrFile.canRead();
if (count == 0) {
//Log.i("ANRTest", "Traces.text is available ? "+read);
epochTimeCurrent = System.currentTimeMillis();
Log.e("ANRTest", "System time in epoch : "+epochTimeCurrent);
readContent(anrFile);
} else if(count > 0) {
//Log.i("ANRTest", "Count increased : "+count);
}
}
else {
System.out.println("ANR file not available");
}
}
}
};
fileObs.startWatching();
//code to simulate ANR
final RelativeLayout cont = findViewById(R.id.container);
Button btn = findViewById(R.id.btn_anr);
final TextView textView = new TextView(this);
textView.setText("ANR");
btn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
System.out.println("Devtest : Inside onclick");
while (true) {
cont.addView(textView);
cont.removeView(textView);
}
//throw new ArrayIndexOutOfBoundsException();
//throw new RuntimeException("This is a crash");
}
});
}
public void readContent(File file) {
BufferedReader br = null;
FileReader fileReader;
String strLine = "";
try {
fileReader = new FileReader(file);
int pid = android.os.Process.myPid();
br = new BufferedReader(fileReader);
while( (strLine = br.readLine()) != null){
semusi.logger.Log.info(strLine);
//semusi.logger.Log.info("Hello there !");
//System.out.println(strLine);
if(strLine.contains("pid "+pid) && count==0) {
System.out.println("File content is : "+strLine);
long logTime = calcSubstring(strLine);
//semusi.logger.Log.info(strLine);
System.out.println("Log print time : "+logTime);
//1512364990000 and 1512364990670
if(logTime > epochTimeCurrent) {
//semusi.logger.Log.info(strLine);
if(strLine.contains("-- end")) {
}
}
count++;
}
}
fileReader.close();
br.close();
} catch (FileNotFoundException e) {
System.err.println("Unable to find the file: fileName");
} catch (IOException e) {
System.err.println("Unable to read the file: fileName");
}
}
public long calcSubstring(String rawStr) {
if(rawStr.contains("at")){
int index = rawStr.indexOf("2017");
//System.out.println("Index of 2017 is : "+index);
String dateSubs = rawStr.substring(index,index+19);
//System.out.println("Time substring : "+dateSubs);
//2017-12-04 10:42:28
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
Date gmt = null;
try {
gmt = formatter.parse(dateSubs);
} catch (ParseException e) {
e.printStackTrace();
}
long millisecondsSinceEpoch0 = gmt.getTime();
String asString = formatter.format(gmt);
System.out.println("Date after formatting : "+asString);
return millisecondsSinceEpoch0;
}
return 0;
}
}

android multithreading: thread.join() does not work as expected

I have trouble using thread.join in my code below. It should wait for the thread to finish before executing the codes after it, right? It was behaving differently on different occasions.
I have three cases to check if my code goes well
App is used for the first time - works as expected but the loading page don't appear while downloading
App is used the second time (db is up to date) - works okay
App is used the third time (db is outdated, must update) - won't update, screen blacks out, then crashes
I think I have problems with this code on onCreate method:
dropOldSchedule();
dropThread.join();
triggerDownload();
Based on the logs, the code works until before this part... What can be the problem?
MainActivity.java
public class MainActivity extends Activity {
final static int INDEX_ACCTTYPE = 0;
final static int INDEX_ECN = 1;
final static int INDEX_TLN = 2;
final static int INDEX_SIN = 3;
final static int INDEX_MOBILE = 4;
final static int INDEX_CITY = 5;
final static int INDEX_START_DATE = 6;
final static int INDEX_START_TIME = 7;
final static int INDEX_END_DATE = 8;
final static int INDEX_END_TIME = 9;
final static int INDEX_REASON = 10;
final static int INDEX_DETAILS = 11;
DatabaseHandler db;
String str;
ProgressDialog pd;
TextView homeText1, homeText2, homeText3, homeText4;
final private String csvFile = "http://www.meralco.com.ph/pdf/pms/pms_test.csv";
final private String uploadDateFile = "http://www.meralco.com.ph/pdf/pms/UploadDate_test.txt";
Thread dropThread = new Thread(new Runnable() {
public void run() {
db = new DatabaseHandler(MainActivity.this);
db.dropOldSchedule();
runOnUiThread(new Runnable() {
public void run() {
while (!pd.isShowing());
db.close();
pd.dismiss();
}
});
}
});
Thread getUploadDateThread = new Thread(new Runnable() {
public void run() {
try {
URL myURL = new URL(uploadDateFile);
BufferedReader so = new BufferedReader(new InputStreamReader(myURL.openStream()));
while (true) {
String output = so.readLine();
if (output != null) {
str = output;
}
else {
break;
}
}
so.close();
}
catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
runOnUiThread(new Runnable() {
public void run() {
while (!pd.isShowing());
pd.dismiss();
}
});
}
});
Thread downloadThread = new Thread(new Runnable() {
public void run() {
db = new DatabaseHandler(MainActivity.this);
db.beginTransaction();
try {
URL url = new URL(csvFile);
Log.i("dl", "start");
InputStream input = url.openStream();
CSVReader reader = new CSVReader(new InputStreamReader(input));
Log.i("dl", "after reading");
String [] sched;
while ((sched = reader.readNext()) != null) {
if(sched[INDEX_CITY].equals("")) sched[INDEX_CITY]="OTHERS";
try {
db.addRow(sched[INDEX_SIN], sched[INDEX_CITY],
sched[INDEX_START_DATE], sched[INDEX_START_TIME],
sched[INDEX_END_DATE], sched[INDEX_END_TIME],
sched[INDEX_DETAILS], sched[INDEX_REASON]);
} catch (IndexOutOfBoundsException e) {
db.addRow(sched[INDEX_SIN], sched[INDEX_CITY],
sched[INDEX_START_DATE], sched[INDEX_START_TIME],
sched[INDEX_END_DATE], sched[INDEX_END_TIME],
"", sched[INDEX_REASON]);
//e.printStackTrace();
}
}
input.close();
Log.i("dl", "finished");
} catch (MalformedURLException e) {
e.printStackTrace();
db.endTransaction();
} catch (IOException e) {
e.printStackTrace();
db.endTransaction();
}
Log.d("Count", ""+db.count());
db.setTransactionSuccessful();
db.endTransaction();
writeUploadDateInTextFile();
}
});
#SuppressWarnings("unqualified-field-access")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.pms_main);
Button home = (Button) findViewById(R.id.home);
home.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Intent intent = new Intent(MainActivity.this, MeralcoSuite_TabletActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
finish();
}
});
homeText1 = (TextView) findViewById(R.id.home_text1);
homeText2 = (TextView) findViewById(R.id.home_text2);
homeText3 = (TextView) findViewById(R.id.home_text3);
homeText4 = (TextView) findViewById(R.id.home_text4);
homeText1.setVisibility(View.INVISIBLE);
homeText2.setVisibility(View.INVISIBLE);
homeText3.setVisibility(View.INVISIBLE);
homeText4.setVisibility(View.INVISIBLE);
getUploadDate();
try {
getUploadDateThread.join(); //wait for upload date
Log.d("getUploadDate","thread died, upload date=" + str);
if(dbExists()){
db = new DatabaseHandler(MainActivity.this);
Log.d("Count", "" + db.count());
db.close();
if(!uploadDateEqualsDateInFile()){
dropOldSchedule();
dropThread.join();
triggerDownload();
}
showDisclaimer();
Log.i("oncreate", "finished!");
return;
}
triggerDownload();
showDisclaimer();
Log.i("oncreate", "finished!");
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public void dropOldSchedule(){
if(pd!=null && pd.isShowing())
pd.setTitle("Getting upload date...");
else
pd = ProgressDialog.show(this, "Getting upload date",
"This may take a few minutes...", true, false);
dropThread.start();
}
public void triggerDownload() {
if (!checkInternet()) {
showAlert("An internet connection is required to perform an update, please check that you are connected to the internet");
return;
}
if(pd!=null && pd.isShowing())
pd.setTitle("Getting upload date...");
else
pd = ProgressDialog.show(this, "Getting upload date",
"This may take a few minutes...", true, false);
downloadThread.start();
}
public void getUploadDate() {
Log.d("getUploadDate", "getting upload date of schedule");
if(pd!=null && pd.isShowing())
pd.setTitle("Getting upload date...");
else
pd = ProgressDialog.show(this, "Getting upload date",
"This may take a few minutes...", true, false);
getUploadDateThread.start();
}
public void writeUploadDateInTextFile() {
Log.d("writeUploadDateTextFile", "writing:"+str);
try {
OutputStreamWriter out = new OutputStreamWriter(openFileOutput(
"update.txt", 0));
out.write(str);
out.close();
} catch (java.io.IOException e) {
e.printStackTrace();
}
}
public void showDisclaimer() {
Log.d("ShowDisclaimer", "showing disclaimer");
homeText3
.setText("..." + str
+ "...");
homeText1.setVisibility(View.VISIBLE);
homeText2.setVisibility(View.VISIBLE);
homeText3.setVisibility(View.VISIBLE);
homeText4.setVisibility(View.VISIBLE);
Log.d("showDisclaimer", "finished showing disclaimer");
}
public boolean uploadDateEqualsDateInFile() {
Log.d("uploadDateEqualsDateInFile","comparing schedule upload dates");
try {
String recordedDate = "";
InputStream instream = openFileInput("update.txt");
if (instream != null) { // if file the available for reading
Log.d("uploadDateEqualsDateInFile","update.txt found!");
InputStreamReader inputreader = new InputStreamReader(instream);
BufferedReader buffreader = new BufferedReader(inputreader);
String line = null;
while ((line = buffreader.readLine()) != null) {
recordedDate = line;
Log.d("uploadDateEqualsDateInFile","recorded:"+recordedDate);
}
Log.d("uploadDateEqualsDateInFile","last upload date: " + str + ", recorded:" +recordedDate);
if(str.equals(recordedDate)) return true;
return false;
}
Log.d("uploadDateEqualsDateInFile","update.txt is null!");
return false;
} catch (FileNotFoundException e) {
e.printStackTrace();
return false;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
public boolean checkInternet() {
ConnectivityManager cm = (ConnectivityManager) this
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo infos[] = cm.getAllNetworkInfo();
for (NetworkInfo info : infos)
if (info.getState() == NetworkInfo.State.CONNECTED
|| info.getState() == NetworkInfo.State.CONNECTING) {
return true;
}
return false;
}
public boolean dbExists() {
File database=getApplicationContext().getDatabasePath(DatabaseHandler.DATABASE_NAME);
if (!database.exists()) {
Log.i("Database", "Not Found");
return false;
}
Log.i("Database", "Found");
return true;
}
#Override
protected void onDestroy() {
super.onDestroy();
if (db != null) {
db.close();
}
}
#Override
protected void onPause() {
super.onPause();
if (db != null) {
db.close();
}
}
}
Sorry but I couldn't find mistakes or problems in your code. But I would strongly recommend you to use AsyncTask for doing something in different thread. AsyncTask is very easy to use and I would say that it is one of the biggest advantages of java. I really miss it in obj-c.
http://labs.makemachine.net/2010/05/android-asynctask-example/
http://marakana.com/s/video_tutorial_android_application_development_asynctask_preferences_and_options_menu,257/index.html
check those links hope that will help you.
It was already mentioned that AsyncTask is the better alternative. However, it may be the case, that your call to join will throw InterruptedException. Try to use it like this:
while(getUploadDateThread.isRunning()){
try{
getUploadDateThread.join();
} catch (InterruptedException ie){}
}
// code after join
I think the problem that your facing is that you are blocking the UI thread when you call join in the onCreate() method. You should move this code into another thread which should execute in the background and once its done you can update the UI.
Here is a sample code:
final Thread t1 = new Thread();
final Thread t2 = new Thread();
t1.start();
t2.start();
new Thread(new Runnable() {
#Override
public void run() {
// Perform all your thread joins here.
try {
t1.join();
t2.join();
} catch (Exception e) {
// TODO: handle exception
}
// This thread wont move forward unless all your threads
// mentioned above are executed or timed out.
// ------ Update UI using this method
runOnUiThread(new Runnable() {
#Override
public void run() {
// Update UI code goes here
}
});
}
}).start();

Database Lock error Occurs while Running service

I have a service which will update the Sqllite database with data at each 10 minute with the help of service.I have Opened a database connetion and closed the connection when data got updated.
In my application I have differnt pages where database updation took place.I have also Opened a database connetion and closed the connection each and every pages for data updation.
The Problem is that While the service is running I am not Able to Update the data to sqlite throught my application when conncetion opened in the service.
Is there any way to run data base updation simuntanously using service and application.
Will any one help with samples.
I am calling a function in my sevice as given below (code)
public class service_helper extends Service {
public static final String TAG = "Service";
private NotificationManager mNM;
private DatabaseAdapter dbAdapter;
private service_updator serviceUpdator;
private int NOTIFICATION = 1;
private Timer timer = new Timer();
#Override
public IBinder onBind(Intent arg0) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
serviceUpdator = new service_updator(this);
dbAdapter = new DatabaseAdapter(this);
dbAdapter.open();
Toast.makeText(this, "Service created ...", Toast.LENGTH_LONG).show();
startService() ;
}
#Override
public void onStart(Intent intent, int startid) {
}
#Override
public void onDestroy() {
timer.cancel();
super.onDestroy();
Toast.makeText(this, "Service destroyed ...", Toast.LENGTH_LONG).show();
}
private void startService()
{
timer.scheduleAtFixedRate(new mainTask(), 0, 250000);
}
private class mainTask extends TimerTask
{
public void run()
{
try {
serviceUpdator.UploadData();
Log.d(TAG, "Service");
} catch (ParserConfigurationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
private Runnable threadBody = new Runnable() {
public void run() {
try {
serviceUpdator.UploadData();
Log.d(TAG, "Service");
} catch (ParserConfigurationException e) {
}
}
};
}
UploadData() Function Code
dbAdapter = new DatabaseAdapter(this.context);
dbAdapter.open();
Long transactionType = null;
String transactionData = null;
String sql = "Select * from tblTransaction where PKTransaction >?";
Cursor cursorTransaction = dbAdapter.ExecuteRawQuery(sql, "-1");
cursorTransaction.moveToFirst();
dbAdapter.close();
for (int i = 0; i < cursorTransaction.getCount(); i++) {
}
dbAdapter.close();
Application Code
private void SaveSortOrder() throws Exception {
try {
String server1IPAddress = "";
String server2IPAddress = "";
String deviceId = "";
Cursor cursorTransaction;
Cursor cursorAdmin;
DatabaseAdapter dbAdapter;
DataXmlExporter dataXmlExporter;
admin_helper adminhelper;
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("dd-MMM-yyyy");
String RevisedEstimatedDate = sdf.format(date);
adminhelper = new admin_helper(this);
cursorAdmin = adminhelper.GetAdminDetails();
if (cursorAdmin.moveToFirst())
server1IPAddress = cursorAdmin.getString(cursorAdmin
.getColumnIndex("RemoteServer1IPAddress"));
server2IPAddress = cursorAdmin.getString(cursorAdmin
.getColumnIndex("RemoteServer2IPAddress"));
deviceId = cursorAdmin.getString(cursorAdmin
.getColumnIndex("DeviceID"));
cursorAdmin.close();
ContentValues initialSortOrder = new ContentValues();
ContentValues initialTransaction = new ContentValues();
for (int i = 0; i < ListSortOrder.getAdapter().getCount(); i++) {
HashMap result = (HashMap) ListSortOrder.getItemAtPosition(i);
View vListSortOrder;
vListSortOrder = ListSortOrder.getChildAt(i);
TextView Sort_DeliveryOrder = (TextView) vListSortOrder
.findViewById(R.id.et_Sort_Order);
initialSortOrder.put("DeliveryOrder", Sort_DeliveryOrder
.getText().toString());
dbAdapter = new DatabaseAdapter(this);
dbAdapter.open();
dbAdapter.BeginTransaction();
dbAdapter.UpdateRecord("tblDelivery", initialSortOrder,
"PKDelivery" + "="
+ result.get("Sort_PKDelivery").toString(),
null);
dataXmlExporter = new DataXmlExporter(this);
dataXmlExporter.StartDataSet();
String sqlTransaction = "Select 5 as TransactionType,'Update Delivery Order' as Description,'"
+ result.get("Sort_PKDelivery").toString()
+ "' as FKDelivery, "
+ " deviceId as DeviceID ,'"
+ Sort_DeliveryOrder.getText().toString()
+ "' as DeliveryOrder ,date() as TransactionUploadDate,time() as TransactionUploadTime from tblAdmin where PKAdmin > ?";
cursorTransaction = dbAdapter.ExecuteRawQuery(sqlTransaction,
"-1");
dataXmlExporter.AddRowandColumns(cursorTransaction,
"Transaction");
String XMLTransactionData = dataXmlExporter.EndDataSet();
try {
if ((server1IPAddress != "") && (server2IPAddress != "")) {
try {
if (server1IPAddress != "") {
InsertUploadedTrancasctionDetails(
server1IPAddress, deviceId,
XMLTransactionData);
}
} catch (Exception exception) {
if ((server1IPAddress != server2IPAddress)
&& (server2IPAddress != "")) {
InsertUploadedTrancasctionDetails(
server2IPAddress, deviceId,
XMLTransactionData);
}
}
}
} catch (Exception exception) {
initialTransaction
.put("ReceivedDate", RevisedEstimatedDate);
initialTransaction.put("TransactionData",
XMLTransactionData);
dbAdapter.InsertRecord("tblTransaction", "",
initialTransaction);
}
dbAdapter.SetSucessfulTransaction();
dbAdapter.EndTransaction();
dbAdapter.close();
}
} catch (Exception exception) {
throw exception;
}
}
I had a similar problem when moving to Honeycomb it started throwing SQLiteDatabaseLockedException I sorted it by putting a content provider over my database and then Android handles all the threading issues. You can try find the threading problem if you want of course but that would definitely fix it :)

When running my Android App in the Eclipse Debugger, I have a service that notifies. Outside of the debugger it does not send a notification

I'm making an app that sends a notification to the status bar, it sends the notification when stepping through the code in the debugger, however it never sends the notification when run in realtime.
Here is my runnable that generates the notification, again when stepping through this code in the debugger the notification runs however in realtime nothing happens.
public class NewsEvents_Service extends Service {
private static final String NEWSEVENTS = "newsevents";
private static final String KEYWORDS = "keywords";
private NotificationManager mNM;
private ArrayList<NewsEvent> neList;
private int count;
#Override
public void onCreate() {
mNM = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
neList = new ArrayList<NewsEvent>();
getKeywords();
//getNewsEvents();
Thread thr = new Thread(null, mTask, "NewsEvents_Service");
thr.start();
Log.d("Thread", "IT STARTED!!!!!!????!!!!!!!!!!!!!!!?!!?");
}
#Override
public void onDestroy() {
// Cancel the notification -- we use the same ID that we had used to start it
mNM.cancel(R.string.ECS);
// Tell the user we stopped.
Toast.makeText(this, "Service Done", Toast.LENGTH_SHORT).show();
}
/**
* The function that runs in our worker thread
*/
Runnable mTask = new Runnable() {
public void run() {
getNewsEventsFromWeb();
for(NewsEvent ne : neList){
Log.d("Thread Running", "Service Code running!!!!!!!!!!!!!!!");
String body = ne.getBody().replaceAll("\\<.*?>", "");
String title = ne.getTitle();
for(String s : keyWordList){
if(body.contains(s) || body.contains(s.toLowerCase()) ||
title.contains(s) || title.contains(s.toLowerCase())){
ne.setInterested(true);
}
}
if(ne.isInterested() == true ){
Notification note = new Notification(R.drawable.icon,
"New ECS News Event", System.currentTimeMillis());
Intent i = new Intent(NewsEvents_Service.this, FullNewsEvent.class);
i.putExtra("ne", ne);
PendingIntent pi = PendingIntent.getActivity(NewsEvents_Service.this, 0,
i, 0);
note.setLatestEventInfo(NewsEvents_Service.this, "New Event", ne.getTitle(), pi);
note.flags = Notification.FLAG_AUTO_CANCEL;
mNM.notify(R.string.ECS, note);
}
}
}
};
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
/**
* Show a notification while this service is running.
*/
private void getNewsEventsFromWeb() {
HttpClient client = new DefaultHttpClient();
HttpGet get;
try {
get = new HttpGet(getString(R.string.jsonnewsevents));
ResponseHandler<String> response = new BasicResponseHandler();
String responseBody = client.execute(get, response);
String page = responseBody;
Bundle data = new Bundle();
data.putString("page",page);
Message msg = new Message();
msg.setData(data);
handler.sendMessage(msg);
}
catch (Throwable t) {
Log.d("UpdateNews", "PROBLEMS");
}
}
private Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
String page = msg.getData().getString("page");
try {
JSONArray parseArray = new JSONArray(page);
for (int i = 0; i < parseArray.length(); i++) {
JSONObject jo = parseArray.getJSONObject(i);
String title = jo.getString("title");
String body =jo.getString("body");
String pd = jo.getString("postDate");
String id = jo.getString("id");
NewsEvent ne = new NewsEvent(title, pd , body, id);
boolean unique = true;
for(NewsEvent ne0 : neList){
if(ne.getId().equals(ne0.getId())){
unique = false;
}else{
unique = true;
}
}
if(unique == true){
neList.add(ne);
}
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
private ArrayList<String> keyWordList;
public void getNewsEvents(){
try {
InputStream fi = openFileInput(NEWSEVENTS);
if (fi!=null) {
ObjectInputStream in = new ObjectInputStream(fi);
neList = (ArrayList<NewsEvent>) in.readObject();
in.close();
}
}
catch (java.io.FileNotFoundException e) {
// that's OK, we probably haven't created it yet
}
catch (Throwable t) {
Toast
.makeText(this, "Exception: "+t.toString(), Toast.LENGTH_LONG)
.show();
}
if(neList == null){
neList = new ArrayList<NewsEvent>();
}
}
public ArrayList<String> getKeywords(){
try {
InputStream fi = openFileInput(KEYWORDS);
if (fi!=null) {
ObjectInputStream in = new ObjectInputStream(fi);
keyWordList = (ArrayList<String>) in.readObject();
in.close();
}
}
catch (java.io.FileNotFoundException e) {
// that's OK, we probably haven't created it yet
}
catch (Throwable t) {
Toast
.makeText(this, "Exception: "+t.toString(), Toast.LENGTH_LONG)
.show();
}
if(keyWordList == null){
keyWordList = new ArrayList<String>();
return keyWordList;
}
return keyWordList;
}
/**
* This is the object that receives interactions from clients. See RemoteService
* for a more complete example.
*/
private final IBinder mBinder = new Binder() {
#Override
protected boolean onTransact(int code, Parcel data, Parcel reply,
int flags) throws RemoteException {
return super.onTransact(code, data, reply, flags);
}
};
}
Here is my activity that schedules the service to run
public class NewsEvents extends ListActivity{
private URL JSONNewsEvents;
private ArrayList<NewsEvent> neList;
private ArrayList<String> keyWordList;
private Worker worker;
private NewsEvents ne;
public static final String KEYWORDS = "keywords";
private static final String NEWSEVENTS = "newsevents";
public static final int ONE_ID = Menu.FIRST+1;
private PendingIntent newsAlarm;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.newsevents);
ne = this;
neList = new ArrayList<NewsEvent>();
try {
JSONNewsEvents = new URL(getString(R.string.jsonnewsevents));
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
worker = new Worker(handler, this);
setListAdapter(new IconicAdapter());
getKeywords();
worker.execute(JSONNewsEvents);
}
#Override
protected void onStop() {
super.onStop();
writeNewsEvents() ;
}
#Override
protected void onPause(){
super.onPause();
writeNewsEvents();
}
private void writeNewsEvents() {
try {
OutputStream fi = openFileOutput(NEWSEVENTS, 0);
if (fi!=null) {
ObjectOutputStream out = new ObjectOutputStream(fi);
out.writeObject(neList);
out.close();
}
}
catch (java.io.FileNotFoundException e) {
// that's OK, we probably haven't created it yet
}
catch (Throwable t) {
Toast
.makeText(this, "Exception: "+t.toString(), Toast.LENGTH_LONG)
.show();
}
}
/**
* #return
*/
public ArrayList<String> getKeywords(){
try {
InputStream fi = openFileInput(KEYWORDS);
if (fi!=null) {
ObjectInputStream in = new ObjectInputStream(fi);
keyWordList = (ArrayList<String>) in.readObject();
in.close();
}
}
catch (java.io.FileNotFoundException e) {
// that's OK, we probably haven't created it yet
}
catch (Throwable t) {
Toast
.makeText(this, "Exception: "+t.toString(), Toast.LENGTH_LONG)
.show();
}
if(keyWordList == null){
keyWordList = new ArrayList<String>();
return keyWordList;
}
return keyWordList;
}
public void onListItemClick(ListView parent, View v,
int position, long id) {
startFullNewsEvent(neList.get(position));
}
/**
* #param newsEvent
*/
public void startFullNewsEvent(NewsEvent ne) {
Intent intent = new Intent(this, FullNewsEvent.class);
intent.putExtra("ne", ne);
this.startActivity(intent);
finish();
}
private Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
String page = msg.getData().getString("page");
try {
JSONArray parseArray = new JSONArray(page);
for (int i = 0; i < parseArray.length(); i++) {
JSONObject jo = parseArray.getJSONObject(i);
String title = jo.getString("title");
String body =jo.getString("body");
String pd = jo.getString("postDate");
String id = jo.getString("id");
NewsEvent ne = new NewsEvent(title, pd , body, id);
boolean unique = true;
for(NewsEvent ne0 : neList){
if(ne.getId().equals(ne0.getId())){
unique = false;
}else{
unique = true;
}
}
if(unique == true){
neList.add(ne);
}
}
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
ne.setListAdapter(new IconicAdapter());
}
};
public class IconicAdapter extends ArrayAdapter<NewsEvent> {
IconicAdapter() {
super(NewsEvents.this, R.layout.rownews, neList);
}
public View getView(int position, View convertView,ViewGroup parent) {
LayoutInflater inflater=getLayoutInflater();
View row=inflater.inflate(R.layout.rownews, parent, false);
TextView label=(TextView)row.findViewById(R.id.label);
ImageView image= (ImageView)row.findViewById(R.id.icon);
String body = neList.get(position).getBody();
body.replaceAll("\\<.*?>", "");
String title = neList.get(position).getTitle();
for(String s : keyWordList){
if(body.contains(s) || body.contains(s.toLowerCase()) ||
title.contains(s) || title.contains(s.toLowerCase())){
neList.get(position).setInterested(true);
}
}
if(neList.get(position).isInterested() == true){
image.setImageResource(R.drawable.star);
}
label.setText(neList.get(position).getTitle());
return(row);
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
populateMenu(menu);
return(super.onCreateOptionsMenu(menu));
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
return(applyMenuChoice(item) || super.onOptionsItemSelected(item));
}
//Creates our activity to menus
private void populateMenu(Menu menu) {
menu.add(Menu.NONE, ONE_ID, Menu.NONE, "Home");
}
private boolean applyMenuChoice(MenuItem item) {
switch (item.getItemId()) {
case ONE_ID: startHome(); return(true);
}
return(false);
}
public void startHome() {
Intent intent = new Intent(this, ECS.class);
this.startActivity(intent);
finish();
}
}
Race conditions, I'm making an HTTP Request and then handing it off to a handler, immediately following that I iterator through the array list, which at full speed is empty because the HTTP hasn't completed. In debugging it all slows down so the HTTP is complete and all works well.
Threads and Network Connections, a deadly combination.

Categories

Resources