#OnClick doesn't works after rotation in ButterKnife - android

I have the next fragment:
public class MyFragment extends Fragment {
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.my_fragment, container, false);
return view;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
ButterKnife.setDebug(true);
ButterKnife.bind(this, view);
}
#OnClick(R.id.button)
public void onButtonClicked () {
//Do some stuff
}
}
OnClick method works like a charm first time and it works fine until I rotate the device. When I rotate the device, method doesn't works more.
Log has no errors.
Do you know what is the problem?
Thanks you.

Try to retain the fragment to avoid to be destroyed and created again.It may resolve you problem

Try unbinding when the fragment is destroyed (which should happen upon rotation). Then it should bind correctly again:
#Override
public void onDestroyView(){
super.onDestroyView();
ButterKnife.unbind(this);
}

Related

"Already executed" error (Retrofit2 and Android)

First of all, I have 2 fragments and they show different json values(2 links). If I change fragment(.replace()), that fragment get values with retrofit and show it. It works well but other fragment is deleted with values. After change fragment, it downloads again so I change structure. I want to take 2 json objects once so I get json objects in mainactivity and fragments get these with methods. They work well in first opening but if i open a fragment second time, it gives this error. How can I solve it?
java.lang.IllegalStateException: Already executed.
at retrofit2.OkHttpCall.enqueue(OkHttpCall.java:84)
Code is very long, i will show main structure.
MainActivity.java
public class MainActivity extends AppCompatActivity
{
private Call<Restaurant[]> restaurantCall;
private Call<Dining[]> diningCall;
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Restaurant Json value
RestaurantInterface restaurantInterface = RetroClient.getClient().create(RestaurantInterface.class);
restaurantCall = restaurantInterface.getJsonValues();
//Dininghall Json value
DiningInterface diningInterface = RetroClient.getClient().create(DiningInterface.class);
diningCall = diningInterface.getJsonValues();
}
public Call<Restaurant[]> RestaurantJson()
{
return this.restaurantCall;
}
public Call<Dining[]> DiningJson()
{
return this.diningCall;
}
}
RestaurantFragment.java (Other fragment has same structure)
public class RestFragment extends Fragment
{
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.fragment_rest, container, false);
Call<Restaurant[]> call = ((MainActivity) getActivity()).RestaurantJson();
call.enqueue(new Callback<Restaurant[]>()
{
.
.
Summing up, in order to avoid the "Already executed" exception, clone the call:
public Call<Restaurant[]> RestaurantJson()
{
return this.restaurantCall.clone();
}
public Call<Dining[]> DiningJson()
{
return this.diningCall.clone();
}
If you want to execute the call in the activity and not in the fragment as you are actually doing, then you need to call enqueue(new Callbak(... in your activity.
So you need something like this:
public class RestFragment extends Fragment {
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_rest, container, false);
((MainActivity) getActivity()).RestaurantJson(this);
}
public void onResponse(Response<T> response) {
//your fragment code on response
}
...
}
public class MainActivity extends AppCompatActivity {
public void RestaurantJson(final RestFragment fragment)
{
RestaurantInterface restaurantInterface = RetroClient.getClient().create(RestaurantInterface.class);
restaurantCall = restaurantInterface.getJsonValues();
restaurantCall.enqueue(new Callback<Restaurant[]>() {
#Override
public void onResponse(Call<T> call, Response<T> response) {
...
fragment.onResponse(response);
}
}
...
}
The same for your DiningFragment and your dining call...

getActivity return null in fragment onActivityCreated in some rooted device

My app work fine on most device but some rooted device. In fragment onActivityCreated, getActivity keep return null. I need Context class to to set up thing below.
So anyone can help me?
Update
public class BaseProductFragment extends Fragment {
...
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(layout_id, container,
false);
return rootView;
}
public void onActivityCreated(final Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
ImageCacheParams cacheParams = new ImageCacheParams(getActivity(),
Utils.PRODUCTS_CACHE_DIR);
....
}
getActivity "might" return null if called from within onActivityCreated...especially during a configuration change like orientation change because the activity gets destroyed...move that initialization to onAttach...
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
//initialize here
}
onActivityCreated is a called when the parent activity's onCreate is called...but remember that it could be "recreated", destroyed during a config change

Passing Arguments to a Fragment via Bundles

Bundle params=new Bundle();
params.putBoolean("isNew", true);
getFragmentManager().beginTransaction()
.replace(R.id.main, Fragment
.instantiate(LandingScreen.this, "com.fragments.FragmentOne",params)).commit()
Now this is Fragment1
public class FragmentOne extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
ViewGroup root = (ViewGroup) inflater.inflate(R.layout.fragment_one, null);
return root;
}
}
Where do i receive the Bundle params, that i sent with when creating this Fragment ?
Kind Regards
You'll receive Bundle in Fragment onCreate(....)
#Override
public void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
boolean isNew=this.getArguments().getBoolean("isNew");
}
You can get the data where Bundle object is accessible as a parameter
onCreate()
onCreateView()
onActivityCreated()
When you use onCreate()
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.fragment_layout);
String myData=this.getArguments().getString("myData");
}
When you use onCreateView()
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {
String myData=this.getArguments().getString("myData");
return inflater.inflate(R.layout.example_fragment, container, false);
}
When you use onActivityCreated()
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
String myData=this.getArguments().getString("myData");
}
Most of the time, you'll use call getArguments() in onCreate(), which gets called sometime after you instantiate the Fragment but before onCreateView() and onActivityCreated() would get called. However, as per Android documentation, if you're calling this from your Activity while it's being created, you're not guaranteed that the Activity has finished initializing before onCreate() is called:
Note that this can be called while the fragment's activity is still in the process of being created. As such, you can not rely on things like the activity's content view hierarchy being initialized at this point. If you want to do work once the activity itself is created, see onActivityCreated(Bundle).
For more information, check out this blog post on Activities and Fragments: http://www.zerotohired.com/2015/02/passing-data-between-activities-and-fragments-in-android.

Why is FragmentPagerAdapter saveState always null?

I want to save the state of my FragmentPagerAdapter so I can reuse it after the orientation of the screen changed. Unfortunately the method saveState returns always null.
My Adapter consists of an ActionBar with two Fragments.
Here ist my method call
#Override
protected void onSaveInstanceState(Bundle outState) {
outState.putInt(FRAGMENT, viewPager.getCurrentItem() + 1);
outState.putParcelable(ADAPTER, fragmentTabAdapter.saveState());
super.onSaveInstanceState(outState);
}
But the Adapter in outState is always null. I don't understand why. Is there something special I missed about the use of saveState?
Hope you can help me!
this example works if the fragment is not destroyed
private int pageID;
#Override
public void onPause() {
super.onPause();
pageID = mViewPager.getCurrentItem(); // 1 save
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
mViewPager.setCurrentItem(pageID, false); // 2 load
}

Test if a layout has been "inflated"

I have an android Activity with swipe navigation (implemented with ViewPager).
public class UberActivity extends FragmentActivity {
ViewPager mViewPager;
protected void onCreate(Bundle savedInstanceState) {
//... some stuff
myfragment1=new MyFragment1();
myfragment2=new MyFragment2();
myfragment3=new MyFragment3();
myfragment4=new MyFragment4();
}
public void onChoiceSelected(){
mViewPager.post(new Runnable(){public void run(){
myfragmen1.update();
myfragmen2.update();
myfragmen3.update();
myfragmen4.update();
}});
}
}
public class Fragment4 extends Fragment {
View v;
#Override
public View onCreateView(LayoutInflater layoutInflater, ViewGroup container,
Bundle savedInstanceState) {
v=layoutInflater.inflate(R.layout.mylayout,container,false);
return v;
}
public void update(){
((TextView)v.findViewById(R.id.textView1)).setText("new text");
}
I will get a NullPointerException on update(), unless I beforehand swipe to it (so that its layout is actually inflated before calling update()).
The problem here is that Fragment4 is instanced but its OnCreateView() is not called. How should I check if OnCreateView() is called? I could put a boolean there, but I don't think this is a best practice...
Just add an if-statement around 'v', checking if it is null or not.
public void update(){
if (v != null) {
((TextView)v.findViewById(R.id.textView1)).setText("new text");
}
}

Categories

Resources