Android Fragment顶级布局无法以编程方式访问

时间:2015-08-22 10:17:06

标签: android android-layout android-fragments

我无法通过其xml中布局的id到达片段的顶级',结果证明它是一个空对象。但我可以访问其子视图的父级。那个父母不是布局本身,而是“包含布局”。当我以编程方式将子项添加到此片段时,它们不会与已存在的子项对齐,建议实际上这些子项位于嵌套布局中。

这种行为真的让我感到困惑。谁能解释一下发生了什么?

我声明了一个顶级碎片布局,如下所示:

  

为了便于阅读而剥离了同级片段和布局设置

private void takePicture() {
    openCamera();
    //System.gc();
    camera.startPreview();
    new Handler().postDelayed(new Runnable() {

        @Override
        public void run() {
            camera.takePicture(
                    new ShutterCallback() {

                        @Override
                        public void onShutter() {
                            // TODO Do something when the shutter closes.
                        }
                    }, new PictureCallback() {

                        @Override
                        public void onPictureTaken(byte[] _data, Camera _camera) {

                        }
                    }, new PictureCallback() {

                        @Override
                        public void onPictureTaken(byte[] _data, Camera _camera) {
                            // TODO Do something with the image JPEG data.
                            Bitmap bitmap = BitmapFactory.decodeByteArray(_data, 0, _data.length);
                            imgPicture.setImageBitmap(bitmap);
                            Toast.makeText(TakePhotoActivity.this, "Length = " + _data.length, Toast.LENGTH_SHORT).show();
                            ByteArrayOutputStream bytes = new ByteArrayOutputStream();
                            bitmap.compress(Bitmap.CompressFormat.JPEG, 40, bytes);
                            File f = new File(Environment.getExternalStorageDirectory()
                                    + File.separator + "test.jpg");

                            // remember close de FileOutput
                            try {
                                f.createNewFile();
                                FileOutputStream fo = new FileOutputStream(f);
                                fo = new FileOutputStream(f);
                                fo.write(bytes.toByteArray());
                                fo.close();
                            }
                            catch (IOException e) {
                                // TODO Auto-generated catch block
                                e.printStackTrace();
                            }
                            CloseCamera();
                        }
                    });
        }
    }, 1000);
}

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/main_view" > <fragment android:layout_gravity="center_horizontal|center_vertical" android:layout_width="match_parent" android:layout_height="0dp" android:layout_marginTop="40dp" android:layout_weight="0.3" android:name="foo.bar.foobar.fragments.ShowWeightsFragment" android:id="@+id/show_weights_fragment" tools:layout="@layout/frag_show_weights" /> </LinearLayout> 定义如下:

layout/frag_show_weights

MainActivity.java如下所示

<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:id="@+id/layout_container_weights"
>

    <TextView
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:textAppearance="?android:attr/textAppearanceSmall"
    android:text="Foo"
    android:id="@+id/xmlTextChildren"
    android:layout_gravity="center" />

</LinearLayout>

日志输出如下:

  

08-22 12:06:24.855:D / MainActivity(2346):ID的布局为空

     

08-22 12:06:24.856:D / MainActivity(2346):ID父名:show_weights_fragment

实际的模拟器输出显示两个文本没有对齐,这使我假设它们不包含在同一个protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); TextView t = (TextView) findViewById(R.id.xmlTextChildren); t.setText("Foo"); LinearLayout parentLayout = (LinearLayout) findViewById(R.id.xmlTextChildren).getParent(); LinearLayout layoutFromID = (LinearLayout) findViewById(R.id.layout_container_weights); TextView v = new TextView(this); v.setText("Bar"); if (layoutFromID == null) Log.d(TAG, "Layout from ID is null"); Log.d(TAG, "ID parent name: " + getResources().getResourceEntryName(parentLayout.getId())); parentLayout.addView(v); } The emulated output on Android 5.22 running on a Nexus 5

2 个答案:

答案 0 :(得分:2)

简答:如果您在R.id.show_weights_fragment内设置了ID,请使用您的片段的ID <fragment>来访问其视图。

The documentation for Fragments有一个关于片段处理ID的声明:

  

注意:每个片段都需要一个唯一的标识符,如果重新启动活动,系统可以使用该标识符来恢复片段(您可以使用它来捕获片段以执行事务,例如删除它)。有三种方法可以为片段提供ID:

     
      
  • 使用唯一ID提供android:id属性。
  •   
  • 使用唯一字符串提供android:tag属性。
  •   
  • 如果您不提供前两个,系统将使用容器视图的ID。
  •   

如果设置了片段的id,这就会激发假设,即它只是反过来。我无法找到关于此的文档,但是the sources for FragmentManagerImpl表明,这个假设成立:

public View onCreateView(View parent, String name, Context context, AttributeSet attrs) {
    if (!"fragment".equals(name)) {
        return null;
    }

    [...]

    int id = a.getResourceId(com.android.internal.R.styleable.Fragment_id, View.NO_ID);
    String tag = a.getString(com.android.internal.R.styleable.Fragment_tag);

    [...]

    if (id != 0) {
        fragment.mView.setId(id);
    }
    if (fragment.mView.getTag() == null) {
        fragment.mView.setTag(tag);
    }
    return fragment.mView;
}

这也是您的日志显示的内容:parentLayout.getId() == R.id.show_weights_fragment

答案 1 :(得分:0)

尝试将代码从onCreate移动到onCreateView。

来自Android doc:

“使用getSystemService(Class)返回的LayoutInflater进行充气时使用的onCreateView(View,String,Context,AttributeSet)的标准实现。此实现处理标记以在活动中嵌入片段。”