Android code does not seem to run synchronously - android

I would like to know why my Android code is not running Synchronously.
I am overriding Cordova's Mainactivity class's onCreate to execute custom code when the app starts.
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 1. Show loading dialog
Display display = getWindowManager().getDefaultDisplay();
Dialog loadingDialog = Loading.createLoadingDialog(this, display, getLoadingHTMLPath());
loadingDialog.show();
loadUrl(launchUrl);
// 2. Copy bunch of files (this takes some time)
copyFiles();
}
I am expecting the app to show the loading dialog first, and then copy the files. However, I see a black screen on the app launch. Then the app copies all the files. It is only after that the app displays the loading dialog.
Why is second part of the code running first? Any suggestions on how to get the dialog to display first?
Edit
This was my initial solution that worked.
Thread onAppStartTask = new Thread(new Runnable() {
public void run() {
copyFiles();
}
});
onAppStartTask.start();

Well, the thing is, you are running the code synchronously. That's the problem. Android has exactly one thread for displaying and modifying the UI, so the call to copyFiles() will prevent any further action in the UI until it finishes.
The show() call doesn't occur instantaneously - onStart() and onResume() need to be called first - and the screen turns black because it's not able to draw anything while your app is stuck in onCreate(). The highly recommended solution is putting the file-loading logic in a background thread and periodically updating the ui with its progress.
Try this for starters and see if it works.
cordovaInterface.getThreadPool().execute(new Runnable() {
#Override
public void run() {
copyFiles();
}
}

Related

How do I implement multi thread on an Android Activity?

I've created a nested class within my Activity
public class MissionsActivity extends Activity {
class UpdateMissions implements Runnable {
#Override
public void run() {
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_BACKGROUND);
[...]
}
[...]
}
In the thread I have to read a file and update some TextFields in the layout. I've tried implementing the run() method with a while(true) that reads and updates the fields, but the app just crashes when I start that Activity.
UPDATE: I've called the execute() method inside the onCreate() method of the UI Activity. The Task is only working the first time I enter the Activity, if i change and go back it won't do anything.
Hey a solution could be trying to use Java's Executor Framework. Put the following code in your Activity.
With executors, you can use a cachedThreadPool() singleThreadExecutor() fixedThreadPoolExecutor(int numOfThreads) etc.
Executors.newSingleThreadExecutor().submit(new Runnable() {
#Override
public void run() {
//Your task here.
}
});
Please note there are numerous Threading Models and techniques in Android, some Android Specific, some based in Android.
AsyncTask
HandlerThread
You can use an AsyncTask. It allows you to load the file and show the progress on ui thread until the load it's finished.
Here you have a good example Download a file with Android, and showing the progress in a ProgressDialog
I would recommend using RxJava or Live Data if you are more advance in developing but also the first solution is fine enough for beginning
https://developer.android.com/topic/libraries/architecture/livedata.html

Android, run code only after the UI has been rendered for an activity

I know this question is on here many times, but the answer that works in all of those cases does not work for mine. When the activity starts I am taking a screenshot of the screen. I execute my code at the bottom of the onCreate. It works great 4 our of 5 times and the 5th time the screen has not rendered yet and you get a black screenshot.
My workaround is to execute the screenshot code in an AsyncTask that is started at the end of onCreate. If I put a 200ms sleep the it works 9 out of 10 times. A 500ms sleep gets it 100% of the time but you can notice the delay. This also seems like a terrible solution because that 500ms is an arbitrary number that may not work across all devices.
How can I know when the UI is rendered, so I can take my screenshot?
You could just grab the top decor view using Window.getDecorView() and then use post(Runnable) on it. Using the decor view results in reusable code that can be run in any application as it does not depend on some specific View element being a part of the inflated layout.
The call will result in your Runnable being placed in the message queue to be run on the UI thread, so do not run long operations in the Runnable to avoid blocking the UI thread.
Simple implementation - Kotlin
// #Override protected void onCreate(Bundle savedInstanceState) {
window.decorView.post {
// TODO your magic code to be run
}
Simple implementation - Java
// #Override protected void onCreate(Bundle savedInstanceState) {
getWindow().getDecorView().post(new Runnable() {
#Override
public void run() {
// TODO your magic code to be run
}
});

What does "setContentView" really do?

In my main activity, I would like to have it set up, so that I first get met by a contentView just showing a background and some text. After X seconds, I want to change to my other view (GLSurfaceView).
This is obviously something I am doing completely wrong.
This is how I've imagined it could've been done (it's all in the onCreate method):
setContentView(R.layout.main);
try {
Thread.sleep(10000);
} catch (InterruptedException e) {
}
viewer = new Viewer(this);
setContentView(viewer);
Where layout Main is what I want to show at the beginning and Viewer is my GLSurfaceView class.
What happens is that it just goes black for 10 seconds and then it starts loading the objects I've got that is shown through OpenGLES.
There's nothing wrong with the layout Main, since it works if I just erase the lines under where the Thread.sleep takes action. Though, nothing happens before the Thread.sleep is over...
With that said, my questions are following:
Why is the contentView not changing until after Thread.sleep is done?
What would be an appropiate solution to what I want to achieve?
I'm assuming this in your onCreate() and thats why you are seeing nothing.
The way I would implement this is to start a thread using AsyncTask sleep in the doInBackground and in the onPostExecute set up the new view.
Don't make sleep the main thread(UI thread).Use a threads,AsynkTask or TimerTask for that type of works instead.
You're not sleeping the UI thread in the way you think you are.
The simplest thing for what you're looking to achieve is to separate the views into separate activities and let Android handle the transition between the views. It adds another file to your codebase, but it's fairly straightforward. Let's say your initial, plain view (R.layout.main) is for a SplashActivity activity, and your post-splash view goes into PostSplashActivity. Then you could do something like this:
public class SplashActivity extends Activity {
private static long DELAY = 10000; //milliseconds;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
new Handler().postDelayed(
new Runnable() {
#Override
public void run() {
Intent postSplash = new Intent(SplashActivity.this, PostSplashActivity.class);
SplashActivity.this.startActivity(postSplash);
SplashActivity.this.finish();
}
}, DELAY);
}
}
This will draw your R.layout.main layout, and then puts a startActivity call for your PostSplashActivity on the message queue and tells the queue to wait DELAY milliseconds to execute it.
It seems like you are making the main thread sleep. This may be why the code is running tell after.
It sounds like you want something like a splash screen. I like to think of these as separate to the following screen, so always use a separate activity rather than calling setContentView twice. You'd still need to sleep in a thread.
Just personal preference though...

Intentionally force android to wait AND load something in background

I want to force android to wait AND continue processing something at the same time. I have seen the Thread wait function, but that just makes things hang for a while not actually letting the app do anything. Subsequent processes are simply queued up waiting their turn.
I want to force the timing of a process. This is kind of a combination between having a thread with a wait AND an asynctask
insight appreciated
public class yourActivity extends Activity{
final WebView yourWebview; //this is the webview
Context mContext = this;
public void onCreate(Bundle B){
setContentView(R.id.somethingtoshow);//this will be shown while webview working
Runnable yourRun = new Runnable(){
public void run(){
yourWebview = new WebView(mContext);
//do whatever you want with it
//loadUrl and whatever you want
//when your done
runOnUiThread(new Runnable(){
public void run(){
setContentView(yourWebView);
}
});
}
};
Thread T= new Thread(yourRun);
T.start();
}
}
'Waiting' means to put the thread in a suspended state - do you mean having the app simply do nothing until the process is completed?
You never want to make the main event thread hang or wait, that will make the user think the app is frozen. To do what you are wanting, you will probably spawn an async thread that loads the page from the main activity. The activity will continue to display whatever you had it doing last, and will not hang up or freeze while the async is going in the background. However, the user will still be able to press buttons, and might mess you up.
So to get the app to appear unfrozen and allow a process to occur in the background, you will want to enter into some loading screen or limit the user's options on the main layout. This will allow activity to continue occurring but allow the user a smooth experience.

Android - Starting a thread crashes app

I've got a few activities. In the main activity I have a login screen, when the user presses the login button, a thread is started to show a progress dialog until the user has been authenticated. At this point i load the next activity which has several fields for the user to input data.
Here the user inputs some data and presses a button to process it. The data is passed to a new activity where the data is actually processed and displayed. This is where i create the new thread and where it's crashing when i call thread.start(); and I have no idea why this is happening.
Both activities are implementing Runnable.
I'm using the same code below to create and call thread.start() in the button press of the first activity and the onCreate method of the last one:
pd = ProgressDialog.show(search_results.this, "", "Searching...", true, false);
Thread thread = new Thread(this);
thread.start();
I'm using the same code below as well to handle the threads for both as well.
public void run() {
handler.sendEmptyMessage(0);
}
private Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
pd.dismiss();
}
};
Am I missing something? I don't really understand why it's crashing.
While I encourage people to use AsyncTask, it's not really needed, especially for simple things like progress/loading dialogs. That's not the problem here.
Your question and your code is confusing. I'm not sure which code goes where, on which activity, and I hope you're not leaving dialogs open between activities, trying to access them across them (it won't work, of course). Also, providing a Context to a Thread does not even compile (it's marked with errors at design time). To sum it all up, you didn't provide the Log entry. Sorry, I can't make sense of what you're doing or where the error is. We can only guess.
Below are one of the possible ways to do it with a Handler, a Runnable and a Thread. This was taken from the Developer Resource when I first learn how to use it:
1- You declare a Handler. Most people do this on the onCreate section to reuse it often:
Handler mHandler = new Handler();
2- When you need, you start a Thread:
new Thread() { public void run() {
mHandler.post(mLoadingData);
// ... do work
mHandler.post(mLoadingDataStop);
}}.start()
3- These are the Runnables that are posted to the Handler:
private final Runnable mLoadingData = new Runnable() {public void run() {
showDialog(LOADING_DIALOG); // In your case, show your custom dialog
}};
private final Runnable mLoadingDataStop = new Runnable() {public void run() {
dismissDialog(LOADING_DIALOG); // In your case, dismiss the dialog
}};
For a progress dialog, things need a bit more work (update the progress etc.), but for a loading dialog, you don't need to really mess with messages.
I had this same issue when developing for the tablet. After a certain API, I'm thinking 3.0 (sdk 11), Android enforces applications to run long running processes on a separate thread, otherwise it kills it. Logcat will confirm this.
I know you are using another thread, but that didn't work for me either. Try using AsyncTask. You can create a quick inner class that, in my opinion, is way easier than handling your own threads. AsyncTask has several functions that run on the UI thread and a couple that run on their own thread. This allows you to start a "Loading" user interface object on the user interface thread, process on the back end thread, and then when its done, it'll notify a user interface thread function.
You'll want to specifically look at override
onPreExecute()
doInBackground()
onPostExecute()

Categories

Resources