Hi I am trying to make my 1st android app and I made a splash screen. However, I tried to add loading please wait at the bottom with the period increment every 2 seconds. I am not sure how to make it happen because the screen crashes because of this text.
final TextView loadingText = (TextView)findViewById(R.id.loading_text);
Thread splashTimer = new Thread(){
public void run(){
try{
int splashTime = 0;
while(splashTime < 6000){
sleep(100);
if(splashTime < 2000){
loadingText.setText("Loading.");
}
else if(splashTime >= 2000 && splashTime < 4000 ){
loadingText.setText("Loading..");
}else if (splashTime >= 4000){
loadingText.setText("Loading...");
}
splashTime = splashTime + 100;
}
Intent intent = new Intent(MainActivity.this,myMainScreen.class);
startActivity(intent);
}catch(InterruptedException e){
e.printStackTrace();
}
finally{
finish();
}
}
};
splashTimer.start();
}
here is my logcat
06-12 01:36:33.646: D/HyLog(29533): I : /data/font/config/sfconfig.dat, No such file or directory (2)
06-12 01:36:33.646: D/HyLog(29533): I : /data/font/config/dfactpre.dat, No such file or directory (2)
06-12 01:36:33.646: D/HyLog(29533): I : /data/font/config/sfconfig.dat, No such file or directory (2)
06-12 01:36:33.986: I/Adreno-EGL(29533): <qeglDrvAPI_eglInitialize:385>: EGL 1.4 QUALCOMM build: ()
06-12 01:36:33.986: I/Adreno-EGL(29533): OpenGL ES Shader Compiler Version: E031.24.00.02
06-12 01:36:33.986: I/Adreno-EGL(29533): Build Date: 01/20/14 Mon
06-12 01:36:33.986: I/Adreno-EGL(29533): Local Branch: PMH2-KK_3.5-RB1-AU61-554722-586267-set2
06-12 01:36:33.986: I/Adreno-EGL(29533): Remote Branch:
06-12 01:36:33.986: I/Adreno-EGL(29533): Local Patches:
06-12 01:36:33.986: I/Adreno-EGL(29533): Reconstruct Branch:
06-12 01:36:34.026: D/OpenGLRenderer(29533): Enabling debug mode 0
06-12 01:36:34.096: I/ActivityManager(29533): Timeline: Activity_idle id: android.os.BinderProxy@42b1e788 time:14063098
06-12 01:36:34.336: W/dalvikvm(29533): threadid=11: thread exiting with uncaught exception (group=0x41ae6e48)
06-12 01:36:34.336: E/AndroidRuntime(29533): FATAL EXCEPTION: Thread-2388
06-12 01:36:34.336: E/AndroidRuntime(29533): Process: com.sachinda.myfirstapp, PID: 29533
06-12 01:36:34.336: E/AndroidRuntime(29533): android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
06-12 01:36:34.336: E/AndroidRuntime(29533): at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6347)
06-12 01:36:34.336: E/AndroidRuntime(29533): at android.view.ViewRootImpl.requestLayout(ViewRootImpl.java:871)
06-12 01:36:34.336: E/AndroidRuntime(29533): at android.view.View.requestLayout(View.java:16472)
06-12 01:36:34.336: E/AndroidRuntime(29533): at android.view.View.requestLayout(View.java:16472)
06-12 01:36:34.336: E/AndroidRuntime(29533): at android.view.View.requestLayout(View.java:16472)
06-12 01:36:34.336: E/AndroidRuntime(29533): at android.view.View.requestLayout(View.java:16472)
06-12 01:36:34.336: E/AndroidRuntime(29533): at android.widget.RelativeLayout.requestLayout(RelativeLayout.java:352)
06-12 01:36:34.336: E/AndroidRuntime(29533): at android.view.View.requestLayout(View.java:16472)
06-12 01:36:34.336: E/AndroidRuntime(29533): at android.widget.TextView.checkForRelayout(TextView.java:6817)
06-12 01:36:34.336: E/AndroidRuntime(29533): at android.widget.TextView.setText(TextView.java:3947)
06-12 01:36:34.336: E/AndroidRuntime(29533): at android.widget.TextView.setText(TextView.java:3805)
06-12 01:36:34.336: E/AndroidRuntime(29533): at android.widget.TextView.setText(TextView.java:3780)
06-12 01:36:34.336: E/AndroidRuntime(29533): at com.sachinda.myfirstapp.MainActivity$1.run(MainActivity.java:45)
06-12 01:36:36.316: I/Process(29533): Sending signal. PID: 29533 SIG: 9
It is crashing because you are modifying ui component on a non UI thread add method like
private void setText(final CharSequence text) {
runOnUiThread(new Runnable() {
@Override
public void run() {
((TextView) findViewById(R.id.loading_text)).setText(text);
}
});
}
and modify your code to use that method
while(splashTime < 6000){
sleep(100);
if(splashTime < 2000){
setText("Loading.");
}
else if(splashTime >= 2000 && splashTime < 4000 ){
setText("Loading..");
}else if (splashTime >= 4000){
setText("Loading...");
}
splashTime = splashTime + 100;
}
I have achieved Loading 3 dots using coroutines
lifecycle
scope and recursion. Check out the below code. isCallAttended is boolean
by default is false
. Then you can set it true
later in logic so that you could cancel coroutine
.
private fun delayCallingAnimation() {
lifecycleScope.launch {
if(isCallAttended) {
this.cancel()
return@launch
}
delay(1000)
mBinding.incomingCallView.tvCalling.text = "Calling."
delay(1000)
mBinding.incomingCallView.tvCalling.text = "Calling.."
delay(1000)
mBinding.incomingCallView.tvCalling.text = "Calling..."
delayCallingAnimation()
}
}
What you are doing here is updating the UI elements inside a thread, which isn't allowed!
What you will have to do is use Handlers:
new Handler().post(new Runnable() {
@Override
public void run() {
// Code here will run in UI thread
}
});
This will solve the purpose.
May be it helps anybody :) I found 2 solutions how animate dots in TextView
ending ("...").
Common function for both solutions
private fun getDotAnimator(
textView: TextView,
dotCount: Int,
list: List<CharSequence>
): ValueAnimator {
val valueTo = dotCount + 1
return ValueAnimator.ofInt(0, valueTo).apply {
this.interpolator = LinearInterpolator()
this.duration = textView.context.resources.getInteger(R.integer.dots_anim_time).toLong()
this.repeatCount = ObjectAnimator.INFINITE
this.repeatMode = ObjectAnimator.RESTART
addUpdateListener {
val value = it.animatedValue as? Int
/**
* Sometimes [ValueAnimator] give a corner value.
*/
if (value == null || value == valueTo) return@addUpdateListener
textView.text = list.getOrNull(value)
}
}
}
In XML:
<string name="dot" translatable="false">.</string>
<integer name="dots_anim_time">1200</integer>
fun getDotsAnimator(textView: TextView?, @StringRes stringId: Int): ValueAnimator? {
val context = textView?.context ?: return null
val simpleText = context.getString(stringId)
val dotText = context.getString(R.string.dot)
val dotCount = 3
val textList = mutableListOf<String>()
for (i in 0 until dotCount + 1) {
val text = StringBuilder(simpleText).apply {
repeat(i) { append(dotText) }
}.toString()
textList.add(text)
}
return getDotAnimator(textView, dotCount, textList)
}
But it has disadvantage. If in your XML file TextView
has android:gravity="center"
it will looks ugly. Because text in textList
has different lenght
and also has different center
. Use this solution only with android:gravity="start"
.
fun getDotsSpanAnimator(textView: TextView?, @StringRes stringId: Int): ValueAnimator? {
val context = textView?.context ?: return null
val simpleText = context.getString(stringId)
val dotText = context.getString(R.string.dot)
val dotCount = 3
val resultText = StringBuilder(simpleText).apply {
repeat(dotCount) { append(dotText) }
}.toString()
val textList = mutableListOf<SpannableString>()
for (i in 0 until dotCount + 1) {
val spannable = SpannableString(resultText)
val start = resultText.length - (dotCount - i)
val end = resultText.length
val flag = Spannable.SPAN_EXCLUSIVE_EXCLUSIVE
spannable.setSpan(ForegroundColorSpan(Color.TRANSPARENT), start, end, flag)
textList.add(spannable)
}
return getDotAnimator(textView, dotCount, textList)
}
This solution will work perfect with every android:gravity
.
private val dotsAnimator by lazy {
getDotsSpanAnimator(loadingText, R.string.dialog_text_loading)
}
override fun onResume() {
super.onResume()
dotsAnimator?.start()
}
override fun onPause() {
super.onPause()
dotsAnimator?.pause()
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With