【问题标题】:Retaining Fragment保留碎片
【发布时间】:2015-10-17 10:01:09
【问题描述】:

我正在编写一个可以在 Canvas 上绘制气泡的应用程序。 我有 MainActivity,它的布局是一个简单的 LinearLayout,我用它作为片段的持有者。 当我在 Canvas 上绘图时,我的片段没有 xml 布局,所以我以编程方式设置它的布局,如下所示:

public class BubbleFragment extends Fragment {

    Bubble bubble;

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

        //retain fragment
        setRetainInstance(true);

        //bubble = new Bubble(getActivity()); //THIS WILL CRASH APP, MOVE TO onCreateView instetad
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT,
                ViewGroup.LayoutParams.MATCH_PARENT,
                100);
        LinearLayout ll = new LinearLayout(getActivity());
        ll.setOrientation(LinearLayout.VERTICAL);

        // instantiate my class that does drawing on Canvas
        bubble = new Bubble(getActivity());
        bubble.setLayoutParams(lp);
        bubble.setBackgroundColor(Color.BLUE);
        ll.addView(bubble);  //if you create bubble in onCreate() this will crash.  Create bubble in onCreateView

        return ll;
    }
}

所以,当我启动我的应用程序时,我希望气泡会显示在屏幕中间并缓慢地向底部移动。因为我在上面使用了 setRetainInstance(true),所以我希望当我旋转屏幕时,气泡会在旋转之前从它离开的地方继续。但是,它会在其初始位置(屏幕中间)重绘。

我想从屏幕方向改变之前的位置继续绘制自己,而不是从头开始。

这是我的气泡代码:

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;

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

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

        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(200);
                    } 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);
        }
    }
}

非常感谢,

【问题讨论】:

标签: android fragment device-orientation


【解决方案1】:

如果您真的想保留整个视图,可以执行延迟加载之类的操作:

public class BubbleFragment extends Fragment {
    Bubble bubble;
    LinearLayout parent;

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

        setRetainInstance(true);
    }

    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        parent = new LinearLayout(activity);
        if(bubble == null) {
            LinearLayout.LayoutParams lp = new LinearLayout.LayoutParams(
                    ViewGroup.LayoutParams.MATCH_PARENT,
                    ViewGroup.LayoutParams.MATCH_PARENT,
                    100);
            bubble = new Bubble(getActivity());
            bubble.setLayoutParams(lp);
            bubble.setBackgroundColor(Color.BLUE);
        }
        parent.setOrientation(LinearLayout.VERTICAL);
        parent.addView(bubble);
    }

    @Override
    public void onDetach() {
        super.onDetach();
        parent.removeView(bubble);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
    {
        return parent;
    }
}

【讨论】:

  • 这行得通,但为什么要在 onAttach() 中创建 2ice LinearLayour?我想说它应该只在气泡为空时创建
  • 那就继续吧
  • 我发布了另一个问题,但只是略有不同。我没有以编程方式创建布局,而是添加了托管我的自定义视图 Bubble 的布局文件。在这里stackoverflow.com/questions/33194087/… 知道在这种情况下我将如何实现保留。我相信你关于延迟加载的建议会奏效,但我正试图绕过它,但收效甚微。非常感谢。
  • 你看过我发布的关于片段生命周期的文章吗?
  • 其实没有,我都没看到。我刚才看到你指出你发了一篇文章。会检查的,谢谢。顺便说一句,我知道新帖子缺少 onAttach/Detach,但原因是我不知道如何处理 onAttach() 中的情况,因为我正在为我的片段使用 xml 布局,而不是像这里那样以编程方式创建布局。这就是为什么我没有在上面提到的新帖子中添加 onAttach()/onDetach()。
【解决方案2】:

在您的情况下,您不需要 setRetainInstance(true),您只需将实例变量保存在 onSaveInstanceState() 中并在 onCreate() 中加载它们。对于您的示例,例如:

public void onCreate(Bundle b) {
    super.onCreate(b);
    if(b != null) {
        xPos = b.getInt("x");
        yPos = b.getInt("y");
    }
}

public void onSaveInstanceState(Bundle b) {
    super.onSaveInstanceState(b);
    b.putInt("x",xPos);
    b.putInt("y",yPos);
}

顺便说一句,您不能在 onCreate() 中创建 Bubble 的原因是,在调用 onActivityCreated() 之前,Fragment 与其 Activity 没有完全关联,而 onActivityCreated() 是在调用 onCreate() 之后发生的。

【讨论】:

  • 我知道onSaveInstanceState,但由于变量很多,我认为简单地保留片段就可以解决它。根据文档,保留也应该有效。不过感谢您的解释。
猜你喜欢
  • 2018-10-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-21
  • 2013-08-14
相关资源
最近更新 更多