繁体   English   中英

逐帧动画Android

[英]Frame by frame animation Android

我想使用Android的tts和Android中的可绘制帧动画来创建会说话的头像。 口型同步图像存储在drawable文件夹中。 这是按下语音按钮时执行的功能。

该功能的要点是,根据出现的字母,将每个相应的口形同步动作添加到动画中。 其余动作基于选择要说的语言,音调和语速决定。 线程用于并行运行动画和声音。

     b1.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            //thread to add the animation
            Thread avatarSp = new Thread(new Runnable() {
                @Override
                public void run() {
                    String toSpeak = ed1.getText().toString();
                    String[] words = toSpeak.split(" ");
                    for (String word : words) {
                        word = word.toLowerCase();
                        char[] letters = word.toCharArray();
                        for (int i = 0; i < letters.length; i++) {
                            if (letters[i] == 'a') {
                                if (sr1 == 1)
                                    avatarSpeak.addFrame(getResources().getDrawable(R.drawable.a_i), 500);
                                else if (sr1 == 2)
                                    avatarSpeak.addFrame(getResources().getDrawable(R.drawable.a_i), 750);
                            } else if (letters[i] == 'e') {
                                if (letters[i + 1] == 'i' || letters[i + 1] == 'a' || letters[i + 1] == 'e') {
                                    i++;
                                    if (sr1 == 1)
                                        avatarSpeak.addFrame(getResources().getDrawable(R.drawable.e), 500);
                                    else if (sr1 == 2)
                                        avatarSpeak.addFrame(getResources().getDrawable(R.drawable.e), 750);
                                } else {
                                    if (sr1 == 1)
                                        avatarSpeak.addFrame(getResources().getDrawable(R.drawable.l), 500);
                                    else if (sr1 == 2)
                                        avatarSpeak.addFrame(getResources().getDrawable(R.drawable.l), 750);
                                }

                            } else if (letters[i] == 'i') {
                                if (sr1 == 1)
                                    avatarSpeak.addFrame(getResources().getDrawable(R.drawable.c_d_g_k_n_r_s_th_y_z), 500);
                                else if (sr1 == 2)
                                    avatarSpeak.addFrame(getResources().getDrawable(R.drawable.c_d_g_k_n_r_s_th_y_z), 750);

                            } else if (letters[i] == 'o') {
                                if (sr1 == 1)
                                    avatarSpeak.addFrame(getResources().getDrawable(R.drawable.o), 500);
                                else if (sr1 == 2)
                                    avatarSpeak.addFrame(getResources().getDrawable(R.drawable.o), 750);
                            } else if (letters[i] == 'u') {
                                if (sr1 == 1)
                                    avatarSpeak.addFrame(getResources().getDrawable(R.drawable.u), 500);
                                else if (sr1 == 2)
                                    avatarSpeak.addFrame(getResources().getDrawable(R.drawable.u), 750);
                            } else if (letters[i] == 'w' || letters[i] == 'q') {
                                if (sr1 == 1)
                                    avatarSpeak.addFrame(getResources().getDrawable(R.drawable.w_q), 500);
                                else if (sr1 == 2)
                                    avatarSpeak.addFrame(getResources().getDrawable(R.drawable.w_q), 750);
                            } else if (letters[i] == 'f' || letters[i] == 'v') {
                                if (sr1 == 1)
                                    avatarSpeak.addFrame(getResources().getDrawable(R.drawable.f_v), 500);
                                else if (sr1 == 2)
                                    avatarSpeak.addFrame(getResources().getDrawable(R.drawable.f_v), 750);
                            } else if (letters[i] == 'l') {
                                if (sr1 == 1)
                                    avatarSpeak.addFrame(getResources().getDrawable(R.drawable.l), 500);
                                else if (sr1 == 2)
                                    avatarSpeak.addFrame(getResources().getDrawable(R.drawable.l), 750);
                            } else if (letters[i] == 'm' || letters[i] == 'b' || letters[i] == 'p') {
                                if (sr1 == 1)
                                    avatarSpeak.addFrame(getResources().getDrawable(R.drawable.m_b_p), 500);
                                else if (sr1 == 2)
                                    avatarSpeak.addFrame(getResources().getDrawable(R.drawable.m_b_p), 750);
                            } else {
                                if (sr1 == 1)
                                    avatarSpeak.addFrame(getResources().getDrawable(R.drawable.c_d_g_k_n_r_s_th_y_z), 500);
                                else if (sr1 == 2)
                                    avatarSpeak.addFrame(getResources().getDrawable(R.drawable.c_d_g_k_n_r_s_th_y_z), 750);
                            }
                        }
                        if (sr1 == 1)
                            avatarSpeak.addFrame(getResources().getDrawable(R.drawable.rest), 500);
                        else if (sr1 == 2)
                            avatarSpeak.addFrame(getResources().getDrawable(R.drawable.rest), 750);
                    }
                    avatar.post(new Starter());
                }

            });
            //start the thread
            avatarSp.start();
            tts1.setPitch(p1);
            tts1.setSpeechRate(sr1);
            String toSpeak = ed1.getText().toString();
            lang = sp1.getSelectedItem().toString();
            if (lang.equals("US")) {
                System.out.print("Condition satisfied");
                tts1.setLanguage(Locale.US);
            } else if (lang.equals("UK"))
                tts1.setLanguage(Locale.UK);
            else if (lang.equals("Germany"))
                tts1.setLanguage(Locale.GERMANY);
            else if (lang.equals("Italy"))
                tts1.setLanguage(Locale.ITALY);
            else if (lang.equals("Japan"))
                tts1.setLanguage(Locale.JAPAN);
            else
                tts1.setLanguage(Locale.CHINA);

            Toast.makeText(getApplicationContext(), toSpeak, Toast.LENGTH_SHORT).show();
            //speak
            tts1.speak(toSpeak, TextToSpeech.QUEUE_FLUSH, null);
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                tts1.speak(toSpeak, TextToSpeech.QUEUE_FLUSH, null, null);
            } else {
                tts1.speak(toSpeak, TextToSpeech.QUEUE_FLUSH, null);
            }
        }
    });
}

整个编码经过测试的API级别为Android 5.0(21)和Android 6.0(AVD 23)。 但是,当我按下语音按钮时,API会在AVD和电话上崩溃。 你能告诉我:

    1. Where the error could possibly be?
    2. Is there a better way to do this and how?

如果它是新手,请与我联系,但是我真的很想知道用我自己的代码实现功能的更好方法。

更新1

将添加日志猫信息。

    10-29 09:02:26.245    1931-1931/com.bluesbegone.avatarspeak I/art﹕ Not late-enabling -Xcheck:jni (already on)
    10-29 09:02:26.246    1931-1931/com.bluesbegone.avatarspeak I/art﹕ Late-enabling JIT
    10-29 09:02:26.411    1931-1931/com.bluesbegone.avatarspeak I/art﹕ JIT created with code_cache_capacity=2MB compile_threshold=1000
    10-29 09:02:27.282    1931-1931/com.bluesbegone.avatarspeak W/System﹕ ClassLoader referenced unknown path: /data/app/com.bluesbegone.avatarspeak-2/lib/x86
    10-29 09:02:28.992    1931-1931/com.bluesbegone.avatarspeak I/TextToSpeech﹕ Sucessfully bound to com.svox.pico
    10-29 09:02:29.026    1931-1956/com.bluesbegone.avatarspeak D/OpenGLRenderer﹕ Use EGL_SWAP_BEHAVIOR_PRESERVED: true
    10-29 09:02:29.056    1931-1931/com.bluesbegone.avatarspeak D/﹕ HostConnection::get() New Host Connection established 0xa3fff460, tid 1931
    10-29 09:02:29.300    1931-1938/com.bluesbegone.avatarspeak W/art﹕ Suspending all threads took: 37.049ms
    10-29 09:02:29.459    1931-1956/com.bluesbegone.avatarspeak D/﹕ HostConnection::get() New Host Connection established 0xa3fff830, tid 1956
    10-29 09:02:29.509    1931-1956/com.bluesbegone.avatarspeak I/OpenGLRenderer﹕ Initialized EGL, version 1.4
    10-29 09:02:29.671    1931-1956/com.bluesbegone.avatarspeak W/EGL_emulation﹕ eglSurfaceAttrib not implemented
    10-29 09:02:29.672    1931-1956/com.bluesbegone.avatarspeak W/OpenGLRenderer﹕ Failed to set EGL_SWAP_BEHAVIOR on surface 0xad77ac60, error=EGL_SUCCESS
    10-29 09:02:29.912    1931-1931/com.bluesbegone.avatarspeak I/Choreographer﹕ Skipped 41 frames!  The application may be doing too much work on its main thread.
    10-29 09:02:31.082    1931-1931/com.bluesbegone.avatarspeak I/Choreographer﹕ Skipped 69 frames!  The application may be doing too much work on its main thread.
    10-29 09:02:31.297    1931-1931/com.bluesbegone.avatarspeak I/TextToSpeech﹕ Connected to ComponentInfo{com.svox.pico/com.svox.pico.PicoService}
    10-29 09:02:31.822    1931-1968/com.bluesbegone.avatarspeak I/TextToSpeech﹕ Set up connection to ComponentInfo{com.svox.pico/com.svox.pico.PicoService}
    10-29 09:02:32.280    1931-1938/com.bluesbegone.avatarspeak W/art﹕ Suspending all threads took: 288.632ms
    10-29 09:02:35.320    1931-1938/com.bluesbegone.avatarspeak W/art﹕ Suspending all threads took: 12.137ms
    10-29 09:02:43.335    1931-2173/com.bluesbegone.avatarspeak E/AndroidRuntime﹕ FATAL EXCEPTION: Thread-83
Process: com.bluesbegone.avatarspeak, PID: 1931
android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
        at android.view.ViewRootImpl.checkThread(ViewRootImpl.java:6556)
        at android.view.ViewRootImpl.invalidateChildInParent(ViewRootImpl.java:942)
        at android.view.ViewGroup.invalidateChild(ViewGroup.java:5081)
        at android.view.View.invalidateInternal(View.java:12713)
        at android.view.View.invalidate(View.java:12649)
        at android.view.View.invalidateDrawable(View.java:16788)
        at android.widget.ImageView.invalidateDrawable(ImageView.java:248)
        at android.graphics.drawable.DrawableContainer.invalidateDrawable(DrawableContainer.java:377)
        at android.graphics.drawable.Drawable.invalidateSelf(Drawable.java:385)
        at android.graphics.drawable.Drawable.setVisible(Drawable.java:764)
        at android.graphics.drawable.DrawableContainer.initializeDrawableForDisplay(DrawableContainer.java:510)
        at android.graphics.drawable.DrawableContainer.selectDrawable(DrawableContainer.java:459)
        at android.graphics.drawable.AnimationDrawable.setFrame(AnimationDrawable.java:274)
        at android.graphics.drawable.AnimationDrawable.addFrame(AnimationDrawable.java:251)
        at com.bluesbegone.avatarspeak.MainActivity$4$1.run(MainActivity.java:190)
        at java.lang.Thread.run(Thread.java:818)
    10-29 09:02:44.093    1931-1942/com.bluesbegone.avatarspeak I/art﹕ Background sticky concurrent mark sweep GC freed 10741(781KB) AllocSpace objects, 0(0B) LOS objects, 39% free, 2MB/3MB, paused 1.490ms total 313.129ms
    10-29 09:02:44.122    1931-1942/com.bluesbegone.avatarspeak W/art﹕ Suspending all threads took: 26.447ms
    10-29 09:02:44.278    1931-1938/com.bluesbegone.avatarspeak W/art﹕ Suspending all threads took: 146.147ms
    10-29 09:02:45.073    1931-1931/com.bluesbegone.avatarspeak I/Choreographer﹕ Skipped 77 frames!  The application may be doing too much work on its main thread.
    10-29 09:02:45.160    1931-1956/com.bluesbegone.avatarspeak W/EGL_emulation﹕ eglSurfaceAttrib not implemented
    10-29 09:02:45.161    1931-1956/com.bluesbegone.avatarspeak W/OpenGLRenderer﹕ Failed to set EGL_SWAP_BEHAVIOR on surface 0xa29586e0, error=EGL_SUCCESS
    10-29 09:02:45.231    1931-1956/com.bluesbegone.avatarspeak E/Surface﹕ getSlotFromBufferLocked: unknown buffer: 0xab81f1e0
    10-29 09:02:47.005    1931-1956/com.bluesbegone.avatarspeak E/Surface﹕ getSlotFromBufferLocked: unknown buffer: 0xab81f1e0
    10-29 09:02:48.334    1931-2173/com.bluesbegone.avatarspeak I/Process﹕ Sending signal. PID: 1931 SIG: 9

您正在尝试从后台线程对视图进行动画处理,但是只有主线程可以触摸视图。 摆脱线程,只需将代码放在主要的onClick方法中即可。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM