¿Cómo podemos optimizar (cpu & ram) esta animación de salpicadura personalizada de android?
He desarrollado una animación personalizada para mi actividad de Splash Screen:
=> Aquí está una animación que muestra lo que está sucediendo:
- ¿Por qué proguard procesa AndroidManifest.xml?
- ¿Cómo hacer que RecyclerView recicle dentro de NestedScrollView?
- Precisión del sueño del hilo
- Cómo reducir el tiempo de arranque en los sistemas operativos de Android.
- Prueba NEON-optimizado cv :: threshold () en el dispositivo móvil
Por supuesto mi aplicación real:
- Es con diferentes imágenes (fullhd)
- Es un poco más lento comparar con el GIF: 3s para 60 pantallas intermedias.
Mi diseñador me proporcionó 60 archivos png.
=> Un ejemplo para ilustrar:
Mi objetivo es:
- Comenzar desde un logotipo central (aquí con SO) con una imagen inferior (Apple)
- Ejecutar una animación morphing
- Terminar en la pantalla como la página principal de la aplicación
Para ejecutar esto, tengo un diseño Multilayer para la SpashScreenActivity con:
- BackGround (invisible): el diseño de la homePage (MainActivity)
- MiddleGround: con el ImageView de Apple que es reemplazado por el Droid y el bottomBar que crecen
- FrontGround: el logotipo en un ImageView con su lema en un TextView
Aquí está el código xml para el diseño de SpashScreen:
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="bottom"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:visibility="invisible" android:orientation="vertical"> <FrameLayout android:id="@+id/fl_logo_top_marge_hidden" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:visibility="invisible" android:background="@color/colorPrimary" /> <include android:visibility="invisible" android:id="@+id/l_logo_activate_hidden" layout="@layout/part_logo_activate" android:layout_width="match_parent" android:layout_height="wrap_content" /> <FrameLayout android:visibility="invisible" android:id="@+id/fl_logo_bottom_marge_hidden" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" android:background="@color/colorPrimary" /> <fr.millezimsolutions.app.splashanimation.SquareAspectWidthBasedImageView android:visibility="invisible" android:id="@+id/iv_home_hidden" android:layout_width="match_parent" android:layout_height="wrap_content" android:scaleType="fitXY" android:src="@drawable/p_log_android" /> <FrameLayout android:visibility="invisible" android:id="@+id/fl_bar_hidden" android:layout_width="match_parent" android:layout_height="@dimen/start_degustation_bar_height" android:background="@color/colorAccent" android:gravity="bottom" /> </LinearLayout> <LinearLayout android:id="@+id/fl_middle" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_alignParentBottom="true" android:background="@color/colorPrimary" android:gravity="bottom" android:orientation="vertical"> <fr.millezimsolutions.app.splashanimation.FitXCropTopImageView android:id="@+id/iv_slogan" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/colorTransparent" android:scaleType="fitStart" android:src="@drawable/p_log_apple" /> <FrameLayout android:id="@+id/fl_logo_bottom_bar" android:layout_width="match_parent" android:layout_height="0dp" android:background="@color/colorAccent" android:gravity="bottom" /> </LinearLayout> <LinearLayout android:id="@+id/fl_front" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <FrameLayout android:id="@+id/fl_logo_top_layout" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="40" android:background="@color/colorPrimary" /> <FrameLayout android:id="@+id/fl_logo_top_marge" android:layout_width="match_parent" android:layout_height="5dp" android:background="@color/colorTransparent" /> <include android:id="@+id/l_logo_activate" layout="@layout/part_logo_activate" android:layout_width="match_parent" android:layout_height="wrap_content" /> <FrameLayout android:id="@+id/fl_logo_bottom_marge" android:layout_width="match_parent" android:layout_height="5dp" android:background="@color/colorTransparent" /> <FrameLayout android:id="@+id/fl_logo_bottom_layout" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="40" android:background="@color/colorTransparent" /> </LinearLayout> </RelativeLayout>
2 El código xml para la parte superior del diseño (vía include)
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/colorTransparent" android:gravity="bottom" android:orientation="vertical"> <FrameLayout android:id="@+id/fl_home_marginTop" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" /> <ImageView android:id="@+id/iv_millezimuLogo" android:layout_width="wrap_content" android:layout_height="64dp" android:layout_gravity="center_horizontal" android:layout_marginLeft="@dimen/marge" android:layout_marginRight="@dimen/marge" android:src="@drawable/p_log_so" /> <TextView android:id="@+id/tv_slogan" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:layout_marginBottom="@dimen/marge_small" android:layout_marginTop="@dimen/marge_small_border" android:gravity="center" android:hint="" android:text="Bonjour" android:textColor="@color/colorAccent" android:textSize="20sp" /> <ImageView android:id="@+id/iv_sponsorLogo" android:layout_width="wrap_content" android:layout_height="50dp" android:layout_gravity="center_horizontal" android:layout_marginLeft="@dimen/marge" android:layout_marginRight="@dimen/marge" android:src="@drawable/p_log_so" android:visibility="gone" /> <TextView android:id="@+id/tv_sponsorLogo" android:layout_width="match_parent" android:layout_height="50dp" android:layout_gravity="center_horizontal" android:layout_marginLeft="@dimen/marge" android:layout_marginRight="@dimen/marge" android:gravity="center" android:textColor="@color/colorAccent" android:textSize="20sp" android:visibility="gone" /> <FrameLayout android:id="@+id/fl_home_marginBottom" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" /> </LinearLayout>
3 Aquí está el código de la Actividad.
import android.content.Intent; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.graphics.Rect; import android.os.Bundle; import android.os.Handler; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.ViewGroup; import android.view.WindowManager; import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; public class SplashScreenActivity extends AppCompatActivity { // Splash screen timer private static int SPLASH_TIME_OUT = 3000; private int finalTopMarge, finalBottomMarge, topMargeDec, bottomMargeInc; long currentTimeStamp; private int[] mSplashAnimFrames = {R.drawable.p_wave_spashscreen_00, R.drawable.p_wave_spashscreen_01, R.drawable.p_wave_spashscreen_02, R.drawable.p_wave_spashscreen_03, R.drawable.p_wave_spashscreen_04, R.drawable.p_wave_spashscreen_05, R.drawable.p_wave_spashscreen_06, R.drawable.p_wave_spashscreen_07, R.drawable.p_wave_spashscreen_08, R.drawable.p_wave_spashscreen_09, R.drawable.p_wave_spashscreen_10, R.drawable.p_wave_spashscreen_11, R.drawable.p_wave_spashscreen_12, R.drawable.p_wave_spashscreen_13, R.drawable.p_wave_spashscreen_14, R.drawable.p_wave_spashscreen_15, R.drawable.p_wave_spashscreen_16, R.drawable.p_wave_spashscreen_17, R.drawable.p_wave_spashscreen_18, R.drawable.p_wave_spashscreen_19, R.drawable.p_wave_spashscreen_20, R.drawable.p_wave_spashscreen_21, R.drawable.p_wave_spashscreen_22, R.drawable.p_wave_spashscreen_23, R.drawable.p_wave_spashscreen_24, R.drawable.p_wave_spashscreen_25, R.drawable.p_wave_spashscreen_26, R.drawable.p_wave_spashscreen_27, R.drawable.p_wave_spashscreen_28, R.drawable.p_wave_spashscreen_29, R.drawable.p_wave_spashscreen_30, R.drawable.p_wave_spashscreen_31, R.drawable.p_wave_spashscreen_32, R.drawable.p_wave_spashscreen_33, R.drawable.p_wave_spashscreen_34, R.drawable.p_wave_spashscreen_35, R.drawable.p_wave_spashscreen_36, R.drawable.p_wave_spashscreen_37, R.drawable.p_wave_spashscreen_38, R.drawable.p_wave_spashscreen_39, R.drawable.p_wave_spashscreen_40, R.drawable.p_wave_spashscreen_41, R.drawable.p_wave_spashscreen_42, R.drawable.p_wave_spashscreen_43, R.drawable.p_wave_spashscreen_44, R.drawable.p_wave_spashscreen_45, R.drawable.p_wave_spashscreen_46, R.drawable.p_wave_spashscreen_47, R.drawable.p_wave_spashscreen_48, R.drawable.p_wave_spashscreen_49, R.drawable.p_wave_spashscreen_50, R.drawable.p_wave_spashscreen_51, R.drawable.p_wave_spashscreen_52, R.drawable.p_wave_spashscreen_53, R.drawable.p_wave_spashscreen_54, R.drawable.p_wave_spashscreen_55, R.drawable.p_wave_spashscreen_56, R.drawable.p_wave_spashscreen_57, R.drawable.p_wave_spashscreen_58, R.drawable.p_wave_spashscreen_59}; private final int C_STOP = 120, C_MOVE = 40, C_BAR = 80; private int bottomBarRatio; private ImageView finalImageView; private int targetWidth, targetHeight; private Rect mImageViewRect; private Paint paint; private Bitmap original; private Bitmap result; private boolean setupOk = false; private ImageView mImageView; private Bitmap mask; private FrameLayout ltm; private FrameLayout lbm; private FrameLayout lbb; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_splash_screen); // Indique que l'ecran est full Screen getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); ImageManager.create(this); } @Override protected void onResume() { super.onResume(); int delay = SPLASH_TIME_OUT / C_STOP; bottomBarRatio = getResources().getDimensionPixelSize(R.dimen.bar_nav_height) / (C_STOP - C_BAR); runCycle(0, delay); } private void logStamp() { long oldTimeStamp = currentTimeStamp; currentTimeStamp = System.currentTimeMillis(); long delay = currentTimeStamp - oldTimeStamp; Log.v("TIMESTAMP", String.valueOf(delay)); } public void runCycle(final int cycle, final int delay) { if (BuildConfig.DEBUG) logStamp(); Handler cyclic = new Handler(); cyclic.postDelayed(new Runnable() { @Override public void run() { if (cycle >= C_STOP) { closeActivity(); } else { runCycle(cycle + 1, delay); if (cycle >= C_MOVE) { // Copy des hauteurs pour les marges initFinalLogoMargeHeight(); // Decroissance du poid de layout superieur MoveUpLogo(); // bouger la bar if (cycle >= C_BAR) { updateBottomBar(cycle - C_BAR); } findViewById(R.id.fl_front).requestLayout(); } if (setupFinalView()) { if ((cycle % 2) == 0) updateImageViewLight(cycle / 2); } } } }, delay); } private boolean setupFinalView() { if (!setupOk) { finalImageView = (ImageView) findViewById(R.id.iv_home_hidden); targetWidth = finalImageView.getWidth(); targetHeight = finalImageView.getHeight(); mImageViewRect = new Rect(0, 0, finalImageView.getWidth(), finalImageView.getHeight()); mImageView = (ImageView) findViewById(R.id.iv_slogan); mImageView.setBackgroundResource(R.drawable.p_log_apple); paint = new Paint(Paint.ANTI_ALIAS_FLAG); ltm = (FrameLayout) findViewById(R.id.fl_logo_top_marge); lbm = (FrameLayout) findViewById(R.id.fl_logo_bottom_marge); lbb = ((FrameLayout) findViewById(R.id.fl_logo_bottom_bar)); if (targetWidth > 0 && targetHeight > 0) { original = ImageManager.decodeSampledBitmapFromResource(getResources(), R.drawable.p_log_android, targetWidth, targetHeight); result = Bitmap.createBitmap(targetWidth, targetHeight, Bitmap.Config.ARGB_4444); setupOk = true; } } return setupOk; } private void MoveUpLogo() { ViewGroup.LayoutParams ltmp = ltm.getLayoutParams(); ltmp.height -= topMargeDec; ViewGroup.LayoutParams lbmp = lbm.getLayoutParams(); lbmp.height += bottomMargeInc; } private void initFinalLogoMargeHeight() { if (finalBottomMarge == 0) { finalTopMarge = findViewById(R.id.fl_logo_top_marge_hidden).getHeight(); topMargeDec = (findViewById(R.id.fl_logo_top_marge).getHeight() - finalTopMarge) / C_BAR; finalBottomMarge = findViewById(R.id.fl_logo_bottom_marge_hidden).getHeight() + findViewById(R.id.fl_bar_hidden).getHeight() + findViewById(R.id.iv_home_hidden).getHeight(); bottomMargeInc = (finalBottomMarge - findViewById(R.id.fl_logo_bottom_marge).getHeight()) / C_BAR; } } private void updateBottomBar(int cycle) { LinearLayout.LayoutParams lbbp = (LinearLayout.LayoutParams) lbb.getLayoutParams(); lbbp.height = cycle * bottomBarRatio; lbb.setLayoutParams(lbbp); } private void closeActivity() { overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out); Intent i = new Intent(SplashScreenActivity.this, MainActivity.class); startActivity(i); finish(); overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out); } private int getNext(int index) { if (index < (mSplashAnimFrames.length - 1)) index++; else index = mSplashAnimFrames.length - 1; return mSplashAnimFrames[index]; } public void updateImageViewLight(int index) { mask = ImageManager.decodeSampledBitmapFromResource(getResources(), getNext(index), targetWidth, targetHeight); Canvas mCanvas = new Canvas(result); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); mCanvas.drawBitmap(original, null, mImageViewRect, null); mCanvas.drawBitmap(mask, null, mImageViewRect, paint); paint.setXfermode(null); mImageView.setImageBitmap(result); } }
4 Y el código del ImageManager para la comprensión (yo uso UIL)
public class ImageManager { private static Context context; public static ImageLoader getImageLoader() { return ImageLoader.getInstance(); } public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId, int reqWidth, int reqHeight) { // First decode with inJustDecodeBounds=true to check dimensions final BitmapFactory.Options options = new BitmapFactory.Options(); options.outWidth = reqWidth; options.outHeight = reqHeight; options.inJustDecodeBounds = true; options.inPreferredConfig = Bitmap.Config.RGB_565; BitmapFactory.decodeResource(res, resId, options); // Calculate inSampleSize options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); // Decode bitmap with inSampleSize set options.inJustDecodeBounds = false; return getResourceImageForCanvas(resId, new ImageSize(reqWidth, reqHeight)); } public static int calculateInSampleSize( BitmapFactory.Options options, int reqWidth, int reqHeight) { // Raw height and width of image final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; if (height > reqHeight || width > reqWidth) { final int halfHeight = height / 2; final int halfWidth = width / 2; // Calculate the largest inSampleSize value that is a power of 2 and keeps both // height and width larger than the requested height and width. while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) { inSampleSize *= 2; } } return inSampleSize; } public static Bitmap getResourceImageForCanvas(int bitmapResourceId, ImageSize targetImageSize) { DisplayImageOptions options = new DisplayImageOptions.Builder().bitmapConfig(Bitmap.Config.RGB_565).build(); return getImageLoader().loadImageSync("drawable://" + bitmapResourceId, targetImageSize, options); // } public static void create(Context context) { try { ImageManager.context = context; initImageLoader(); } catch (IOException e) { e.printStackTrace(); } } private static void initImageLoader() throws IOException { // Create global configuration and initialize ImageLoader with this // configuration BitmapFactory.Options opt = new BitmapFactory.Options(); // opt.inScaled = false; opt.inSampleSize = 1; opt.inDither = true; opt.inPreferredConfig = Bitmap.Config.RGB_565; opt.inPreferQualityOverSpeed = false; DisplayImageOptions defaultOptions = new DisplayImageOptions.Builder()./* cacheInMemory(true). */cacheOnDisk(true).decodingOptions(opt).imageScaleType(ImageScaleType.IN_SAMPLE_POWER_OF_2) .bitmapConfig(Bitmap.Config.RGB_565).build(); ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(context).defaultDisplayImageOptions(defaultOptions).memoryCacheSizePercentage(13).writeDebugLogs().build(); ImageLoader.getInstance().init(config); } }
ESTADO:
El método updateImageViewLight puede ayudar a otros a tratar este tipo de comportamiento (PortedDuff …) que no fue fácil de encontrar.
La animación funciona bien en un dispositivo potente, pero a menudo se retrasa si el dispositivo o la aplicación hace algo más.
He intentado ejecutar este cálculo en Async Task pero era menos potente que en el mainThread
PREGUNTAS:
Estoy buscando cualquier consejo educado sobre mi implementación, que puede ayudar a mejorar:
- Consumo de memoria
- uso de CPU
Pero también :
- Fuga potencial
- Legibilidad del código
- Cómo utilizar -assumenosideeffects clase android.util.Log en mi aplicación
- ¿Qué optimizaciones puedo esperar de Dalvik y la cadena de herramientas de Android?
- Demasiadas actividades en Android?
- Ajustes de optimización de Proguard: Habilitar la combinación de clases, los modelos y el campo / * en versiones modernas de API y Proguard
- Android ProGuard: Optimizaciones más agresivas
- ¿Algún consejo sobre cómo acelerar esto en Android?
- Optimizaciones de Scrollview
- Precisión del sueño del hilo
Aún no responde completamente, pero es un intento, que necesita ser continuado y comentado.
Primera optimización:
- Cree una vista personalizada (aquí la extensión
ImageView
) para la onda, que se actualizará en el métodoonDraw
- Define miembro const como miembros de clase
static final
- Como más posible, evite la creación de instancias de objetos en
onDraw
(Canvas
yPaint
), así como la actualización innecesaria de objetos
Aquí está el código del CustomView que extiende ImageView
public class WaveFillingImageView extends ImageView { private final static int[] mSplashAnimFrames = {R.drawable.p_wave_spashscreen_00, R.drawable.p_wave_spashscreen_01, R.drawable.p_wave_spashscreen_02, R.drawable.p_wave_spashscreen_03, R.drawable.p_wave_spashscreen_04, R.drawable.p_wave_spashscreen_05, R.drawable.p_wave_spashscreen_06, R.drawable.p_wave_spashscreen_07, R.drawable.p_wave_spashscreen_08, R.drawable.p_wave_spashscreen_09, R.drawable.p_wave_spashscreen_10, R.drawable.p_wave_spashscreen_11, R.drawable.p_wave_spashscreen_12, R.drawable.p_wave_spashscreen_13, R.drawable.p_wave_spashscreen_14, R.drawable.p_wave_spashscreen_15, R.drawable.p_wave_spashscreen_16, R.drawable.p_wave_spashscreen_17, R.drawable.p_wave_spashscreen_18, R.drawable.p_wave_spashscreen_19, R.drawable.p_wave_spashscreen_20, R.drawable.p_wave_spashscreen_21, R.drawable.p_wave_spashscreen_22, R.drawable.p_wave_spashscreen_23, R.drawable.p_wave_spashscreen_24, R.drawable.p_wave_spashscreen_25, R.drawable.p_wave_spashscreen_26, R.drawable.p_wave_spashscreen_27, R.drawable.p_wave_spashscreen_28, R.drawable.p_wave_spashscreen_29, R.drawable.p_wave_spashscreen_30, R.drawable.p_wave_spashscreen_31, R.drawable.p_wave_spashscreen_32, R.drawable.p_wave_spashscreen_33, R.drawable.p_wave_spashscreen_34, R.drawable.p_wave_spashscreen_35, R.drawable.p_wave_spashscreen_36, R.drawable.p_wave_spashscreen_37, R.drawable.p_wave_spashscreen_38, R.drawable.p_wave_spashscreen_39, R.drawable.p_wave_spashscreen_40, R.drawable.p_wave_spashscreen_41, R.drawable.p_wave_spashscreen_42, R.drawable.p_wave_spashscreen_43, R.drawable.p_wave_spashscreen_44, R.drawable.p_wave_spashscreen_45, R.drawable.p_wave_spashscreen_46, R.drawable.p_wave_spashscreen_47, R.drawable.p_wave_spashscreen_48, R.drawable.p_wave_spashscreen_49, R.drawable.p_wave_spashscreen_50, R.drawable.p_wave_spashscreen_51, R.drawable.p_wave_spashscreen_52, R.drawable.p_wave_spashscreen_53, R.drawable.p_wave_spashscreen_54, R.drawable.p_wave_spashscreen_55, R.drawable.p_wave_spashscreen_56, R.drawable.p_wave_spashscreen_57, R.drawable.p_wave_spashscreen_58, R.drawable.p_wave_spashscreen_59}; private Paint paint; private long nextDrawTimeStamp; private boolean init = false, isStarted = false; private Bitmap original, result; private Rect mImageViewRect; private int index = 0; private LogAndStat las; private Canvas mCanvas; private final int timeTick = 50; public WaveFillingImageView(Context context) { super(context); init(context); } public WaveFillingImageView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public WaveFillingImageView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context); } @DebugLog private void init(Context context) { paint = new Paint(Paint.ANTI_ALIAS_FLAG); paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN)); las = new LogAndStat("View", mSplashAnimFrames.length); } public void start() { isStarted = true; nextDrawTimeStamp = System.currentTimeMillis(); invalidate(); } @DebugLog @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); // Before Layout if (getWidth() == 0 || getHeight() == 0) return; // Init variables if (!init) { las.logStamp("init onDraw"); original = ImageManager.decodeSampledBitmapFromResourcewithUIL(getResources(), R.drawable.p_log_android, getWidth(), getHeight()); result = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.ARGB_4444); mCanvas = new Canvas(result); mImageViewRect = new Rect(0, 0, getWidth(), getHeight()); init = true; las.logStamp("init onDraw"); } // If tick reached for refresh if (System.currentTimeMillis() >= nextDrawTimeStamp) { nextDrawTimeStamp += timeTick; las.logStamp(index); Bitmap mask = ImageManager.decodeSampledBitmapFromResourcewithUIL(getResources(), getResourceForNextCycle(index), mImageViewRect.width(), mImageViewRect.height()); mCanvas.drawBitmap(original, null, mImageViewRect, null); mCanvas.drawBitmap(mask, null, mImageViewRect, paint); canvas.drawBitmap(result, 0, 0, null); index++; } if (isStarted) // Invalidate during animation to call again on Draw if (index < mSplashAnimFrames.length) { las.logStamp("invalidate"); invalidate(); } else { las.logStats(); } } @DebugLog private int getResourceForNextCycle(int index) { if (index < (mSplashAnimFrames.length - 1)) index++; else index = mSplashAnimFrames.length - 1; return mSplashAnimFrames[index]; } @DebugLog @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, widthMeasureSpec); } }
Resultados:
- La animación se ahoga, y parece que toma menos recursos. Sin embargo, está completamente sin sincronizar con la animación de diseño. Necesidad de hacer eso. ¿Cuales son las mejores prácticas?
- Éste es claramente el paso init del método
onDraw
que toma tiempo en el primer ciclo - Trabajando en lienzo temporal para finalmente dibujar el lienzo en el lienzo de la vista principal mejoró mucho
- Appengine conectado proyecto android muerto a la llegada
- ¿Qué desencadena (o genera) KeyEvent.ACTION_MULTIPLE?