Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
206 views
in Technique[技术] by (71.8m points)

android - Error when refreshing View on top of SurfaceView

I met the problem when I want to display a normal view object on top a surfaceview. The problem is: If I set the visibility of the normal view to invisible in the layout xml file, the refreshing of the view is not correct - the overlapped area of view and surface view cannot be updated. If I set the visibility of the normal view to visible in the layout xml, there is no problem.

Here is my test code:

package com.test;

import java.io.IOException;


import android.app.Activity;
import android.media.MediaPlayer;
import android.media.MediaPlayer.OnPreparedListener;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
import android.view.View;
import android.widget.LinearLayout;


public class TESTActivity extends Activity implements Callback, OnPreparedListener {
    private SurfaceView mSurface1;
    private SurfaceHolder mSurfaceHolder1;
    private MediaPlayer mMediaPlayer1;
    private LinearLayout mLayout;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        mLayout = (LinearLayout) findViewById(R.id.channel_subscribe);

        new Handler() {
            @Override
            public void handleMessage(Message m) {
                if(mLayout.getVisibility() == View.INVISIBLE)
                    mLayout.setVisibility(View.VISIBLE);
                else
                    mLayout.setVisibility(View.INVISIBLE);
                this.sendEmptyMessageDelayed(0, 4000);
            } 
        }.sendEmptyMessageDelayed(0, 4000);

        mSurface1 = (SurfaceView) findViewById(R.id.video_surface);
        mSurfaceHolder1 = mSurface1.getHolder();
        mSurfaceHolder1.addCallback(this);
        mSurfaceHolder1.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

        mMediaPlayer1 = new MediaPlayer();
        mMediaPlayer1.setOnPreparedListener(this);

        try {
            mMediaPlayer1.setDataSource("/sdcard/d4.avi");
        } catch (IllegalArgumentException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalStateException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
        // TODO Auto-generated method stub

    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        Log.w("XXXXX", "Surface1 created");
        mMediaPlayer1.setDisplay(holder);
        mMediaPlayer1.prepareAsync();

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder arg0) {
        // TODO Auto-generated method stub

    }

    @Override
    public void onPrepared(MediaPlayer mp) {
        Log.w("XXXXX", "Mediaplayer prepared");
        mp.start();
    }
}

And here is the layout file:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout android:layout_width="fill_parent" android:layout_height="fill_parent"
  xmlns:android="http://schemas.android.com/apk/res/android">
    <SurfaceView android:id="@+id/video_surface"
        android:layout_width="480dip" 
        android:layout_height="270dip"
        android:layout_marginLeft="180dip"
        android:layout_marginTop="40dip"
        />
    <LinearLayout android:id="@+id/channel_subscribe" android:visibility="invisible" android:orientation="vertical" android:background="#bb161616" android:layout_width="436.0sp" android:layout_height="148.0sp" android:layout_alignParentBottom="true">
      <TextView android:textSize="14.0dip" android:textStyle="normal" android:textColor="#ffb7b7b7" android:id="@+id/subscribe_title" android:layout_width="wrap_content" android:layout_height="70.0sp" android:layout_marginLeft="38.0sp" android:layout_marginTop="18.0sp" android:layout_marginRight="34.0sp" android:text="We Hope you enjoyed the channel preview. To subscribe this channel, please press the button below." />
      <Button android:id="@+id/subscribe_now_button" android:layout_width="184.0sp" android:layout_height="42.0sp" android:layout_marginLeft="38.0sp" android:layout_marginRight="34.0sp" android:layout_marginBottom="18.0sp" android:text="SubscribeNow" />
     </LinearLayout>



</RelativeLayout>
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Problem solved.

the course is:

  1. The subscribe dialog widget is initialized as invisible during inflating the activity layout.
  2. And then the SurfaceView used for playing video is attached to the activity window.
  3. When the SurfaceView invokes mParent.requestTransparentRegion(this); in the callback onAttachedToWindow(), the dialog widget is invisible
  4. When ViewRoot calculate the transparent region, the overlapped area is considered invisible, and then the painting of the area is incorrect.

To fix this issue, please call requestTransparentRegion when you change the visibility of the widget if it is not visible when SurfaceView is attached to window.

For example, you can call mWidget.getParent().requestTransparentRegion(mSurfaceView).

Since the ViewRoot is the root parent of the view hierachy, this will take the same effect to call SurfaceView’s parent to request transparentRegion.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...