逐帧动画Android

时间:2015-10-27 02:58:16

标签: android animation animationdrawable

我想创建一个会说话的头像,在Android中使用Android和drawable frame anmation。唇形同步图像存储在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

1 个答案:

答案 0 :(得分:1)

您尝试从后台线程设置动画视图,但只有主线程可以触摸视图。摆脱线程,只需将代码放在主要的onClick方法中。