2013-07-19 3 views
0

У меня есть два фрагмента, позвоните им Фрагмент A и фрагмент B, которые являются частью NavigationDrawer (это деятельность, к которой они привязаны). В Fragment A у меня есть кнопка. Когда эта кнопка нажата, я хотел бы добавить к элементу ListView в фрагменте B. еще один элемент.изменить элементы в ListView из другого фрагмента

Каков наилучший способ сделать это? Используйте Intents, SavedPreferences, делая что-то публичное (?) Или что-то еще?

EDIT 5: 20/7/13 Это с srains последней версии кода

Это NavigationDrawer, что я использую, чтобы начать фрагменты:

import android.support.v4.app.Fragment; 
import android.support.v4.app.FragmentActivity; 
import android.support.v4.app.FragmentManager; 
import android.app.Service; 
import android.content.Context; 
import android.content.Intent; 
import android.content.SharedPreferences; 
import android.content.res.Configuration; 
import android.os.Bundle; 
import android.preference.PreferenceManager; 
import android.support.v4.app.ActionBarDrawerToggle; 
import android.support.v4.view.GravityCompat; 
import android.support.v4.widget.DrawerLayout; 
import android.view.Menu; 
import android.view.MenuInflater; 
import android.view.MenuItem; 
import android.view.View; 
import android.view.WindowManager; 
import android.view.inputmethod.InputMethodManager; 
import android.widget.AdapterView; 
import android.widget.ArrayAdapter; 
import android.widget.ListView; 

public class Navigation_Drawer extends FragmentActivity { 

    public DrawerLayout mDrawerLayout; // Creates a DrawerLayout called_. 
    public ListView mDrawerList; 
    public ActionBarDrawerToggle mDrawerToggle; 

    private CharSequence mDrawerTitle; 
    private CharSequence mTitle; 
    private String[] mNoterActivities; // This creates a string array called _. 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     // TODO Auto-generated method stub 

// Just setting up the navigation drawer 

    } // End of onCreate 

// Removed the menu 


     @Override 
     public void onItemClick(AdapterView<?> parent, View view, int position, 
       long id) { 
      selectItem(position); 
     } 
    } 

    private void selectItem(int position) { 

     FragmentManager fragmentManager = getSupportFragmentManager(); 

     if (position == 0) { 
      Fragment qnfragment = new QuickNoteFragment(); 
      ((FragmentBase) qnfragment).setContext(this); 
      Bundle args = new Bundle(); // Creates a bundle called args 
      args.putInt(QuickNoteFragment.ARG_nOTERACTIVITY_NUMBER, position); 

      qnfragment.setArguments(args); 

      fragmentManager.beginTransaction() 
        .replace(R.id.content_frame, qnfragment).commit(); 



     } else if (position == 3) { 
      Fragment pendViewPager = new PendViewPager(); // This is a ViewPager that includes HistoryFragment 
      ((FragmentBase) pendViewPager).setContext(this); 
      Bundle args = new Bundle(); 

      pendViewPager.setArguments(args); 
      fragmentManager.beginTransaction() 
        .replace(R.id.content_frame, pendViewPager).commit(); 
     } 

    // Update title etc 
    } 


    @Override 
    protected void onPostCreate(Bundle savedInstanceState) { // Used for the NavDrawer toggle 
     super.onPostCreate(savedInstanceState); 
     // Sync the toggle state after onRestoreInstanceState has occurred. 
     mDrawerToggle.syncState(); 
    } 

    @Override 
    public void onConfigurationChanged(Configuration newConfig) { // Used for the NavDrawer toggle 
     super.onConfigurationChanged(newConfig); 
     // Pass any configuration change to the drawer toggles 
     mDrawerToggle.onConfigurationChanged(newConfig); 
    } 

} 

Это QuickNoteFragment:

import android.support.v4.app.Fragment; 
import android.support.v4.app.FragmentManager; 
import android.app.Notification; 
import android.app.NotificationManager; 
import android.app.PendingIntent; 
import android.content.Context; 
import android.content.Intent; 
import android.content.SharedPreferences; 
import android.net.Uri; 
import android.os.Bundle; 
import android.preference.PreferenceManager; 
import android.support.v4.app.NotificationCompat; 
import android.view.LayoutInflater; 
import android.view.Menu; 
import android.view.MenuInflater; 
import android.view.MenuItem; 
import android.view.View; 
import android.view.View.OnClickListener; 
import android.view.ViewGroup; 
import android.widget.Button; 
import android.widget.CheckBox; 
import android.widget.EditText; 
import android.widget.TextView; 
import android.widget.Toast; 

public class QuickNoteFragment extends FragmentBase implements OnClickListener { 

    public static final String ARG_nOTERACTIVITY_NUMBER = "noter_activity"; 

    Button b_create; 
// removed other defining stuff 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
      Bundle savedInstanceState) { 
     View rootView = inflater.inflate(R.layout.quicknote, container, false); 
     int i = getArguments().getInt(ARG_nOTERACTIVITY_NUMBER); 
     String noter_activity = getResources().getStringArray(
       R.array.noter_array)[i]; 
     FragmentManager fm = getFragmentManager(); 
     setRetainInstance(true); 

     b_create = (Button) rootView.findViewById(R.id.qn_b_create); 

     // Removed other stuff 

     getActivity().setTitle(noter_activity); 
     return rootView; 
    } 

    @Override 
    public void onClick(View v) { 

     // TODO Auto-generated method stub 

     switch (v.getId()) { 

     case R.id.qn_b_create: 

           String data = "String data"; 
       DataModel.getInstance().addItem(data); 

      break; 
     } 
    } 

@Override 
    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { 
     // TODO Auto-generated method stub 
     super.onCreateOptionsMenu(menu, inflater); 
    } 

    @Override 
    public boolean onOptionsItemSelected(MenuItem item) { 
     // Handle item selection 

     } 
    } 

    public interface OnItemAddedHandler { // Srains code 
     public void onItemAdded(Object data); 
    } 
} 

Это HistoryFragment (Помните, что это часть ViewPager):

import java.util.ArrayList; 
import java.util.HashMap; 
import java.util.List; 
import java.util.Map; 

import com.RiThBo.noter.QuickNoteFragment.OnItemAddedHandler; 

import android.os.Bundle; 
import android.support.v4.app.Fragment; 
import android.view.ContextMenu; 
import android.view.ContextMenu.ContextMenuInfo; 
import android.view.LayoutInflater; 
import android.view.View; 
import android.view.ViewGroup; 
import android.widget.AdapterView; 
import android.widget.AdapterView.AdapterContextMenuInfo; 
import android.widget.ListView; 
import android.widget.SimpleAdapter; 
import android.widget.TextView; 
import android.widget.Toast; 

public class HistoryFragment extends FragmentBase implements OnItemAddedHandler { 

    ListView lv; 
    List<Map<String, String>> planetsList = new ArrayList<Map<String, String>>(); 
    SimpleAdapter simpleAdpt; 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, 
      Bundle savedInstanceState) { 
     // TODO Auto-generated method stub 
     View view = inflater.inflate(R.layout.history, container, false); 
     initList(); 


     ListView lv = (ListView) view.findViewById(R.id.listView); 
     simpleAdpt = new SimpleAdapter(getActivity(), planetsList, 
       android.R.layout.simple_list_item_1, new String[] { "planet" }, 
       new int[] { android.R.id.text1 }); 

     lv.setAdapter(simpleAdpt); 

     lv.setOnItemClickListener(new AdapterView.OnItemClickListener() { 

      public void onItemClick(AdapterView<?> parentAdapter, View view, 
        int position, long id) { 

       // We know the View is a TextView so we can cast it 

       TextView clickedView = (TextView) view; 

       Toast.makeText(
         getActivity(), 
         "Item with id [" + id + "] - Position [" + position 
           + "] - Planet [" + clickedView.getText() + "]", 
         Toast.LENGTH_SHORT).show(); 
      } 

     }); 
     registerForContextMenu(lv); 

     return view; 

    } 

    private void initList() { 

     // We populate the planets 

     planetsList.add(createPlanet("planet", "Mercury")); 
     planetsList.add(createPlanet("planet", "Venus")); 
     planetsList.add(createPlanet("planet", "Mars")); 
     planetsList.add(createPlanet("planet", "Jupiter")); 
     planetsList.add(createPlanet("planet", "Saturn")); 
     planetsList.add(createPlanet("planet", "Uranus")); 
     planetsList.add(createPlanet("planet", "Neptune")); 

    } 

    private HashMap<String, String> createPlanet(String key, String name) { 

     HashMap<String, String> planet = new HashMap<String, String>(); 

     planet.put(key, name); 

     return planet; 

    } 

    // We want to create a context Menu when the user long click on an item 

    @Override 
    public void onCreateContextMenu(ContextMenu menu, View v, 

    ContextMenuInfo menuInfo) { 

     super.onCreateContextMenu(menu, v, menuInfo); 

     AdapterContextMenuInfo aInfo = (AdapterContextMenuInfo) menuInfo; 

     // We know that each row in the adapter is a Map 

     HashMap map = (HashMap) simpleAdpt.getItem(aInfo.position); 

     menu.setHeaderTitle("Options for " + map.get("planet")); 
     menu.add(1, 1, 1, "Details"); 
     menu.add(1, 2, 2, "Delete"); 

    } 
    @Override 
     public void onItemAdded(Object data) { 
      // to add item 
      String string = String.valueOf(data); 
      Toast.makeText(getContext(), "Data: " + string, Toast.LENGTH_SHORT).show(); 
      planetsList.add(createPlanet("planet", string)); 
     } 
     @Override 
    public void onStart() { 
      super.onStart(); 

      DataModel.getInstance().setOnItemAddedHandler(this); 
     } 
} 

Это FragmentBase:

import android.support.v4.app.Fragment; 
    import android.support.v4.app.FragmentActivity; 

     public class FragmentBase extends Fragment { 

      private FragmentActivity mActivity; // I changed it to FragmentActivity because Activity was not working, and my `NavDrawer` is a FragmentActivity. 

      public void setContext(FragmentActivity activity) { 
       mActivity = mActivity; 
      } 

      public FragmentActivity getContext() { 
       return mActivity; 
      } 
    } 

Это DataModel:

import android.util.Log; 
    import com.xxx.xxx.QuickNoteFragment.OnItemAddedHandler; 

public class DataModel { 

    private static DataModel instance; 
    private static OnItemAddedHandler mOnItemAddHandler; 

    public static DataModel getInstance() { 
     if (null == instance) { 
      instance = new DataModel(); 
     } 
     return instance; 
    } 

    public void setOnItemAddedHandler(OnItemAddedHandler handler) { 
     mOnItemAddHandler = handler; 
    } 

    public void addItem(Object data) { 
     if (null != mOnItemAddHandler) 
      mOnItemAddHandler.onItemAdded(data); 
     else { 
      Log.i("is context null?", "yes!"); 
     } 
    } 
} 

Спасибо

+0

Поскольку фрагменты, принадлежащие к одной и той же Деятельности, объединяются, вы можете безопасно использовать статические поля. Что-то вроде 'FragmentB.adapter.add (x); FragmentBadapter.notifyDataSetChanges(); ' –

+0

@ Archie.bpgc Пожалуйста, можете ли вы расширить немного больше - на самом деле не понимаете – RiThBo

+0

Просто создайте' ListView Adapter' из ** FragmentB ** 'static' и используйте его как' FragmentB.adapter.add (новый элемент); 'в ** Кнопка щелчка кнопки FragmentA **. –

ответ

1

Я предлагаю вам использовать interface и MVC, что сделает ваш код более удобным.

Сначала вам нужно интерфейс:

public interface OnItemAddedHandler { 
     public void onItemAdded(Object data); 
    } 

Тогда вам нужна модель данных:

public class DataModel { 

     private static DataModel instance; 
     private static OnItemAddedHandler mOnItemAddHandler; 

     public static DataModel getInstance() { 
      if (null == instance) { 
       instance = new DataModel(); 
      } 
      return instance; 
     } 

     public void setOnItemAddedHandler(OnItemAddedHandler handler) { 
      mOnItemAddHandler = handler; 
     } 

     public void addItem(Object data) { 
      if (null != mOnItemAddHandler) 
       mOnItemAddHandler.onItemAdded(data); 
     } 
    } 

При нажатии на кнопку, вы можете добавить данные в DataModel:

Object data = null; 
    DataModel.getInstance().addItem(data); 

Затем FragmentB реализует интерфейс OnItemAddedHandler, чтобы добавить товар

public class FragmentB implements OnItemAddedHandler { 

     @Override 
     public void onItemAdded(Object data) { 
      // to add item 
     } 
    } 

также, когда FragmentB начала, вы должны зарегистрировать себя DataModel:

public class FragmentB implements OnItemAddedHandler { 

     @Override 
     public void onItemAdded(Object data) { 
      // to add item 
     } 

     @Override 
     protected void onStart() { 
      super.onStart(); 

      DataModel.getInstance().setOnItemAddedHandler(this); 
     } 
    } 

Вы также можете добавить DataModel.getInstance().setOnItemAddedHandler(this); к onCreate методу FragmentB

@Override 
protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    DataModel.getInstance().setOnItemAddedHandler(this); 

    // do other things 
} 

обновление

вы можете отправить строку просто:

String data = "some string"; 
    DataModel.getInstance().addItem(data); 

затем на FragementB

public class FragmentB implements OnItemAddedHandler { 

     @Override 
     public void onItemAdded(Object data) { 
      // get what you send into method DataModel.getInstance().addItem(data); 
      String string = String.valueOf(data); 
     } 
    } 

обновление

OK. У вас есть DataModel.getInstance().setOnItemAddedHandler(this) в методе onCreateView, поэтому нет необходимости добавлять его в метод onStart(). Вы можете удалить весь метод onStart.

onStart будет вызываться в начале фрагмента, нам не нужно называть его onCreateView. И на onItemAdded будет звонить, когда вызывается метод DataModel.getInstance().addItem(data), нам не нужно звонить ему в onCreateView.

так, вы можете удалить этот код из onCreateView метода:

DataModel.getInstance().setOnItemAddedHandler(this); 
    // remove the methods below 
    // onItemAdded(getView()); 
    // onStart(); 

У вас есть еще один фрагмент, где есть кнопка, вы можете добавить коды ниже в функции clickhandler:

String data = "some string"; 
DataModel.getInstance().addItem(data); 

update3

Я думаю, что HistoryFragment был отсоединен после вас ан к QuickNoteFragment Вы можете добавить код HistoryFragment проверить:

@Override 
public void onDetach() { 
    super.onDetach(); 
    Log.i("test", String.format("onDetach! %s", getActivity() == null)); 
} 

update4

Я думаю HistoryFragment и QuickNoteFragment должен есть родительский класс, названный FragmentBase:

public class FragmentBase extends Fragment { 

     private Activity mActivity; 

     public void setContext(Activity activity) { 
      mActivity = mActivity; 
     } 

     public Activity getContext() { 
      return mActivity; 
     } 
    } 

HistoryFragment и QuickNoteFragment распространяется FragmentBase. Затем, когда вы переключаетесь между ними, вы можете вызвать setContext установить активность, как:

private void selectItem(int position) { 

    FragmentManager fragmentManager = getSupportFragmentManager(); 

    if (position == 0) { 
     Fragment qnfragment = new QuickNoteFragment(); 
     qnfragment.setContext(this); 

     // ... 

    } else if (position == 1) { 
     Fragment pagerFragment = new RemViewPager(); 
     pagerFragment.setContext(this); 

     // ... 
    } 
} 

теперь мы можем получить ненулевую активность в HistoryFragment по телефону getContext, поэтому мы можем изменить onItemAdded метод:

@Override 
    public void onItemAdded(Object data) { 
     // to add item 
     String string = String.valueOf(data); 
     Toast.makeText(getContext(), "Data: " + string, Toast.LENGTH_SHORT).show(); 
     planetsList.add(createPlanet("planet", string)); 
    } 

Я надеюсь, что это сработает.

+0

Wow! Большое спасибо за подробное руководство - я тоже попробую это сделать – RiThBo

+1

ОК, у меня все работает без ошибок, но объект не добавляется (я пробовал String и TextView) в listview – RiThBo

+0

добавить некоторый журнал в onItemAdded метод в FragmentB, чтобы показать, каковы данные. – srain

0
  1. Используйте Broadcast. Отправьте boradcast от A, и B получит и обработает его.
  2. Добавить открытый метод в B, например, public void addListItem(), который будет добавлять данные в список в B. Фрагмент Попробуйте найти экземпляр фрагмента B с помощью FragmentMananger.findFragmentByTag() и вызвать этот метод.
+0

Что бы вы спасли, это «лучше». Кнопка будет нажата много раз, будет ли много передач вызывать разрядку батареи? – RiThBo

+0

В FragmentA у меня есть \t FragmentManager fm = getFragmentManager(); \t \t \t \t fm.findFragmentByTag ("FragmentB"); Как мне вызвать общедоступный метод. – RiThBo

+0

Используйте FramgmentManager.findFragmentByTag() и получите ссылку на экземпляр Fragment B, напишите открытый метод addListItem() в фрагменте B и назовите его от A. – faylon

1

Некоторые хорошие дизайнерские принципы:

  • Деятельность может знать все лобковые о любом фрагменте он содержит.
  • Фрагмент не должен знать ничего о Действия, которые его содержат.
  • Фрагмент НИКОГДА не должен знать о других фрагментах, которые могут содержать или не содержать в родительской активности.

Предлагаемый подход (неформальный шаблон проектирования), основанный на этих принципах.

Каждый фрагмент должен объявить интерфейс, который будет реализован своей родительской деятельности:

public class MyFragment extends Fragment 
{ 
    public interface Parent 
    { 
     void onMyFragmentSomeAction(); 
    } 
    private Parent mParent; 
    public onAttach(Activity activity) 
    { 
     mParent = (Parent) activity; 
    } 

    // This would actually be in a listener. Simplifying to save typing. 
    void onSomeButtonClick(View button) 
    { 
     mParent.onMyFragmentSomeAction(); 
    } 
} 

И деятельность должны осуществлять соответствующие интерфейсы для всех содержащихся в нем фрагментов.

public class MyActivity extends Activity 
         implements MyFragment.Parent, 
            YourFragment.Parent, 
            HisFragment.Parent 
{ 
    [usual Activity code] 
    void onMyFragmentSomeAction() 
    { 
    if yourFragment is showing 
    { 
     yourFragment.reactToSomeAction(); 
    } 
    if hisFragment is showing 
    { 
     hisFragment.observeThatSomeActionHappened(); 
    } 
    [etc] 
} 

Радиопередача подход хорош, тоже, но это довольно тяжеловесные и требует целевого фрагмента, чтобы знать, что вещание будет послано исходным фрагментом.

+0

Спасибо за код и info :-), я попробую это, если я не получу код скрепления для работы – RiThBo

Смежные вопросы