Для людей, которые используют AngularJS , может справиться с этой ситуацией, используя Promises
.
Здесь it говорит,
Обещания могут использоваться для отключения асинхронных функций и позволяют объединять несколько функций вместе.
Вы можете найти приятное объяснение здесь .
Пример, найденный в docs , упомянутом ниже.
promiseB = promiseA.then( function onSuccess(result) { return result + 1; } ,function onError(err) { //Handle error } ); // promiseB will be resolved immediately after promiseA is resolved // and its value will be the result of promiseA incremented by 1.
Angular2 and Later
In
Angular2
, посмотрите на следующий пример, но его рекомендовал использоватьObservables
сAngular2
.search(term: string) { return this.http .get(`https://api.spotify.com/v1/search?q=${term}&type=artist`) .map((response) => response.json()) .toPromise();
}
Вы можете использовать это таким образом,
search() { this.searchService.search(this.searchField.value) .then((result) => { this.result = result.artists.items; }) .catch((error) => console.error(error)); }
См. здесь оригинал . Но TypScript не поддерживает native es6 Promises , если вы хотите его использовать, для этого вам может понадобиться плагин.
Кроме того, здесь представлены обещания spec определите здесь.
Вы могли бы просто сделать это:
Активность:
Fragment someFragment;
//...onCreate etc instantiating your fragments
public void myClickMethod(View v) {
someFragment.myClickMethod(v);
}
Фрагмент:
public void myClickMethod(View v) {
switch(v.getId()) {
// Just like you were doing
}
}
В ответ на @Ameen, кто хотел
public interface XmlClickable {
void myClickMethod(View v);
}
Активность:
XmlClickable someFragment;
//...onCreate, etc. instantiating your fragments casting to your interface.
public void myClickMethod(View v) {
someFragment.myClickMethod(v);
}
Фрагмент:
public class SomeFragment implements XmlClickable {
//...onCreateView, etc.
@Override
public void myClickMethod(View v) {
switch(v.getId()){
// Just like you were doing
}
}
Я недавно решил эту проблему, не добавляя метод к контексту Activity или не используя OnClickListener. Я не уверен, что это «действительное» решение, но оно работает.
На основании: https://developer.android.com/tools/data-binding/guide. html # binding_events
Это можно сделать с привязкой данных: просто добавьте экземпляр фрагмента в качестве переменной, затем вы можете связать любой метод с onClick.
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:context="com.example.testapp.fragments.CustomFragment">
<data>
<variable name="fragment" type="com.example.testapp.fragments.CustomFragment"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_place_black_24dp"
android:onClick="@{fragment.buttonClicked}"/>
</LinearLayout>
</layout>
И код ссылки на фрагмент будет ...
public class CustomFragment 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_person_profile, container, false);
FragmentCustomBinding binding = DataBindingUtil.bind(view);
binding.setFragment(this);
return view;
}
...
}
Добавление к ответу Бланделла. Если у вас больше фрагментов, с большим количеством onClicks:
Активность:
Fragment someFragment1 = (Fragment)getFragmentManager().findFragmentByTag("someFragment1 ");
Fragment someFragment2 = (Fragment)getFragmentManager().findFragmentByTag("someFragment2 ");
Fragment someFragment3 = (Fragment)getFragmentManager().findFragmentByTag("someFragment3 ");
...onCreate etc instantiating your fragments
public void myClickMethod(View v){
if (someFragment1.isVisible()) {
someFragment1.myClickMethod(v);
}else if(someFragment2.isVisible()){
someFragment2.myClickMethod(v);
}else if(someFragment3.isVisible()){
someFragment3.myClickMethod(v);
}
}
В вашем фрагменте:
public void myClickMethod(View v){
switch(v.getid()){
// Just like you were doing
}
}
Как я вижу ответы, они как-то стары. Недавно Google ввел DataBinding , который намного легче обрабатывать onClick или назначать в вашем xml.
Вот хороший пример, который вы можете увидеть, как справиться с этим :
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android">
<data>
<variable name="handlers" type="com.example.Handlers"/>
<variable name="user" type="com.example.User"/>
</data>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.firstName}"
android:onClick="@{user.isFriend ? handlers.onClickFriend : handlers.onClickEnemy}"/>
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{user.lastName}"
android:onClick="@{user.isFriend ? handlers.onClickFriend : handlers.onClickEnemy}"/>
</LinearLayout>
</layout>
Существует также очень хороший учебник о DataBinding, который вы можете найти Здесь .
В моем случае использования у меня есть 50 нечетных ImageViews, которые мне нужно подключить к одному методу onClick. Мое решение состоит в том, чтобы перебрать представления внутри фрагмента и установить одинаковый прослушиватель onclick для каждого:
final View.OnClickListener imageOnClickListener = new View.OnClickListener() {
@Override
public void onClick(View v) {
chosenImage = ((ImageButton)v).getDrawable();
}
};
ViewGroup root = (ViewGroup) getView().findViewById(R.id.imagesParentView);
int childViewCount = root.getChildCount();
for (int i=0; i < childViewCount; i++){
View image = root.getChildAt(i);
if (image instanceof ImageButton) {
((ImageButton)image).setOnClickListener(imageOnClickListener);
}
}
Ваша активность получает обратный вызов, который должен был использоваться:
mViewPagerCloth.setOnClickListener((YourActivityName)getActivity());
Если вы хотите, чтобы ваш фрагмент получал обратный вызов, сделайте следующее:
mViewPagerCloth.setOnClickListener(this);
и реализуйте onClickListener
на фрагменте
Я хотел бы добавить к [j0] ответ [].
.. Если вам нужно несколько обработчиков, вы можете просто использовать ссылки лямбда
void onViewCreated(View view, Bundle savedInstanceState)
{
view.setOnClickListener(this::handler);
}
void handler(View v)
{
...
}
Фокус в том, что подпись handler
метода совпадает с сигнатурой View.OnClickListener.onClick
. Таким образом, вам не понадобится интерфейс View.OnClickListener
.
Кроме того, вам не нужны какие-либо операторы switch.
К сожалению, этот метод ограничен только интерфейсами, которые требуют один метод или лямбда.
Это другой способ:
1.Создать базовыйфрагмент следующим образом:
public abstract class BaseFragment extends Fragment implements OnClickListener
2.Используйте
public class FragmentA extends BaseFragment
вместо
public class FragmentA extends Fragment
3.В вашей деятельности:
public class MainActivity extends ActionBarActivity implements OnClickListener
и
BaseFragment fragment = new FragmentA;
public void onClick(View v){
fragment.onClick(v);
}
Надеюсь, что это поможет.
Если вы зарегистрируетесь в xml с помощью android: Onclick = "", обратный вызов будет передан уважаемому действию, в контексте которого принадлежит ваш фрагмент (getActivity ()). Если такой метод не найден в Activity, тогда система выдаст исключение.
Я предпочитаю использовать следующее решение для обработки событий onClick. Это также работает для Activity и Fragments.
public class StartFragment extends Fragment implements OnClickListener{
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_start, container, false);
Button b = (Button) v.findViewById(R.id.StartButton);
b.setOnClickListener(this);
return v;
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.StartButton:
...
break;
}
}
}
Наилучшее решение IMHO:
в фрагменте:
protected void addClick(int id) {
try {
getView().findViewById(id).setOnClickListener(this);
} catch (Exception e) {
e.printStackTrace();
}
}
public void onClick(View v) {
if (v.getId()==R.id.myButton) {
onMyButtonClick(v);
}
}
, а затем в Fragment's onViewStateRestored:
addClick(R.id.myButton);
Вы можете определить обратный вызов как атрибут вашего XML-макета. В статье Пользовательские атрибуты XML для ваших пользовательских виджетов Android покажут, как это сделать для пользовательского виджета. Кредит идет к Кевину Диону :)
Я изучаю, могу ли я добавлять атрибуты стиля к базовому классу Fragment.
Основная идея состоит в том, чтобы иметь те же функции, что View реализует, когда работа с обратным вызовом onClick.
Возможно, вы захотите рассмотреть возможность использования EventBus для развязанных событий. Вы можете слушать события очень легко. Вы также можете убедиться, что событие получено в потоке ui (вместо вызова runOnUiThread .. для себя для каждой подписки на события)
https://github.com/greenrobot/EventBus
из Github:
Оптимизированная для Android шина событий, которая упрощает связь между действиями, фрагментами, потоками, службами и т. д. Меньше кода, лучшее качество
BLOCKQUOTE>
ButterKnife , вероятно, является лучшим решением проблемы помех. Он использует обработчики аннотаций для генерации шаблона так называемого «старого метода».
Но метод onClick все еще может использоваться с пользовательским инфлятором.
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup cnt, Bundle state) {
inflater = FragmentInflatorFactory.inflatorFor(inflater, this);
return inflater.inflate(R.layout.fragment_main, cnt, false);
}
public class FragmentInflatorFactory implements LayoutInflater.Factory {
private static final int[] sWantedAttrs = { android.R.attr.onClick };
private static final Method sOnCreateViewMethod;
static {
// We could duplicate its functionallity.. or just ignore its a protected method.
try {
Method method = LayoutInflater.class.getDeclaredMethod(
"onCreateView", String.class, AttributeSet.class);
method.setAccessible(true);
sOnCreateViewMethod = method;
} catch (NoSuchMethodException e) {
// Public API: Should not happen.
throw new RuntimeException(e);
}
}
private final LayoutInflater mInflator;
private final Object mFragment;
public FragmentInflatorFactory(LayoutInflater delegate, Object fragment) {
if (delegate == null || fragment == null) {
throw new NullPointerException();
}
mInflator = delegate;
mFragment = fragment;
}
public static LayoutInflater inflatorFor(LayoutInflater original, Object fragment) {
LayoutInflater inflator = original.cloneInContext(original.getContext());
FragmentInflatorFactory factory = new FragmentInflatorFactory(inflator, fragment);
inflator.setFactory(factory);
return inflator;
}
@Override
public View onCreateView(String name, Context context, AttributeSet attrs) {
if ("fragment".equals(name)) {
// Let the Activity ("private factory") handle it
return null;
}
View view = null;
if (name.indexOf('.') == -1) {
try {
view = (View) sOnCreateViewMethod.invoke(mInflator, name, attrs);
} catch (IllegalAccessException e) {
throw new AssertionError(e);
} catch (InvocationTargetException e) {
if (e.getCause() instanceof ClassNotFoundException) {
return null;
}
throw new RuntimeException(e);
}
} else {
try {
view = mInflator.createView(name, null, attrs);
} catch (ClassNotFoundException e) {
return null;
}
}
TypedArray a = context.obtainStyledAttributes(attrs, sWantedAttrs);
String methodName = a.getString(0);
a.recycle();
if (methodName != null) {
view.setOnClickListener(new FragmentClickListener(mFragment, methodName));
}
return view;
}
private static class FragmentClickListener implements OnClickListener {
private final Object mFragment;
private final String mMethodName;
private Method mMethod;
public FragmentClickListener(Object fragment, String methodName) {
mFragment = fragment;
mMethodName = methodName;
}
@Override
public void onClick(View v) {
if (mMethod == null) {
Class<?> clazz = mFragment.getClass();
try {
mMethod = clazz.getMethod(mMethodName, View.class);
} catch (NoSuchMethodException e) {
throw new IllegalStateException(
"Cannot find public method " + mMethodName + "(View) on "
+ clazz + " for onClick");
}
}
try {
mMethod.invoke(mFragment, v);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new AssertionError(e);
}
}
}
}
Это работает для меня: (студия Android)
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.update_credential, container, false);
Button bt_login = (Button) rootView.findViewById(R.id.btnSend);
bt_login.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
System.out.println("Hi its me");
}// end onClick
});
return rootView;
}// end onCreateView
Проблема, я думаю, в том, что представление по-прежнему является активностью, а не фрагментом. Фрагменты не имеют самостоятельного представления и привязаны к представлению родительских действий. Вот почему событие завершается в Activity, а не в фрагменте. Его неудача, но я думаю, вам понадобится какой-то код, чтобы сделать эту работу.
То, что я делал во время конверсий, просто добавляет прослушиватель кликов, который вызывает старый обработчик событий.
например:
final Button loginButton = (Button) view.findViewById(R.id.loginButton);
loginButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(final View v) {
onLoginClicked(v);
}
});