I am building an Android application that opens different activities on start depending on firebase value. Right now I have an activity with just my logo that determines which activity to go to in its onCreate method. The problem is that I still get a white screen for half a second when launching my app because of the cold start. Is there a way to create a launch screen with my logo that will open a corresponding activity depending on returned firebase value and will replace the default white screen? Kinda like what WhatsApp or Instagram are doing these days. I know I can change window background in the styles.xml, but that's not ideal as it changes background everywhere and there will still be no way to determine which activity to open right on start
You need not change the background of all the windows. In order to show the splash screen instantaneously, consider using a custom theme just for the splash screen activity. Something like this:
Styles.xml
<style name="SplashTheme" parent="AppTheme">
<item name="android:windowBackground">#drawable/splash_drawable</item>
</style>
Splash Activity Screen layout
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/splashLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:screenOrientation="portrait"
android:theme="#style/SplashTheme">
<ProgressBar
android:id="#+id/splash_activity_progress"
style="#style/Widget.AppCompat.ProgressBar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_horizontal"
android:indeterminate="true"/>
</FrameLayout>
This will give you a Splash screen with a drawable(app logo). The progress bar let the user know that there are some background operations in progress.
To query the firebase you should use AsyncTask/Coroutine/Executor so that the operation is performed in background thread & the UI thread is not blocked. This is important to avoid ANRs.
Considering the fact that there is a possibility of AsyncTask getting deprecated, I suggest you consider wither Kotlin coroutines/Java executors framework instead of AsyncTasks.
Build a Splash screen that contains your logo.
It is very important to make firebase server (or any server) calls in the background.
Recommend you use AsyncTask with CallBack.
Base example:
The call back class:
public interface CallBack_TaskCompleted {
void taskIsCompleted(boolean success);
}
AsyncTask:
private static class DownloadDataAsync extends AsyncTask<String, Integer, String> {
CallBack_TaskCompleted callBack_taskCompleted;
String someData = "";
public DownloadDataAsync(String someData, CallBack_TaskCompleted callBack_taskCompleted) {
this.callBack_taskCompleted = callBack_taskCompleted;
this.someData = someData;
}
#Override
protected String doInBackground(String... params) {
// Some download staff
if (callBack_taskCompleted != null)
callBack_taskCompleted.taskIsCompleted();
return "Executed";
}
#Override
protected void onPostExecute(String result) {
MyUtils.logd("TAG", "onPostExecute");
}
#Override
protected void onPreExecute() {
MyUtils.logd("TAG", "onPreExecute");
}
#Override
protected void onProgressUpdate(Integer... values) {
MyUtils.logd("TAG", "onProgressUpdate" + values[0]);
}
}
In your activity:
DownloadDataAsync downloadDataAsync = new DownloadDataAsync("DATA", new CallBack_TaskCompleted() {
#Override
public void taskIsCompleted() {
// go to another activity
}
});
Related
The first activity of my android app, the "launcher activity", finishes pretty quickly. It's goal is to redirect to the MainActivity or to the UserLoginActivity, depending on the value of a shared-preferences variable.
If this variable does not exist, it automatically perform a StartActivity to the MainActivity.
If this variable is set, then it will perform an HTTP request to my API, in order to Authenticate the user. Then it will start the MainActivity. The HTTP request usually takes less than one second.
The thing is that I would like to display a progress bar, in the center of the LauncherActivity, so the user can understand that something is loading.
The problem is that nothing is displayed on the screen. But if I comment the line that starts the activity, then it will be displayed... It seems that the activity duration is too fast to display anything !
I thought calling the setContentView() method will instantly load Views on the screen. Is my case a normal behavior ? How could I display a progress bar on the screen, knowing that the activity will last around one second ?
Here you can see my Launcher Activity
public class Launcher extends Activity {
private void goToUserLogin(){
Intent intent;
intent = new Intent(this, UserLoginActivity.class);
startActivity(intent);
finish();
}
private void goToMain(){
YokiAPI API = new YokiAPI(this);
Intent intent;
try {
if (API.authenticateSmart(YokiGlobals.preferences.getSavedUserId(this))) {
intent = new Intent(this, MainActivity.class);
startActivity(intent);
finish();
} else {
this.goToUserLogin();
}
} catch (Exception e){}
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_launcher);
// Launch Demo if First Run
if (YokiGlobals.preferences.getFirstLaunch(this)){
YokiGlobals.preferences.updateFirstLaunch(false, this);
this.launchDemo();
}
/*
** If userId saved, smart Auth and go to Main
** Else go to User Login for Full Auth or register
*/
if (YokiGlobals.preferences.getSavedUserId(this) == null){
this.goToUserLogin();
}
else {
this.goToMain();
}
}
}
And the .xml ressource file
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="THIS TEXT WONT APPEAR"
android:layout_marginTop="208dp"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true" />
</RelativeLayout>
Thanks,
Oscar
I thought calling the setContentView() method will instantly load Views on the screen
No it won't because you are still in onCreate(). If you want to see any UI you need to let the activity cycle to go further, so rework your code or move your authentication to separate activity, meybe?
PS: you use this. without any real reason.
Thank you for your help. I used AsyncTask in order to fetch data from the API.
The main UI thread can now load the view.
Here is some very simplified code that maybe could help others.
public class UserSmartAuthActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_user_smart_auth);
new SmartAuth().execute();
}
private class SmartAuth extends AsyncTask<Void, Void, Void> {
#Override
protected Void doInBackground(Void... params) {
Context context = getApplicationContext();
YokiAPI API = new YokiAPI(context);
Intent intent = null;
try {
if (API.authenticateSmart(YokiGlobals.preferences.getSavedUserId(context)))
intent = new Intent(context, MainActivity.class);
else
intent = new Intent(context, UserLoginActivity.class);
} catch (Exception e){}
startActivity(intent);
finish();
return null;
}
}
}
I want to show a splashScreen on my app firstly for few seconds and then load all my threads data using timer in java, then how should i do it.
Add Splash Screen Activity to your Project...
now replace the SplashScree.java file code as :
package samples.splash.screen;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
/**
* Splash screen activity
*
* #author Catalin Prata
*/
public class SplashScreen extends Activity {
// used to know if the back button was pressed in the splash screen activity and avoid opening the next activity
private boolean mIsBackButtonPressed;
private static final int SPLASH_DURATION = 2000; // 2 seconds
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.splash_screen);
Handler handler = new Handler();
// run a thread after 2 seconds to start the home screen
handler.postDelayed(new Runnable() {
#Override
public void run() {
// make sure we close the splash screen so the user won't come back when it presses back key
finish();
if (!mIsBackButtonPressed) {
// start the home screen if the back button wasn't pressed already
Intent intent = new Intent(SplashScreen.this, Home.class);
SplashScreen.this.startActivity(intent);
}
}
}, SPLASH_DURATION); // time in milliseconds (1 second = 1000 milliseconds) until the run() method will be called
}
#Override
public void onBackPressed() {
// set the flag to true so the next activity won't start up
mIsBackButtonPressed = true;
super.onBackPressed();
}
}
And the splash_screen xml looks like this: where you should have any image in your drawables named : "splash_screen"
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#drawable/splash_screen"/>
Now make your Splash Screen a Launcher Activity in Manifest File to make it a startup Activity..
And in order to get the title bar of the application down, just add he activity in your manifest and add the theme as you can see below:
<activity android:name=".SplashScreen" android:theme="#android:style/Theme.Black.NoTitleBar.Fullscreen">
<intent-filter>
<action android:name="android.intent.action.MAIN">
<category android:name="android.intent.category.LAUNCHER">
</category></action></intent-filter>
</activity>
Visit the following excellent tutorial on splash screen in Java(Swing).
Adding a splash screen to your application
In my code i have a boolean to install information to the database via preference. It works fine but the issue is now that have alot of information to add to the app and i get a black screen while the information is being added to the sqlite (only during installation). How can i add a progress spinner so the users will know the app is in the installation process. I am afraid they will think the app is broken when they stare at the black screen.
/** Insert list into db once */
if (pref.getBoolean("isFirst", true)) {
readBLContactsfromAssetsXMLToDB("list.xml");
pref.edit().putBoolean("isFirst", false).commit();
}
addQuickActions();
}
First you may use AsyncTask for doing processes that take long time. If you are not aware of it, it allows to perform background operations and publish results on the UI thread without having to manipulate threads and/or handlers.
But if you insist not to use that, then since you are blocking the UI thread, you cannot show the dialog and do your stuff at the same time. You need to have a background thread for the lengthy process, and show the progress dialog on the UI thread.
There are lots of examples of AsyncTaks online. Just for sample:
private class OuterClass extend Activity{
//....
#Override
public void onCreate(Bundle savedInstanceState) {
new performBackgroundTask ().execute();
}
//....
private class performBackgroundTask extends AsyncTask < Void, Void, Void >
{
private ProgressDialog dia;
// This method runs in UI thread before the background process starts.
#Override
protected void onPreExecute(){
// Show dialog
dia = new ProgressDialog(OuterClass.this);
dia.setMessage("Installing...");
dia.show();
}
#Override
protected Void doInBackground(Void... params) {
// Do all the stuff here ...
addQuickActions();
}
// Ececutes in UI thread after the long background process has finished
#Override
protected void onPostExecute(Void result){
// Dismiss dialog
dia.dismiss();
}
}
}
You may see How to display progress dialog before starting an activity in Android?
Hope this helps.
I am loading around 100 soundpools of small sound which I need them through out application in an activity.
When this activity starts, the screen goes blank and the background loads after loading all soundpools.
How do make it display the background I which have already added in xml through out while loading soundpools?
Use AsyncTask to handle this.
private class MyBackgroundTask extends AsyncTask<String, Void, Boolean> {
#Override
protected void onPreExecute() {
//initialize views like progress dialog.
}
#Override
protected Boolean doInBackground(String... params) {
//Add code which you want to run in background.
//In your case, code to load sound pools
}
#Override
public void onPostExecute(Boolean success) {
//update UI with the result
}
}
And in onCreate method,
new MyBackgroundTask().execute();
I've basically created a ListPreference where user would be able to choose from a list of options. After they have chosen one of the available option,the app will return to the main activity and the background image will change accordingly,however,it seems my app would't be able to detect the change in preference and change the background image.Can somebody please advice?Thanks!***Below snippet shows after my main activity resume,how it detects the change in preference and change the background image.
protected void onResume()
{
super.onResume();
listener = new SharedPreferences.OnSharedPreferenceChangeListener() {
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
if(key.equals("listPrefwall")){
tv.setText(prefs.getString("listPrefwall", "ondon"));
if(prefs.getString("listPrefwall", "ondon")=="ondon")
{
getWindow().setBackgroundDrawableResource(R.drawable.ondon);
tv.setText("testing");
}
else if(prefs.getString("listPrefwall", "ondon")=="japan")
{
getWindow().setBackgroundDrawableResource(R.drawable.japan);
tv.setText("pivot");
}
}
}
};
settings.registerOnSharedPreferenceChangeListener((OnSharedPreferenceChangeListener) listener);
}
Maybe your "settings" member retains a cached value? Try using the "prefs" object that gets passed to your listener.