-2

i am trying to hide/show Button in fragment from Activity but it give me following exception.

android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.

Home Activity

 public class HomeActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);
        CategoryFragment frag=(CategoryFragment) activity.getSupportFragmentManager() 
                                  .findFragmentByTag("cat_frag");
        Button newDesigns= (Button) frag.getView().findViewById(R.id.new_designs);
        newDesigns.setVisibility(View.VISIBLE);
     }
 }

Category Fragment

 public class CategoryFragment extends Fragment{
    Button newDesigns;
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        View v = inflater.inflate(R.layout.fragment_category, null);
        newDesigns= (Button) v.findViewById(R.id.new_designs);
   }
}
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#CCCCCC">

    <TextView
        android:id="@+id/list_name"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:background="@drawable/shape_logo_bg"
        android:gravity="center"
        android:padding="5dp"
        android:textColor="@android:color/white"
        android:textSize="18sp" />

    <Button
        android:id="@+id/new_designs"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@id/list_name"
        android:background="@color/edit_button_color"
        android:padding="10dp"
        android:text="@string/new_designs"
        android:textColor="@color/btn_text_color"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="5dp"
        android:visibility="gone"
        />
</RelativeLayout>

Code is too large to be posted here. Thats why i have only posted the code where i am finding an issue.

I am able to get newDesigns BUTTON instance.What is shocking for me is if try to play with button instance (VISIBLE/GONE) it gives me above mentioned exception.

Help is appreciated.

Ankit Ostwal
  • 1,033
  • 3
  • 14
  • 32
  • Similar questions have been asked many times ! Refrain from asking similar questions ! – Abhinav Arora Jul 22 '16 at 06:24
  • see this link http://stackoverflow.com/questions/20124557/disable-button-in-fragment-from-main-activity – Vivek Mishra Jul 22 '16 at 06:25
  • 1
    Possible duplicate of [Android "Only the original thread that created a view hierarchy can touch its views." error in Fragment](http://stackoverflow.com/questions/18656813/android-only-the-original-thread-that-created-a-view-hierarchy-can-touch-its-vi) – Abhinav Arora Jul 22 '16 at 06:27

2 Answers2

1

You shouldn't play with a view of the Fragment while you are in a Activity directly. You will not know what the view's state will be and this can potentially lead to issues you can't even think of(beleive me i faced many). To interact with the activity's views, make an interface:

public interface AccessFragmentViews{
  public void setVisibilityForButton(boolean bool);
  //any other methods that you need
}

Now implement this inside the fragment class and override the method.

class YourFragment implements AccessFragmentViews{

. 
.

    public void serVisibilityForButton(boolean shouldHide){
       if(shouldHide){
           yourButton.setVisibility(View.GONE);
       }else{
           yourButton.setVisibility(View.VISIBLE);
       }
    }
}

Now you can interact safely with the views of the fragment within a activity using this interface. Make sure that the fragment is alive before doing so though ;) accessing child's view are prone to WindowLeakedExceptions and illegalstateexceptions

In the activity use it as follows:

you can get the fragment reference by either finding it by its tag or by using the reference you used to create the fragment

//NOTE: it is very very dangerous to do the accessing on a fragment views from an activity

//first the alive check then the logic 

if(yourFragmentReference!=null){
((AccessFragmentViews)yourFragmentReference).setVisibilityForButton(true);// or false if you want to make it visible
}
Kushan
  • 5,855
  • 3
  • 31
  • 45
  • He wants to change fragment view, not the activity view, as far as i understand his question – Mohammed Atif Jul 22 '16 at 06:45
  • Oops... reverse the order then lol. @MohammedAtif thank you :) – Kushan Jul 22 '16 at 06:48
  • I guess, reverse order is little bit more tricky to implement, You need to access fragment via its tag to call the methods. Definitely interfaces work in your case, but reverse is little dangerous. – Mohammed Atif Jul 22 '16 at 06:49
  • @MohammedAtif both are dangerous. I put a check on a fragment reference he owns, but that will not save him from all issues. Well he wants this, what more can i do lol :D – Kushan Jul 22 '16 at 06:53
0

Add a method in your fragment class

public void changeButtonVisibility(boolean visibility){
  if(visibility){
    newDesigns.setVisibility(View.VISIBLE);
  }else{
    newDesigns.setVisibilty(View.GONE);
  }
}

and in your activity class

add this line

 public class HomeActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home);
        CategoryFragment frag=(CategoryFragment) activity.getSupportFragmentManager() 
                                  .findFragmentByTag("cat_frag");
        frag.changeButtonVisibility(true);
     }
 }
Mohammed Atif
  • 4,383
  • 7
  • 28
  • 57
  • this will keep unnecessary references alive when not needed. also if the fragment gets destroyed, the app will crash. – Kushan Jul 22 '16 at 06:36
  • 1
    This is just an example, there are several ways of accessing alive fragment like `using tag reference`, `using weak references`, `using variable reference`, For this particular example, this one suits best. – Mohammed Atif Jul 22 '16 at 06:44