How do I avoid a black screen before startup? - android

I created a loadpage with a background and a progress bar and when it finishes loading, it starts the main class but the loading screen is not showing up. It is just a black screen while it loads and then the main screen. I put all the work in the onResume and I also tried onStart with no luck
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.loadpage);
//get rid of title bar
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
setRequestedOrientation(1);
}
#Override
public void onResume() {
super.onResume();
words = WordList.sharedWordList(this);
if(generatedLevels==null)
{
generatedLevels = new ArrayList<PuzzleMZLen>();
}
if(!p.isAlive())
{
p.start();
}
Intent i = new Intent(getApplicationContext(), Main.class);
startActivity(i);
}
thanks in advance

You have to use AsyncTask for this kind of work.Your layout is populated after the completion of the loading.So you are watching black screen.
Use onPreExecute of AsyncTask class to show the progress bar. And write loading code in the doInBackground method.

Definitely use AsyncTask for this. I had the same thing going for my app, and here's my code:
private class getAllData extends AsyncTask<Context, Void, Cursor> {
protected void onPreExecute () {
dialog = ProgressDialog.show(Directory.this, "",
"Loading. Please wait...", true);
}
#Override
protected Cursor doInBackground(Context... params) {
DirectoryTransaction.doDepts();
return null;
}
protected void onPostExecute(Cursor c) {
for(int i = 0 ; i < DeptResults.length ; i++){
deptsAdapter.add(DeptResults[i][0]);
}
dialog.dismiss();
}
}
onPreExecute method loads a ProgressDialog that just shows "Loading. Please wait...". doInBackground does what was making my app load (in my case grabbing and parsing text from a server) and then onPostExecute is filling a spinner then dismissing the ProgressDialog. You'll want some thing different for a progress BAR, but the AsyncTask will be very similar. Call it in onCreate with new getAllData.execute(this);

There is a good way how to create a good splash activity.
To prevent ANR you should move all data loading outside of UI thread as it was mentioned at other answers. Please use AsyncTask or any other kind of multi-threading for that.
However to remove annoying black screen which shows for few moments on some slow devices you need to do next steps:
Create bg_splash drawable. It will be shown instead of black background just in time activity shows to user. For example it can be brand logo on brand color background.
Create a splash screen theme and put it into /res/values/themes.xml:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="MyApp.Splash" parent="#style/Theme.Sherlock.Light.NoActionBar">
<item name="android:windowBackground">#drawable/bg_splash</item>
</style>
</resources>
Don't forget assign created theme to splash activity by updating AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.myapp"
android:versionCode="1"
android:versionName="1" >
...
<application>
<activity
android:name=".SplashActivity"
android:theme="#style/MyApp.Splash" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<activity>
...
</application>
</manifest>

Related

How to add real Loading Screen

I have an android application of a pdf file inside. When I open my application on lower configuration devices (galaxy 2 etc.), it takes a while to load the PDF file. I tried to adding a splash screen in my application but when opening MainActivity.class after SplashScreen still taking same time. How can I develop a real loading screen? It should work on top of Main Activity layer.
Here my codes:
AndroidManifest.xml
<activity
android:name=".SplashScreen"
android:label="#string/app_name"
android:theme="#style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".MainActivity"></activity>
</application>
</manifest>
SplashScreen.class
public class SplashScreen extends AppCompatActivity {
private GifImageView gifImageView;
private ProgressBar progressBar;
Handler handler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash_screen);
gifImageView=(GifImageView)findViewById(R.id.gifview);
progressBar=(ProgressBar)findViewById(R.id.progressbar);
progressBar.setVisibility(progressBar.VISIBLE);
try {
InputStream inputStream = getAssets().open("loading.gif");
byte[] bytes = IOUtils.toByteArray(inputStream);
gifImageView.setBytes(bytes);
gifImageView.startAnimation();
}
catch (IOException ex)
{
}
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
Intent intent = newIntent(SplashScreen.this,MainActivity.class);
SplashScreen.this.startActivity(intent);
SplashScreen.this.finish();
}
},12000);
}
}
Here my codes how I can solve this problem?
Have you considered using Async Task for this?
You can use the async task in your MainActivity.
For Example you can do something like the following:
class PDFLoader extends AsyncTask<Void, Void, Void>
{
protected void onPreExecute (){
super.onPreExecute();
// Here you can instantiate the Progressdialog to show the progress.
}
protected String doInBackground(Void...arg0) {
// here you can go ahead write the reading logic for the PDF
// if it is taking time.
}
protected void onProgressUpdate(Integer...a){
super.onProgressUpdate(a);
// you may or may not use this. This can act as a progress updated based on
// the integer.
}
protected void onPostExecute(String result) {
super.onPostExecute(result);
// Here you can dismiss the progress bar since the read as been done.
}
}
Call it like this in your MainActivity:
new PDFLoader().execute();
I hope this helps you.
This is just the basic structure to get you started. More information here.
Using a Splash screen is not a solution to this.You are adding a screen with 12second gap and after 12 second the MainActivity class is getting execute.
So, you can directly add a progress bar in MainActivity class and you can use AsyncTask to solve this problem.
AsyncTask has 3 methods-
OnPreExecute, doInBackground, OnPostExecute. Here, you can add a progress bar in OnPreExecute method and the code for opening PDF file in doInBackground method, and finally stop the progress bar in OnPostExecute method.
For more help you should provide your MainActivity class code here.
You should give a shot to this article: https://antonioleiva.com/branded-launch-screen/
It's far better than Splash Screen, 'cause It loads async to your MainActivity
Add this code to styles:
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar" />
<style name="AppTheme.BrandedLaunch" parent="AppTheme">
<item name="android:windowBackground">#drawable/branded_logo</item>
</style>
Now create branded_logo.xml into your drawable directory
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<color android:color="#color/background_material_light"/>
</item>
<item>
<bitmap
android:src="#drawable/launch_logo_image"
android:tileMode="disabled"
android:gravity="center"/>
</item>
</layer-list>
And assign that style into your MainActivity
<activity
android:name=".MainActivity"
android:label="#string/app_name"
android:theme="#style/AppTheme.BrandedLaunch">
And finally add setStyle to your default theme in your onCreate in MainActivity
#Override
protected void onCreate(Bundle savedInstanceState) {
setTheme(R.style.AppTheme);
super.onCreate(savedInstanceState);
...
You can create a LoadingScreen instead of splash screen(looking at your 12 secs. delay). Here is something that might help:
public class LoadingScreen {private ImageView loading;
LoadingScreen(ImageView loading) {
this.loading = loading;
}
public void setLoadScreen(){
final Integer[] loadingImages = {R.mipmap.loading_1, R.mipmap.loading_2,
R.mipmap.loading_3, R.mipmap.loading_4};
final Handler loadingHandler = new Handler();
Runnable runnable = new Runnable() {
int loadingImgIndex = 0;
public void run() {
loading.setImageResource(loadingImages[loadingImgIndex]);
loadingImgIndex++;
if (loadingImgIndex >= loadingImages.length)
loadingImgIndex = 0;
loadingHandler.postDelayed(this, 500);//change to accordingly(i.e. 12000)
}
};
loadingHandler.postDelayed(runnable, 500); // change it accordingly
}}
In your MainActivity, you can pass a to the LoadingScreen class like this :-
private ImageView loadingImage;
Don't forget to add an ImageView in activity_main. After that call the LoadingScreen class like this;
LoadingScreen loadingscreen = new LoadingScreen(loadingImage);
loadingscreen.setLoadScreen();
It is always helpful in creating a custom loading screen instead of Splash screen.Also don't forget to add some different images to make that feel like a gif and after that add the images in the res folder . I have checked it for lower versions too Therefore, believe that it might serve your purpose...
Nowadays lots of applications are avoiding loading screen due to bad UI/UX. You can use alternative for content loading. This article may help more about. You can look this kind of implementation on lot of popular apps like Facebook, LinkedIn, Upwork etc.

How to display Splash Screen in android

I want to display splash screen in android app. But I want to execute onCreate() method of MainActivity behind the splash screen. because i am doing huge work in this method. Anyone can tel me how to do that.
Basically you want to do some work in background while user is shown some splash screen, right ? What you need is an Async Task or a Loader kind of thing.
Step 1: Display the splash screen.
Step 2: Start an Async task and do all your heavy processing in the doInBackground method of Async Task
Step 3: Update the UI using the onPostExecute method of Async Task. In this method, first close the timer to splash screen. Then send the intent to start another screen with the data of the heavy processed result of Async task. Display it on UI thread.
Only Showing Splash screen is very simple. This code creates a splash screen of 3 seconds and then sends an Intent to another activity.
public class SplashScreenActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash_screen);
CountDownTimer cdt1 = new CountDownTimer(3000, 1000) {
Boolean checkInternetConnection = false;
#Override
public void onTick(long l) {
}
#Override
public void onFinish() {
//Send Intent here
Intent i = new Intent(getApplicationContext(),
anotherActivity.class);
startActivity(i);
}
}.start();
}
PS- Dont forget to make the activity with this code as launcher activity from manifest file.
You can try this for Splash Screen...
public class SplashScreen extends Activity {
//Further Needed Declarations
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_splash);
/**
* Showing splashscreen while making network calls to download necessary
* data before launching the app Will use AsyncTask to make http call
*/
new PrefetchData().execute();
}
}
This is exactly the same way you wanted it.
create file in drawable
<item
android:drawable="#color/gray"/>
<item>
<bitmap
android:gravity="center"
android:src="#mipmap/ic_launcher"/>
</item>
</layer-list>
Styles.xml
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
</style>
<style name="SplashTheme" parent="Theme.AppCompat.NoActionBar">
<item name="android:windowBackground">#drawable/background_splash</item>
</style>
</resources>
Activity:
public class SplashActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
finish();
}
}
You can add this in your onCreate Method
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
// going to next activity
Intent i=new Intent(SplashScreenActivity.this,MainActivity.class);
startActivity(i);
finish();
}
},time);
And initialize your time value in milliseconds as yo want...
private static int time=5000;
for more detail download full code from this link...
https://github.com/Mr-Perfectt/Splash-Screen

Android app without a layout

I'm a totally noob on Android, is there a way to execute an app without a layout? The process would be like: Click app icon -> run some code (Without prompting any window) -> display toast.
The trick is to open a transparent activity, show the toast and finish the activity, which makes it look like only the toast is displayed because the activity which opened was transparent.
To do this you can do.
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Toast.makeText(this, messageToBeDisplayed, Toast.LENGTH_SHORT).show();
// finish the activity as soon as it opened.
this.finish();
}
}
Also you need to give a transparent theme to your activity by specifying it in AndroidManifest.xml, For which you can use NoDisplayeTheme provided by Android like this.
<activity android:name="TransparentActivity"
android:theme="#android:style/Theme.NoDisplay">
</activity>
Yes you can by adding:
android:theme="#android:style/Theme.NoDisplay"
in your activity in Android manifest.
Check this answer for more details.
Use this:
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Toast.makeText(this, "", Toast.LENGTH_SHORT).show();
this.finish();
}
}
and in manifest file add: android:theme="#android:style/Theme.NoDisplay"

Why won't dismissDialog, removeDialog, or dialog.dismiss work in onDestroy or onPause?

I can't for the life of me figure out how to manage dialogs without using configChanges to specify that you want to manually handle orientation changes.
So lets say you have this AndroidManifest:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.testandroid"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="15" />
<application
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<activity
android:name=".MainActivity"
android:label="#string/title_activity_main" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Take this MainActivity.java:
package com.example.testandroid;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.AlertDialog.Builder;
import android.app.Dialog;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.View;
public class MainActivity extends Activity {
private final static String TAG = "MainActivity";
Dialog mDialog = null;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "onCreate");
setContentView(R.layout.activity_main);
}
public void doShowDialog(View b) {
Log.d(TAG, "doShowDialog");
showDialog(1);
}
private void tryDismiss() {
Log.d(TAG, "tryDismiss");
try {
dismissDialog(1);
removeDialog(1);
mDialog.dismiss();
} catch(IllegalArgumentException ex) {
Log.e(TAG, ex.getMessage());
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}
#Override
protected void onPause() {
tryDismiss();
super.onPause();
Log.d(TAG, "onPause");
}
#Override
protected Dialog onCreateDialog(int dialog) {
Builder b = new AlertDialog.Builder(this);
b.setTitle("Hello").setMessage("Waiting..");
mDialog = b.create();
return mDialog;
}
}
and this layout (main.xml)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Open Dialog"
android:onClick="doShowDialog"
/>
</LinearLayout>
It doesn't seem to matter if you call from onDestroy or onPause, the dialog shows back up after the orientation switches. But why? I told it to go away. If call removeDialog/dismissDialog it does nothing when called before the orientation changes. I can't figure out for the life of me why this is. The only way to get rid of this that I know of is to handle the orientation change yourself by using
android:configChanges="keyboardHidden|orientation"
I know the new way of working is to use the FragmentDialog stuff which I have not upgraded to yet and am not ready to rewrite my whole app for that. Just seems strange that this doesn't work.
This is just an example of a real world problem I'm having in my app where the user can request some data be pulled from a remote server (to update a spinner's data), and if they switch orientation the loading dialog will never go away and there seems to be no fix for this besides handling the orientation change with the android:configChanges option. Which I can do but it seems ridiculous to me to have to do that.
-- Update --
Removed the button to dismiss the dialog as it's not necessary and you can't click it anyways since the dialog is on top.
To reproduce just start the app, click the button that opens the dialog, and then rotate your phone.
Your dialog is saved in onSaveInstanceState, so you might try dismissing it before it's launched:
#Override
protected void onSaveInstanceState(Bundle state)
{
tryDismiss();
super.onSaveInstanceState(state);
}
Also I don't really understand why do you use Activity's onCreateDialog to manage dialogs. The reason it was designed was to handle orientation changes automatically. If you want to handle it manually, why don't you just use dialog's functions? Instead of using showDialog(id) and onCreateDialog(id) just launch it directly, it won't reappear after rotating the screen.
Builder b = new AlertDialog.Builder(this);
b.setTitle("Hello").setMessage("Waiting..");
Dialog mDialog = b.create();
mDialog.show(); // <-----
Sebastian got it but I'd like to explain a bit more about the situation and my findings on dialogs since it can be quite confusing:
As sebastian put it, you must call dismissDialog/removeDialog from
onSaveInstanceState if you want the dialog gone before the rotation.
While you can create a dialog from onCreate, if you don't dismiss it before the orientation
change you won't be able to dismiss in the onCreate method when the activity restarts. You must call dismissDialog from onPostCreate
Calling dismissDialog didn't work in onRestoreInstanceState after orientation change as well. I tried both before and after calling super.onRestoreInstanceState and neither worked (thought it would since dimissing happens in onSaveInstanceState)
Even more important than this is that I learned if you are doing some Asynchronous task, such as an HTTP call and you have an inner class which contains a callback function which will run when the task is complete, you need to be aware that that inner class method will contain a reference to the original instance of the outer Activity class if the screen is rotated. This was not at all obvious to me as and I wasn't actually using AsyncTask as many others have had issues with (I was using an asynchronous http library).
Taking a small example similar to my real code:
public class MyActivity extends Activity {
private static MyActivity sThis;
#Override
public void onCreate(Bundle state) {
super.onCreate(state);
sThis = this;
doAsyncWork();
}
#Override
public void onDestroy() {
super.onDestroy();
sThis = null;
}
private void doAsyncWork() {
showDialog(LOADING_DIALOG);
ExampleAsyncWorker.work(new AsyncWorkerCallback() {
#Override
public void onWorkComplete() {
dismissDialog(LOADING_DIALOG); //doesn't work if orientation change happened.
}
});
}
}
The above code, through the CategoryManager, connects to an external server, downloads a list of categories, and once it is complete calls onCategoriesObtained and then onFetchComplete (also there are some error handling callback function removed for brevity). If an orientation change happens between the fetchCategories call and onFetchComplete then the call to dismissDialog in onFetchComplete will never work. The reason is that this inner class has an implicit reference to the original instance of the Activity class which was created before the orientation change. Thus, when you call dismissDialog you are calling it on the original instance not the new one, which will cause the dismissDialog to fail with the message: "no dialog with id 1 was ever shown via Activity#showDialog". I did figure out a way around this but its a bit of hack:
In your Activity class, include a static reference to the this reference and set it in onCreate, and null it in onDestroy, and use that reference from your inner class like so:
public class MyActivity extends Activity {
private static MyActivity sThis;
#Override
public void onCreate(Bundle state) {
super.onCreate(state);
sThis = this;
doAsyncWork();
}
#Override
public void onDestroy() {
super.onDestroy();
sThis = null;
}
private void doAsyncWork() {
showDialog(LOADING_DIALOG);
ExampleAsyncWorker.work(new AsyncWorkerCallback() {
#Override
public void onWorkComplete() {
sThis.dismissDialog(LOADING_DIALOG);
}
});
}
}
Note that I'm not sure this is a great practice but it worked for me. I know there can be problems with inner classes in activities that refer to the outer class (leaking the context) so there may be better ways of solving this problem.
AFAIK , This window leaked can be handled in two ways.
#Override
public void onDestroy(){
super.onDestroy();
if ( Dialog!=null && Dialog.isShowing() ){
Dialog.dismiss();
}
}
Or
if(getActivity()!= null && !getActivity().isFinishing()){
Dialog.show();
}
Here Dailog is your progress /alert dailog
for creating your app without the savedinstace you can use super.onCreate(null);

Android: dynamically choosing a launch activity doesn't always work

I've read a few articles here (and other places) that describe how to dynamically choose which activity to show when launching an app. Below is my code:
AndroidManifest.xml
<activity android:name=".StartupActivity"
android:theme="#android:style/Theme.NoDisplay">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
StartupActivity.java
public class StartupActivity extends Activity
{
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
Intent intent;
if (RandomClass.getSomeStaticBoolean())
{
intent = new Intent(this, ActivityOften.class);
}
else
{
intent = new Intent(this, ActivityRare.class);
}
startActivity(intent);
finish();
}
}
Both ActivityOften and ActivityRare are declared in the manifest (without the launcher category of course) and extend ListActivity and Activity respectively. 99% of the time the 1st activity to get shown is ActivityOften based on RandomClass.getSomeStaticBoolean().
So launching my app from the icon for the 1st time I break inside the StartupActivity.onCreate. The choice is properly made. But then any subsequent attempts to launch the app (from a shortcut or the apps menu) show the ActivityOften again. No further breaks occur inside the StartupActivity class. Despite the fact that I know that RandomClass.getSomeStaticBoolean() has changed value and that ActivityRare should appear, the 1st activity keeps popping up.
Any ideas?
Thanks, Merci, Gracias, Danke, Grazie!
Sean
It is happening because your application activity is loaded from the history stack.
Set android:noHistory=true in the manifest for both ActivityOften and ActivityRare. That should solve your problem.
Just as a suggestion, you could just have one activity instead of three by choosing the content View dynamically. i.e.
#Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
if (RandomClass.getSomeStaticBoolean())
{
setContentView(R.layout.Often);
// Set up often ....
}
else
{
setContentView(R.layout.Rare);
// Set up rare ....
}
}
This would mean that you would have to write setup code both views in on activity, which can get a bit messy.

Categories

Resources