Android 使用自定义视图保留片段

Android 使用自定义视图保留片段,android,android-fragments,device-orientation,Android,Android Fragments,Device Orientation,我正在写一个小动画项目。我的问题是,在屏幕上的方向改变,它崩溃了。但是我发现了,所以在这里发布完整的代码,以防有人需要类似的东西。底部的最后一句解释了我观察到的一个小问题 在这个项目中,我的主要活动是托管一个片段。片段正在使用一个自定义的气泡视图(气泡扩展视图) 主要活动布局活动_Main.xml是: <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.androi

我正在写一个小动画项目。我的问题是,在屏幕上的方向改变,它崩溃了。但是我发现了,所以在这里发布完整的代码,以防有人需要类似的东西。底部的最后一句解释了我观察到的一个小问题

在这个项目中,我的主要活动是托管一个片段。片段正在使用一个自定义的气泡视图(气泡扩展视图)

主要活动布局活动_Main.xml是:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:id="@+id/bubble_fragment">

</LinearLayout> 
因此,我的主要活动包含一个带有自定义视图的片段。片段布局bubble_fragment.xml为:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:background="#ffcc33">

    <study.android.dino.testsolar.Bubble
        android:id="@+id/bubbleAnimationView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="#ff1122"
        android:padding="20dp"/>

    <!-- since parent is FrameLayout, this view will be stacked up in z-order -->
    <LinearLayout
        android:id="@+id/buttonsView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_gravity="right|bottom"
        android:layout_margin="10dp">

        <ImageButton
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:src="@mipmap/ic_launcher"
            android:background="@null"/>
        <ImageButton
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:src="@mipmap/ic_launcher"
            android:background="@null"/>
        <ImageButton
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:src="@mipmap/ic_launcher"
            android:background="@null"/>
    </LinearLayout>
</FrameLayout>
这个片段包含自定义视图气泡,它只是画布上的一个气泡图,在这里并不重要;因此,未提供完整的代码:

public class Bubble extends View {

    private static final boolean BUBBLING = true; //thread is running to draw

    private Paint paint;
    private ShapeDrawable bubble;

    // coordiantes, radius etc
    private int x;
    private int y;
    private int dx;
    private int dy;
    private int r;
    private int w = 400;
    private int h = 400;
    private int speed = 200;

    //handler to invalidate (force redraw on main GUI thread from this thread)
    private Handler handler = new Handler();

    public Bubble(Context context, AttributeSet attributesSet) {
        super(context, attributesSet);

        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        Display display = wm.getDefaultDisplay();
        Point size = new Point();
        display.getSize(size);
        w = size.x;
        h = size.y;

        x = w/2;
        y = h/2;
        r = 60;
        dx = 1;
        dy = 1;

        bubble = new ShapeDrawable(new OvalShape());
        bubble.getPaint().setColor(Color.RED);
        bubble.setBounds(0, 0, r, r);

        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setStrokeWidth(10);
    }

    @Override
    protected void onSizeChanged  (int w, int h, int oldw, int oldh){
        //set bubble parameters (center, size, etc)

        startAnimation();
    }

    public void startAnimation(){
        new Thread(new Runnable() {
            public void run() {
                while (BUBBLING) {
                    moveBubble();

                    try {
                        Thread.sleep(speed);
                    } catch (InterruptedException e) {

                    }

                    //update by invalidating on main UI thread
                    handler.post(new Runnable() {
                        public void run() {
                            invalidate();
                        }
                    });
                }
            }
        }).start();
    }


    @Override
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        canvas.save();
        // draws bubble on canvas
        canvas.translate(dx, dy);
        bubble.draw(canvas);
        canvas.restore();
    }

    private void moveBubble(){
        dx += 1;
        dy += 1;
        x = x + dx;
        y = y + dy;
        if (bubble.getPaint().getColor() == Color.YELLOW){
            bubble.getPaint().setColor(Color.RED);
        } else {
            bubble.getPaint().setColor(Color.YELLOW);
        }
    }
}
这一切都起作用了,我的泡泡在屏幕上绘制和移动,方向也起作用了。我观察到的唯一“小”问题是,根据上面的代码,气泡的绘制速度设置为200ms。然而,当我改变方向时,气泡闪烁得更快,尽管跟踪代码痛斥速度仍然是200。不知道为什么会这样


谢谢

我更新了我的原始帖子以展示解决方案。

你应该在框架布局中添加片段,而不是线性布局(id bubble_fragment)。顺便说一句,只要配置/方向发生变化,视图对象就不会被保留和销毁。您确定已从“活动”中还原片段吗?您的活动中缺少保存片段的代码。请确保存储片段的行存在于onSaveInstanceState中。这里是一个代码的例子如何可以做到这一点,请让我知道它是否适用于you@ProblemSlover谢谢,但那不是我想要的。需要LinearLayour,片段通过我的自定义视图添加。另外,我知道onSaveInstanceState,但这是我所做工作的简化版本,我不想保存这么多东西。保留应该是有效的,它更简单,这是我目前所需要的。感谢您的帮助和分享链接。将单个片段添加到linearlayout不会对framelayout造成太多差异,FYIIndeed。正在属性内存储视图。。我正要提出这个建议,但我觉得很尴尬,因为这只是一个假设:)
public class BubbleFragment extends Fragment {

    View view;
    Bubble bubble;
    FrameLayout parent;
    LinearLayout floater;


    @Override
    public void onCreate(Bundle savedInstanceState){
        super.onCreate(savedInstanceState);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        if (bubble == null){
            view =  inflater.inflate(R.layout.bubble_fragment, container, false); 
            parent = (FrameLayout) view;
        }

        return view;
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState){
        super.onActivityCreated(savedInstanceState);
        setRetainInstance(true);
    }

    @Override
    public void onAttach(Activity activity){
        super.onAttach(activity);

        if (parent != null){
            parent.addView(bubble);
            parent.addView(floater);
        }
    }

    @Override
    public void onDetach(){
        super.onDetach();
        bubble = (Bubble) view.findViewById(R.id.bubbleAnimationView);
        floater = (LinearLayout) parent.findViewById(R.id.buttonsView);
        parent.removeView(bubble);
        parent.removeView(floater);
    }
}
public class Bubble extends View {

    private static final boolean BUBBLING = true; //thread is running to draw

    private Paint paint;
    private ShapeDrawable bubble;

    // coordiantes, radius etc
    private int x;
    private int y;
    private int dx;
    private int dy;
    private int r;
    private int w = 400;
    private int h = 400;
    private int speed = 200;

    //handler to invalidate (force redraw on main GUI thread from this thread)
    private Handler handler = new Handler();

    public Bubble(Context context, AttributeSet attributesSet) {
        super(context, attributesSet);

        WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
        Display display = wm.getDefaultDisplay();
        Point size = new Point();
        display.getSize(size);
        w = size.x;
        h = size.y;

        x = w/2;
        y = h/2;
        r = 60;
        dx = 1;
        dy = 1;

        bubble = new ShapeDrawable(new OvalShape());
        bubble.getPaint().setColor(Color.RED);
        bubble.setBounds(0, 0, r, r);

        paint = new Paint();
        paint.setAntiAlias(true);
        paint.setStrokeWidth(10);
    }

    @Override
    protected void onSizeChanged  (int w, int h, int oldw, int oldh){
        //set bubble parameters (center, size, etc)

        startAnimation();
    }

    public void startAnimation(){
        new Thread(new Runnable() {
            public void run() {
                while (BUBBLING) {
                    moveBubble();

                    try {
                        Thread.sleep(speed);
                    } catch (InterruptedException e) {

                    }

                    //update by invalidating on main UI thread
                    handler.post(new Runnable() {
                        public void run() {
                            invalidate();
                        }
                    });
                }
            }
        }).start();
    }


    @Override
    public void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        canvas.save();
        // draws bubble on canvas
        canvas.translate(dx, dy);
        bubble.draw(canvas);
        canvas.restore();
    }

    private void moveBubble(){
        dx += 1;
        dy += 1;
        x = x + dx;
        y = y + dy;
        if (bubble.getPaint().getColor() == Color.YELLOW){
            bubble.getPaint().setColor(Color.RED);
        } else {
            bubble.getPaint().setColor(Color.YELLOW);
        }
    }
}