Цветные полосы и артефакты с градиентами, несмотря на повсеместное использование RGBA_8888

Мне известно, что цветовая полоса - это старый каштан проблемы, которая много раз обсуждалась ранее с различными решениями (которые, по сути, сводятся к 32-битному использованию или к сглаживанию). На самом деле не так давно яспросил и впоследствии ответил на мой собственный вопрос в соответствии с этим. Тогда я думал, что решение, которое я положил в ответ на этот вопрос (который должен применятьсяsetFormat(PixelFormat.RGBA_8888) кWindow а также кHolder в случаеSurfaceView) решил проблему в моем приложении навсегда. По крайней мере, решение сделало градиент очень красивым на устройствах, которые я разрабатывал тогда (скорее всего, Android 2.2).

Сейчас я работаю с HTC One X (Android 4.0) и Asus Nexus 7 (Android 4.1). То, что я пытался сделать, это применить серый градиент ко всей областиSurfaceView, Хотя я предположительно гарантировал, что содержащийWindow иHolder настроены на 32-битный цвет, я получаю ужасные полосы артефактов. На самом деле на Nexus 7,I even see the artifacts move about, Это происходит не только наSurfaceView который, конечно, постоянно рисует, но и в нормальномView Я добавил, чтобы нарисовать точно такой же градиент для тестирования, который бы нарисовал один раз. То, как эти артефакты присутствуют, а также, кажется, движутся, конечно, выглядит совершенно ужасно, и этоactually like viewing an analogue TV with a poor signal, ОбаView а такжеSurfaceView экспонировать точно такие же артефакты, которые движутся вместе.

Мое намерение состоит в том, чтобы использовать 32-битный код, а не использовать дизеринг. У меня сложилось впечатление, чтоWindow был 32-битным по умолчанию задолго до Android 4.0. ПрименяяRGBA_8888 вSurfaceView Я бы ожидал, что все будет 32-битным, что позволит избежать любых артефактов.

Я отмечаю, что есть некоторые другие вопросы относительно SO, когда люди заметили, чтоRGBA_8888 больше не кажется эффективным на платформах 4.0 / 4.1.

Это скриншот с моего Nexus 7, с нормальнымView на вершине иSurfaceView ниже, оба применяют один и тот же градиент кCanvas, Конечно, он не показывает артефакты так же хорошо, как при просмотре дисплея, и поэтому, вероятно, показывать этот снимок экрана довольно бессмысленно. Я хочу подчеркнуть, что на экране Nexus полоса действительно выглядит ужасно.Edit: На самом деле, скриншот действительно не показывает артефактыat all, Артефакты, которые я вижу на Nexus 7, не являются равномерной полосой; это выглядит случайным по своей природе.

enter image description here

ТестActivity используется для создания выше:

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.Shader;
import android.os.Bundle;
import android.os.Handler;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.WindowManager;
import android.view.SurfaceHolder.Callback;
import android.widget.LinearLayout;

public class GradientTest extends Activity {

    @Override
    public void onAttachedToWindow() {
        super.onAttachedToWindow();
        getWindow().setFormat(PixelFormat.RGBA_8888);
    }


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);      
        WindowManager.LayoutParams lp = new WindowManager.LayoutParams();
        lp.copyFrom(getWindow().getAttributes());
        lp.format = PixelFormat.RGBA_8888;
        getWindow().setAttributes(lp);     
        LinearLayout ll = new LinearLayout(this);
        LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(500,500);
        params.setMargins(20, 0, 0, 0);
        ll.addView(new GradientView(this), params);    
        ll.addView(new GradientSurfaceView(this), params);
        ll.setOrientation(LinearLayout.VERTICAL);
        setContentView(ll);
    }


    public class GradientView extends View {

        public GradientView(Context context) {
            super(context);     
        }

        @Override
        protected void onDraw(Canvas canvas) {

            Paint paint = new Paint();
            paint.setStyle(Paint.Style.FILL);
            paint.setAntiAlias(false);
            paint.setFilterBitmap(false);
            paint.setDither(false); 
            Shader shader = new LinearGradient(
                    0,
                    0,
                    0,
                    500,
                    //new int[]{0xffafafaf, 0xff414141},
                    new int[]{0xff333333, 0xff555555},
                    null,

                    Shader.TileMode.CLAMP
                    );

            paint.setShader(shader);    
            canvas.drawRect(0,0,500,500, paint);
        }       
    }




    public class GradientSurfaceView extends SurfaceView implements Callback {

        public GradientSurfaceView(Context context) {
            super(context);

            getHolder().setFormat(PixelFormat.RGBA_8888); // Ensure no banding on gradients 
            SurfaceHolder holder = getHolder();
            holder.addCallback(this);    
        }


        Paint paint;
        private GraphThread thread;

        @Override
        public void surfaceCreated(SurfaceHolder holder) {
            holder.setFormat(PixelFormat.RGBA_8888); // Ensure no banding on gradients    

            paint = new Paint();
            paint.setStyle(Paint.Style.FILL);
            paint.setAntiAlias(false);
            paint.setFilterBitmap(false);
            paint.setDither(false); 

            Shader shader = new LinearGradient(
                    0,
                    0,
                    0,
                    500,
                    //new int[]{0xffafafaf, 0xff414141},
                    new int[]{0xff333333, 0xff555555},
                    null,
                    Shader.TileMode.CLAMP
                    );


            paint.setShader(shader);  



            thread = new GraphThread(holder, new Handler() );
            thread.setName("GradientSurfaceView_thread");
            thread.start();
        }

        class GraphThread extends Thread {

            /** Handle to the surface manager object we interact with */
            private SurfaceHolder mSurfaceHolder;   

            public GraphThread(SurfaceHolder holder, Handler handler) {
                mSurfaceHolder = holder;
                holder.setFormat(PixelFormat.RGBA_8888); // Ensure no banding on gradients  
            }

            @Override
            public void run() {

                Canvas c = null;

                while (true) {

                    try {
                        c = mSurfaceHolder.lockCanvas();

                        synchronized (mSurfaceHolder) {

                            if (c != null){


                                c.drawRect(0,0,500,500, paint);

                            }
                        }                                 
                    } 

                    finally {
                        if (c != null) {
                            mSurfaceHolder.unlockCanvasAndPost(c);
                        }
                    }
                }
            }    

        }

        @Override
        public void surfaceChanged(SurfaceHolder holder, int format, int width,
                int height) {

        }

        @Override
        public void surfaceDestroyed(SurfaceHolder holder) {

        }
    }


}

Я установил приложение под названием Display Tester из Google Play. Это приложение может быть использовано для создания тестовых градиентов на экране. Хотя его градиенты не выглядят идеально, они кажутся немного лучше, чем то, что я смог достичь, что заставляет меня задуматься, есть ли еще какие-то меры, которые я могу сделать, чтобы предотвратить образование полос.

Еще одна вещь, которую я хочу отметить, заключается в том, что приложение Display Tester сообщает, что мой Nexus & apos; Экран 32-битный.

Для информации я явно включаю аппаратное ускорение. Мои уровни SDK:

 <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="15"></uses-sdk>

Еще одна вещь, которую я заметил, это то, что по умолчанию градиентный фон дляActivityчто, как я понимаю, является особенностью Холо, тоже очень скандально. Это также вообще не показано на скриншоте. И я также только что заметил, что на моем Nexus 7 ненадолго движется полосатость фона, сочувствуя движению полос в моих двухViews, Если я создаю совершенно новый проект Android с «пустым» по умолчаниюActivity,Activity показывает неприятный полосатый градиентный фон на моем Nexus и HTC One X. Это нормально? Я понимаю, что этот черный / фиолетовый градиентный фон по умолчаниюActivity должен иметь, если аппаратное ускорение включено. Ну, независимо от того, включено аппаратное ускорение или нет, я вижу, что все же противный полосатыйActivity фоновый градиент. Это даже происходит в моем пустом тестовом проекте, целевой SDK которого составляет 15. Чтобы уточнить, способ, которым я включаю или отключаю аппаратное ускорение, явно используетandroid:hardwareAccelerated="true" а такжеandroid:hardwareAccelerated="false".

Я не уверен, что мое наблюдение о Холо черный / фиолетовыйActivity градиентный фон имеет какое-то отношение к моему первичному вопросу, но кажется странно связанным. Также странно, что он выглядит таким плохим качеством (т.е. полосатым) и выглядит одинаково независимо от того, включено ли аппаратное ускорение. Итак, второстепенный вопрос будет: когда у вас естьActivity с заданным по умолчанию фоном градиента Holo, и для каждого случая аппаратного ускорения, включающего и затем отключающего Explicity, должен ли этот градиентный фон (a) присутствовать и (b) выглядеть идеально гладким? Я хотел бы задать это в отдельном вопросе, но опять же, похоже, связано.

So, in summary: Основная проблема у меня заключается в том, что применение градиентного фона кSurfaceView кажется, просто не может быть сделано на моем Nexus 7. Это проблема не просто бандинга, с которой я мог бы смириться, если бы это было просто так; это фактически тот факт, что полосатость является случайной по своему характеру при каждом розыгрыше. Это означает, чтоSurfaceView это постоянно перерисовывает, заканчивает тем, что имел движущийся, нечеткий фон.

Ответы на вопрос(4)

Ваш ответ на вопрос