Изменить лист из активити во фрагменте

Рейтинг: 2Ответов: 1Опубликовано: 18.12.2014

Хочу из активити во фрагменте изменить лист.
Выкидывает ошибку строки:

Fragment frag1 = getFragmentManager().findFragmentById(R.id.fragment2);

ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.rowlayout, R.id.label,  list1);
ListView lIstView  = (ListView) frag1.getView().findViewById(R.id.listView);

Последняя строка выводит ошибку:

12-18 11:00:01.066 9961-9961/com.example.eldos.callreport E/AndroidRuntime﹕ FATAL EXCEPTION: main Process: com.example.eldos.callreport, PID: 9961 java.lang.IllegalStateException: Could not execute method of the activity at android.view.View$1.onClick(View.java:3823) at android.view.View.performClick(View.java:4438) at android.view.View$PerformClick.run(View.java:18422) at android.os.Handler.handleCallback(Handler.java:733) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:136) at android.app.ActivityThread.main(ActivityThread.java:5001) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:515) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601) at dalvik.system.NativeStart.main(Native Method) Caused by: java.lang.reflect.InvocationTargetException at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:515) at android.view.View$1.onClick(View.java:3818) at android.view.View.performClick(View.java:4438) at android.view.View$PerformClick.run(View.java:18422) at android.os.Handler.handleCallback(Handler.java:733) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:136) at android.app.ActivityThread.main(ActivityThread.java:5001) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:515) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601) at dalvik.system.NativeStart.main(Native Method) Caused by: java.lang.NullPointerException at com.example.eldos.callreport.MainActivity.call(MainActivity.java:122) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:515) at android.view.View$1.onClick(View.java:3818) at android.view.View.performClick(View.java:4438) at android.view.View$PerformClick.run(View.java:18422) at android.os.Handler.handleCallback(Handler.java:733) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:136) at android.app.ActivityThread.main(ActivityThread.java:5001) at java.lang.reflect.Method.invokeNative(Native Method) at java.lang.reflect.Method.invoke(Method.java:515) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:785) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:601) at dalvik.system.NativeStart.main(Native Method)

Ответы

▲ 4Принят

Вы выбрали не самый удачный подход к решению проблемы.

Связь меж активити и фрагменами сложна, неоднозначна и ведёт к множеству проблем при неправильном понимании жизненного цикла обоих элементов.

Лучше всего (согласно моему опыту) не общаться с фрагментом напрямую из активити, а использовать, например, LocalBroadcastManager

Задача:

Обновить список из активити, присвоив ему адаптер с данными, кои есть в активити. Для этого:

Решение:

1) В onCreateView() фрагмента находим ListView и присваиваем его переменной фрагмента

ListView lV;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
    //inflate root view
    View v;
    v = inflater.inflate(R.layout.YOURS_FRAGMENT_LAYOUT_WITH_LIST_VIEW, container, false);
        this.lV=v.findViewById(R.id.YOURS_LIST_VIEW_IN_FRAGMENTS_LAYOUT_ID);
        return v;
    }

2) Создаём во фрагменте метод, принимающий данные для списка, инициализирующий адаптер и назначающий его списку:

private void setAdapterForListView(String[] yoursStringArrayWithData)
{
    ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, R.layout.rowlayout, R.id.label,  yoursStringArrayWithData);
    this.lv.setAdapter(adapter);
}

3) Описываем как должен фрагмент реагировать на сообщения LocalBroadcastManager:

private BroadcastReceiver receiver = new BroadcastReceiver()
{
    @Override
    public void onReceive(Context context, Intent intent)
    {
                //наши данные из активити придут внутри Intent
                //значит надо их вытащить
                String[] yoursStringArrayWithDataFromIntent = intent.getStringArrayExtra("stringKeyToExtractData");
                //вызываем наш метод, коий сделает адаптер с пришедшими данными
                //и присвоит его списку
        setAdapterForListView(yoursStringArrayWithDataFromIntent )
    }
};

4) Фрагмент должен знать, что умеет принимать сообщения и реагировать на них. Пишем эту строку в onCreate() фрагмента.

LocalBroadcastManager.getInstance(this.act).registerReceiver(receiver,
    new IntentFilter("setAdapterToListView"));

5) Важно научить фрагмент отмене регистрации на приём сообщений и очистке памяти. Пишем:

    @Override
public void onDestroy()
{
    //если reciver существует, то отменяем регистрацию и стираем его.
    if (receiver != null)
    {
        LocalBroadcastManager.getInstance(act).unregisterReceiver(receiver);
        receiver = null;
    }
    // Не забываем вызвать super метод в конце
    super.onDestroy();
}

6) Осталось только из активити послать сообщение с данными для адаптера, которое будет принято и обработано фрагментом. Пишем в нужном месте активити:

//Наши данные для адаптера
String[] data={"раз", "два", "три", "рубль", "расти"};
//Создаём интент, пихаем в него наши данные
Intent intent=new Intent("setAdapterToListView");
Bundle b=new Bundle();
b.putStringArray("stringKeyToExtractData", data);
intent.putExtras(b);
//Посылаем сообщение с данными
LocalBroadcastManager.getInstance(context).sendBroadcast(intent);

Итого:

1) В нужный момент (по клику или по приходу данных) из активити посылаем сообщение с данными.

2) Фрагмент ловит сообщение (определяет что это ему сообщение по строке, коя передана в конструктор intent.

3) Делает всё что нужно. В данном случае - вытаскивает данные, передаёт их списку.

Возможные проблемы:

Надо помнить о жизненном цикле. Отсылать сообщение с данными из onCreate() активити нет смысла, т.к. фрагментов ещё нет, разметки в них нет, приложение падает.