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