I call a method(below deleteCache method) in OnCreate() in a class which extend Application class. This method is for deleting files. It uses Thread because I want this method won't affect UI flow.
public static void deleteCache(final Context context) {
new Thread(new Runnable() {
#Override
public void run() {
try {
File dir = context.getCacheDir();
deleteDir(dir);
} catch (Exception e) {}
}
}).start();
}
But with this, the OnCreate() method in App class(extend Application) is called very slowly. So when I launch the app, it takes about 5 seconds to show a first Activity.
I don't know why this happen.
Please give me a any hint of this problem.
As #Umer said, use AsyncTask if you run the in the UI-Thread. For Reference:
https://developer.android.com/reference/android/os/AsyncTask.html
Otherwise, if that won`t solve your problem, maybe your function is too complex or the data that will be deleted are very large.
Related
I want perform a network call in every 30sec to push some metrics to Server. Currently I am doing it using thread.sleep(). I found some articles saying thread.sleep() has some drawbacks. I need to know am I doing it right? or Replacing the thread with Handler will improve my code?
public static void startSending(final Context con) {
if (running) return;
running = true;
threadToSendUXMetrics = new Thread(new Runnable() {
#Override
public void run() {
do {
try {
Thread.sleep(AugmedixConstants.glassLogsPushInterval);
} catch (InterruptedException e) {
mLogger.error(interrupt_exception + e.getMessage());
}
// to do to send each time, should have some sleep code
if (AugmedixConstants.WEBAPP_URL.equals(AugmedixConstants.EMPTY_STRING)||!StatsNetworkChecker.checkIsConnected(con)) {
Utility.populateNetworkStat();
mLogger.error(may_be_provider_not_login_yet);
} else
sendUXMetrics();
} while (running);
if (!uxMetricsQueue.isEmpty()) sendUXMetrics();
}
});
threadToSendUXMetrics.start();
}
If You are using only one thread in the network, then usage of the thread.sleep() is fine. If there are multiple threads in synchronization, then the thread.sleep() command will block all the other threads that are currently running.
As per the details you've provided, there is only one thread present which isn't blocking any other active threads which are running in synchronization, so using thread.sleep() shouldn't be a problem.
Use Handler.postDelayed to schedule tasks if you are working in UI Thread and Thread.sleep if you are working in background thread.
Apparently you are sending some data using network, you must do it in the background thread, hence Thread.sleep is recommended.
Simple is:
Thread.sleep(millisSeconds): With this method, you only can call in background tasks, for example in AsyncTask::doInBackground(), you can call to delay actions after that. RECOMMENDED CALL THIS METHOD IN BACKGROUND THREAD.
Handler().postDelayed({METHOD}, millisSeconds): With this instance, METHOD will trigged after millisSeconds declared.
But, to easy handle life cycle of Handler(), you need to declare a Handler() instance, with a Runnable instance. For example, when your Activity has paused or you just no need call that method again, you can remove callback from Handler(). Below is example:
public class MainActivity extends Activity {
private Handler mHandler = Handler();
public void onStart(...) {
super.onStart(...)
this.mHandler.postDelayed(this.foo, 1000)
}
public void onPaused(...) {
this.mHandler.removeCallback(this.foo)
super.onPaused(...)
}
private Runnable foo = new Runnable() {
#Override
public void run() {
// your code will call after 1 second when activity start
// end remove callback when activity paused
// continue call...
mHandler.postDelayed(foo, 1000)
}
}
}
The code above just for reference, I type by hand because don't have IDE to write then copy paste.
I have two simple classes:
public class MainActivity extends Activity {
NetworkTask task;
#Override
protected void onCreate(Bundle savedInstanceState) {
[...]
task = new NetworkTask();
task.execute();
}
public void myClickHandler(View view) {
switch(view.getId()) {
case R.id.button1:
// Why this line crash?
task.connection("127.0.0.1");
break;
}
}
}
and
public class NetworkTask extends AsyncTask<String, Void, String> {
Socket sock;
volatile boolean running = true;
public int connection(String url){
try{
sock = new Socket(url, 4567)
}
catch (IOException ex){
Logger.getLogger(NetworkTask.class.getName()).log(Level.SEVERE, null, ex);
return -1;
}
}
public String doInBackground(String... strings) {
// If I do this, it works well
//connection(127.0.0.1);
while(running)
{
[...]
}
return null;
}
}
As I commented when I call connection method from outside of the AsyncTask method, the app crashes more particulary « sock = new Socket(...) » line. But when connection call is done inside the AsynTask method socket is created.
I don't understand why.
What's happening?
Thanks.
It's because when you do
task.connection("127.0.0.1");
You are still working in the main (UI) Thread - you're not using the AsyncTask properly. Instead you're using it like a normal class, and so, you get a NetworkOnMainThreadException on the new Android versions.
However when you call from doInBackground(), it means you started the AsyncTask via execute and the work is done in a separate Thread, letting everything work as it should.
Keep in mind that if you are doing non-network stuff, you can still call from outside. However, I'd recommend keeping your AsyncTask depend on the outside as little as possible, since AsyncTasks only run once. You then have to make a new instance if you want to do more work, which means if you depend on setter methods or similar, you have to make sure you call those methods again, which makes this simple class more complex than needed.
For a good, to the point explanation of how to use an AsyncTask, this is a pretty good source. And of course the official documentation.
I am a relatively new Android programmer and I was wondering how you could get read text off the internet in 4.0.3. I keep finding code that gives me a Network on Main exception: http://developer.android.com/reference/android/os/NetworkOnMainThreadException.html and was wondering if anyone could provide me some sample code to get around this, for reference I got the code I tried to use here: http://android-er.blogspot.com/2011/04/read-text-file-from-internet-using-java.html. Thanks a lot.
In Honeycomb and Ice Cream Sandwich (i.e. Android 3.0+) , you cannot connect to the internet in the main thread (onCreate(), onPause(), onResume() etc.), and you have to instead start a new thread. The reason why this has changed is because network operations can make the app wait for a long time, and if you're running them in the main thread, the whole application becomes unresponsive. If you try to connect from the main thread, Android will throw a NetworkOnMainThreadException.
To bypass this, you can run networking code from a new thread, and use runOnUiThread() to do things in the main thread, such as update the user interface. Generally, you can do something like:
class MyActivity extends Activity {
public onCreate(Bundle savedInstanceState) {
super.onCreate();
// Create thread
Thread networkThread = new Thread() {
#Override
public void run() {
try {
// this is where your networking code goes
// I'm declaring the variable final to be accessible from runOnUiThread
final String result = someFunctionThatUsesNetwork();
runOnUiThread(new Runnable() {
#Override
public void run() {
// this is where you can update your interface with your results
TextView myLabel = (TextView) findViewById(R.id.myLabel);
myLabel.setText(result);
}
}
} catch (IOException e) {
Log.e("App", "IOException thrown", e);
}
}
}
}
}
You need to complete an HTTP Request. There are a lot of examples available on line. Try here for starts.
Note : I know there are many questions related to this, but still I am not convince, so asking.
I am getting cant create handler inside thread that has not called looper.prepare when I try to show the dialog.
Here is my code...
//this method is called from a different method based on some condition which is inturn called on click a button
private void download() {
thread = new Thread() {
public void run() {
/**** Downloads each tour's Tour.plist file ****/
try {
// do many heavy operations here, like download,
//calling web webvice and starting another activity
This comes at the end
Intent toAudio = new Intent(TourDescription.this,Audio.class);
startActivity(toAudio);
} catch (Exception e) {
}
}
};
thread.start();
}
Now before this actity gets called I am trying to show a dialog. I am trying to place that just before calling Intent.
Can any body please tell me how to do this, as I am not understanding how to solve this
you cannot show a dialog from a child thread.
A dialog can only be showed from within the UI thread/main Thread.
try this from inside the child thread
runOnUiThread(new Runnable() {
#Override
public void run() {
// TODO show dialog....
}
});
The documentation at http://developer.android.com/reference/android/database/sqlite/SQLiteOpenHelper.html#getWritableDatabase%28%29 states:
Database upgrade may take a long time,
you should not call this method
[getWritableDatabase] from the
application main thread, including
from ContentProvider.onCreate().
This begs the question: for best practice, where should getWritableDatabase be called from?
My feeling is that, perhaps, it should be called once upon application launch with a callback to mark the database as ready. Is this correct?
For small and agile databases I imagine this isn't much of an issue.
Otherwise, I'd use an always-wonderful AsyncTask, called from onCreate.
It can be called from anywhere, but it should not be called from the UI thread because you don't know how long the process will take (especially with the different file systems in use). Even if you know the database should be small, you don't know about the file system (can it perform more than one job at a time? are there are thousand other jobs waiting in line already?). You can use an AsyncTask or a Thread to call getWriteableDatabase.
It seems that the intended use of the open helper framework, is to open the db on activity start, and close it when the Activity is destroyed.
In an AsyncTask from within onCreate()...
new StartupTask().execute();
The AsyncTask Thread.sleep() below is just to give enough time to show the dialog so that you can see it work. Obviously take that out when you're done playing. ;)
private class StartupTask extends AsyncTask
{
private ProgressDialog progressDialog;
#Override
protected Object doInBackground(final Object... objects)
{
openHelperRef.getWritableDatabase();
try
{
Thread.sleep(5000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
return null;
}
#Override
protected void onPreExecute()
{
super.onPreExecute();
runOnUiThread(new Runnable()
{
public void run()
{
progressDialog = ProgressDialog.show(
MyActivity.this, "Title",
"Opening/Upgrading the database, please wait", true);
}
});
}
#Override
protected void onPostExecute(Object object)
{
super.onPostExecute(object);
progressDialog.dismiss();
}
}
in onDestroy()...
openHelper.close();