从片段访问主要活动视图

时间:2015-12-28 16:06:52

标签: java android android-fragments android-activity

我有一个包含片段的容器的活动,这个片段还有其他片段。

现在我希望第二个或子片段访问主活动中的视图,但它返回空指针异常。

类:

public class ImageListFragment extends AbsListViewBaseFragment   implements  ObservableScrollViewCallbacks {

public static final int INDEX = 0;




android.support.design.widget.FloatingActionButton mFab;

@Bind(R.id.ic_call)
ImageView mIcCall;
@Bind(R.id.ic_email)
ImageView mIcEmail;
@Bind(R.id.ic_forum)
ImageView mIcForum;
FabToolbar mFabToolbar;
ObservableListView mObservableListView;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
    View rootView = inflater.inflate(R.layout.fr_image_list, container, false);
    listView = (ListView) rootView.findViewById(android.R.id.list);
    ((ListView) listView).setAdapter(new ImageAdapter(getActivity()));

    final SubTaB mainActivity = (SubTaB)getActivity();
    ButterKnife.bind(mainActivity);
      //////////////// problem here 
     mFabToolbar = (FabToolbar) rootView.findViewById(R.id.fabtoolbar);  
      ////////////////
    getFragmentManager().findFragmentByTag("TAG");
        //  rootView.findViewById(R.id.fab);
    mObservableListView = (ObservableListView)rootView.findViewById(android.R.id.list);
    //


     mObservableListView.setAdapter(this.listView.getAdapter());
   mObservableListView.setScrollViewCallbacks(this);



    mainActivity.mFab.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Toast.makeText(mainActivity.getApplicationContext(), "msg msg", Toast.LENGTH_LONG).show();
            mainActivity.mFabToolbar.expandFab();
        }
    });



    listView.setOnItemClickListener(new OnItemClickListener() {
        @Override
        public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

            startImagePagerActivity(position);
        }
    });
    return rootView;
}

@Override
public void onDestroy() {
    super.onDestroy();
    AnimateFirstDisplayListener.displayedImages.clear();
}

private static class ImageAdapter extends BaseAdapter {

    private static final String[] IMAGE_URLS = Constants.IMAGES;

    private LayoutInflater inflater;
    private ImageLoadingListener animateFirstListener = new AnimateFirstDisplayListener();

    private DisplayImageOptions options;

    ImageAdapter(Context context) {
        inflater = LayoutInflater.from(context);

        options = new DisplayImageOptions.Builder()
                .showImageOnLoading(R.drawable.ic_stub) // تغيير الفيو قبل تحميل الصورة
                .showImageForEmptyUri(R.drawable.ic_empty) // لما الصورة فاضية
                .showImageOnFail(R.drawable.ic_error) // عند الفشل
                .cacheInMemory(true)
                .cacheOnDisk(true)
                .considerExifParams(true)
                .displayer(new CircleBitmapDisplayer(Color.WHITE, 5))
                .build();
    }

    @Override
    public int getCount() {
        return IMAGE_URLS.length;
    }

    @Override
    public Object getItem(int position) {
        return position;
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        View view = convertView;
        final ViewHolder holder;
        if (convertView == null) {
            view = inflater.inflate(R.layout.item_list_image, parent, false);
            holder = new ViewHolder();
            holder.text = (TextView) view.findViewById(R.id.text);
            holder.image = (ImageView) view.findViewById(R.id.image);
            view.setTag(holder);
        } else {
            holder = (ViewHolder) view.getTag();
        }

        holder.text.setText("Item " + (position + 1));



        ImageLoader.getInstance().displayImage(IMAGE_URLS[position], holder.image, options, animateFirstListener);

        return view;
    }
}

static class ViewHolder {
    TextView text;
    ImageView image;
}



@Override
public void onScrollChanged(int i, boolean b, boolean b1) {

}

@Override
public void onDownMotionEvent() {

}

@Override
public void onUpOrCancelMotionEvent(ScrollState scrollState) {
    Log.d("","Scroll scroll scroll");

    if (scrollState == ScrollState.UP) {
        mFabToolbar.slideOutFab();
    } else if (scrollState == ScrollState.DOWN) {
        mFabToolbar.slideInFab();
    }
}

@OnClick(R.id.fab)
void onFabClick() {
    mFabToolbar.expandFab();
}

@OnClick(R.id.call)
void onClickCall() {
    iconAnim(mIcCall);
}

@OnClick(R.id.ic_email)
void onClickEmail() {
    iconAnim(mIcEmail);
}

@OnClick(R.id.ic_forum)
void onClickForum() {
    iconAnim(mIcForum);
}

private void iconAnim(View icon) {
    Animator iconAnim = ObjectAnimator.ofPropertyValuesHolder(
            icon,
            PropertyValuesHolder.ofFloat("scaleX", 1f, 1.5f, 1f),
            PropertyValuesHolder.ofFloat("scaleY", 1f, 1.5f, 1f));
    iconAnim.start();
}







private static class AnimateFirstDisplayListener extends SimpleImageLoadingListener {

    static final List<String> displayedImages = Collections.synchronizedList(new LinkedList<String>());

    @Override
    public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
        if (loadedImage != null) {
            ImageView imageView = (ImageView) view;
            boolean firstDisplay = !displayedImages.contains(imageUri);
            if (firstDisplay) {
                FadeInBitmapDisplayer.animate(imageView, 500);
                displayedImages.add(imageUri);
            }
        }
    }
}
}

2 个答案:

答案 0 :(得分:2)

以这种方式查找和控制视图不是一个好习惯。视图很容易与活动分离并导致意外异常。

如果需要,您应该考虑使用回调来在片段和活动之间进行通信。这样,它还可以将代码保存在正确的位置 - 因此活动是唯一触及自己视图的活动,片段也只触及自己的视图。它只是告诉活动(通过回调)活动可能想要了解的事情。它还确保碎片完全自包含,并且可以轻松重复使用。

您可以在此处阅读有关如何实施回调的信息:com.google.activity.sample

答案 1 :(得分:1)

使用EventBus在活动和片段之间进行通信。 riggarro建议是正确的方法。但您也可以使用EventBus更新基本活动视图。

例如,我们需要更新片段中活动中的TextView文本,然后按照步骤操作。

  1. 首先,您需要将以下库作为依赖项添加到build.gradle的{​​{1}}项目中。
  2.   

    编译'de.greenrobot:eventbus:2.4.0'

    1. 首先,您需要创建一个事件对象类,以便在片段和活动之间进行通信,如下所示。
    2. app
      1. 您需要将事件发布到片段中的事件总线,以更新活动中的public class UpdateTextEvent { private String sampleTextValue; public UpdateTextEvent(String textValue) { this.sampleTextValue = textValue; } public String getTextValue() { return sampleTextValue; } }
      2. TextView
        1. 之后,你需要在下面的活动中在事件回调中注册
        2. public class TestingFragment extends Fragment{
              private EventBus bus = EventBus.getDefault()
              public TextingFragment(){}
              public void onCreate(Bundle onSavedInstanceState){
                  super.onCreate(onSavedInstanceState);
              }
              public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle savedInstanceState){
                  View v = inflater.inflate(R.layout.sample_activity, parent, false);
                  ...
                  Button b1 = (Button) v.findViewById(R.id.button1);
                  b1.setOnClickListener(new View.OnClickListener() {
                      @Override
                      public void onClick(View v) {
                          //trigger a update to the activity
                          bus.post(new UpdateTextEvent("testing"));
                      }
                  });
              }
          }
          

          在上面的示例中,当您从片段发布事件时,将调用public class MainActivity extends Activity{ private EventBus bus = EventBus.getDefault(); private TextView textView; @Override public void onCreate(Bundle onSavedInstanceState){ super.onCreate(onSavedInstanceState); .... // The textview going to be updated on posting the event textView = (TextView) findViewById(R.id.text1); bus.register(this); } public void onEvent(UpdateTextEvent event){ textView.setText(event.getTextValue()); } } 方法。

          希望它会对你有所帮助。