Я создал экспериментальное приложение, в котором пытаюсь научиться налаживать успешное общение ч / б двумя фрагментами.
У меня есть только одно действие, которое является основным действием. В этом упражнении у меня есть элемент просмотра пейджера в XML. Я создал настраиваемый адаптер пейджера, который распространяется на адаптер пейджера фрагментов и два фрагмента, которые являются дочерними и поставляются моим адаптером пейджера для пейджера просмотра.
Я пытаюсь сделать следующее: FirstFragment имеет одну кнопку, которая при нажатии меняет цвет фона SecondFragment (в качестве родительского элемента есть относительный макет), который будет виден при одном касании.
Что я сделал до сих пор: я создал интерфейс в FirstFragment, реализованный в MainActivity, создал метод в SecondFragment, который изменяет цвет фона макета и, наконец, получил SecondFragment в MainActivvity (по крайней мере, пытался) и вызвал его метод. Но приложение дает сбой при нажатии кнопки с надписью «Фрагмент SecondFragment не привязан к контексту».
Вот код:
activity_main.xml
<?xml version = "1.0" encoding = "utf-8"?>
<android.support.constraint.ConstraintLayout
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"
tools:context = ".MainActivity">
<android.support.v4.view.ViewPager
android:id = "@+id/view_pager"
android:layout_width = "match_parent"
android:layout_height = "match_parent"/>
</android.support.constraint.ConstraintLayout>
MainActivity.java
package com.example.android.laboratory;
import...
public class MainActivity extends AppCompatActivity implements FirstFragment.MyListener {
ViewPager viewPager;
MyPagerAdapter adapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = findViewById(R.id.view_pager);
adapter = new MyPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(adapter);
}
@Override
public void changeColor() {
SecondFragment secondFragment = new SecondFragment();
secondFragment.changeColor();
}
}
Пользовательский адаптер:
package com.example.android.laboratory;
import ...
public class MyPagerAdapter extends FragmentPagerAdapter {
public MyPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int i) {
switch (i) {
case 0:
return new FirstFragment();
case 1:
return new SecondFragment();
}
return null;
}
@Override
public int getCount() {
return 2;
}
}
Первый фрагмент:
package com.example.android.laboratory;
import ...
public class FirstFragment extends Fragment {
MyListener listener;
public FirstFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_first, container, false);
Button button = view.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
listener.changeColor();
}
});
return view;
}
public interface MyListener{
void changeColor();
}
@Override
public void onAttach(Context context) {
super.onAttach(context);
try {
listener = (MyListener) context;
} catch (ClassCastException e) {
throw new ClassCastException(getActivity().toString() + " must implement MyListener interface.");
}
}
}
Второй фрагмент:
package com.example.android.laboratory;
import ...
public class SecondFragment extends Fragment {
RelativeLayout relativeLayout;
public SecondFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_second, container, false);
relativeLayout = view.findViewById(R.id.layout);
return view;
}
public void changeColor() {
relativeLayout.setBackgroundColor(getResources().getColor(R.color.colorAccent));
}
}
Журнал сбоев:
12-23 12:18:03.574 31428-31428/com.example.android.laboratory E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.android.laboratory, PID: 31428
java.lang.IllegalStateException: Fragment SecondFragment{2bfa6ff2} not attached to a context.
at android.support.v4.app.Fragment.requireContext(Fragment.java:696)
at android.support.v4.app.Fragment.getResources(Fragment.java:760)
at com.example.android.laboratory.SecondFragment.changeColor(SecondFragment.java:32)
at com.example.android.laboratory.MainActivity.changeColor(MainActivity.java:28)
at com.example.android.laboratory.FirstFragment$1.onClick(FirstFragment.java:31)
at android.view.View.performClick(View.java:4791)
at android.view.View$PerformClick.run(View.java:19903)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5296)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:912)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:707)
Кстати, этот подход вам не поможет, потому что метод getItem () вернет НОВЫЙ фрагмент, который ничего не будет знать о вашем цвете.
Так что же мне делать?
Я считаю, что есть много способов. Что касается меня, я бы создал новый класс модели, который содержит все состояния ваших фрагментов, включая цвет. Первый фрагмент изменяет эту модель, а второй фрагмент использует ее.
Вы имеете в виду модель представления, указанную в документации по Android?
См. Ответ ниже
Вы можете увидеть этот документ https://developer.android.com/training/basics/fragments/communicating Если по каким-то причинам вы хотите сделать свой велосипед, вы можете попробовать что-то вроде этого (шаблон наблюдателя)
MyModel
import java.util.ArrayList;
public class MyModel {
private int color = R.color.colorPrimary;
private ArrayList<MyObserver> observers = new ArrayList<>();
interface MyObserver {
void setColor(int color);
}
public void setColor(int color) {
this.color = color;
for (int i = 0; i < observers.size(); i++) {
observers.get(i).setColor(color);
}
}
public void addObserver(MyObserver newObserver) {
if (observers.indexOf(newObserver) < 0) {
observers.add(newObserver);
}
}
public void deleteObserver(MyObserver oldObserver) {
if (observers.indexOf(oldObserver) > -1) {
observers.remove(oldObserver);
}
}
}
Первый фрагмент
public class FirstFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_first, container, false);
Button button = view.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
MainActivity mainActivity = (MainActivity) getActivity();
mainActivity.myModel.setColor(R.color.colorAccent);
}
});
return view;
}
}
ВторойФрагмент
public class SecondFragment extends Fragment implements MyModel.MyObserver {
RelativeLayout relativeLayout;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_second, container, false);
relativeLayout = view.findViewById(R.id.layout);
MainActivity mainActivity = (MainActivity) getActivity();
mainActivity.myModel.addObserver(this);
return view;
}
@Override
public void onDestroy() {
MainActivity mainActivity = (MainActivity) getActivity();
mainActivity.myModel.deleteObserver(this);
super.onDestroy();
}
@Override
public void setColor(int color) {
relativeLayout.setBackgroundColor(getResources().getColor(color, null));
}
}
Основная деятельность
public class MainActivity extends AppCompatActivity {
ViewPager viewPager;
MyPagerAdapter adapter;
public MyModel myModel = new MyModel();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = findViewById(R.id.view_pager);
adapter = new MyPagerAdapter(getSupportFragmentManager());
viewPager.setAdapter(adapter);
}
}
В методе MainActivity.changeColor вы только создаете SecondFragment, но не присоединяете его к действию, поэтому Fragment не имеет контекста и вылетает, как вы можете видеть в этой строке журнала: в android.support.v4.app.Fragment. requireContext (Fragment.java: 696)