2016-06-17 3 views
0

Не уверен, что мне здесь не хватает, но я создаю фрагмент и добавляю его с помощью FragmentManager. Вскоре после этого я запускаю метод из этого фрагмента, который должен загружать предоставленную информацию (объект Tool) в макет.onCreateView не вызывается перед запуском метода фрагментов

В InfoActivity.java:

public class InfoActivity extends AppCompatActivity{ 

... 

protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    mCatIndex = getIntent().getExtras().getInt("catIndex", 0); 
    mToolIndex = getIntent().getExtras().getInt("toolIndex", 0); 

    // If we are in two-pane layout mode, this activity is no longer necessary 
    if (getResources().getBoolean(R.bool.has_two_panes)) { 
     finish(); 
     return; 
    } 

    // Place an InfoFragment as our content pane 
    InfoFragment f = new InfoFragment(); 
    getSupportFragmentManager().beginTransaction().add(android.R.id.content, f).commit(); 

    // Display the correct tool info on the fragment 
    Tool tool = ToolsSource.getInstance(this).getCategory(mCatIndex).getTool(mToolIndex); 
    f.displayTool(tool); 
} 
} 

Однако объекты макета не инициализируются, потому что как-то метод работает до создания представления.

package com.anothergamedesigner.listviewtest; 

import android.os.Bundle; 
import android.support.v4.app.Fragment; 
import android.view.LayoutInflater; 
import android.view.View; 
import android.view.ViewGroup; 
import android.widget.TextView; 

public class InfoFragment extends Fragment { 

private TextView mTitle; 
private TextView mSubtitle; 
private TextView mDescription; 

//Tool to be displayed 
Tool mTool = null; 

//Parameterless constructor needed for framework 
public InfoFragment(){ 
    super(); 
} 

@Override 
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
    View view = inflater.inflate(R.layout.info_layout, container, false); 

    mTitle = (TextView) view.findViewById(R.id.title); 
    mSubtitle = (TextView) view.findViewById(R.id.subtitle); 
    mDescription = (TextView) view.findViewById(R.id.description); 

    loadView(); 
    return view; 
} 

public void displayTool(Tool t){ 
    mTool = t; 
    loadView(); 
} 

private void loadView(){ 
    if(mTool != null) { 
     System.out.println(mTitle.getText()); <----- error here so it's for sure the TextView returning null. 
     System.out.println(mTool.getTitleTxt()); 
     mTitle.setText(mTool.getTitleTxt()); 
     mSubtitle.setText(mTool.getSubtitleTxt()); 
     mDescription.setText(mTool.getDescriptionTxt()); 

    } 
} 
} 
+0

Почему бы вам не позвонить displayTool в конце onCreateView? –

+0

Я должен уточнить, первый бит был из другого класса InfoActivity не из того же класса. Для пояснения я редактировал декларацию класса. – NappyXIII

+0

Где находится 'setContentView' Activity? –

ответ

1

Большинство связанных с UI вещей на Android являются асинхронными, включая операции фрагмента. В основном изменения пользовательского интерфейса происходят периодически в цикле запуска. Вот некоторые способы решения этой проблемы:

Опция 1: Храните данные при вызове метода общедоступного устройства. Затем, если представление было создано, немедленно измените пользовательский интерфейс; в противном случае подождите до onViewCreated().

private Tool mTool; 

@Override 
public void onViewCreated(View view,Bundle savedInstanceState) { 
    // obtain view references 
    if (mTool != null) { 
     updateDisplay(); 
    } 
} 

public void setTool(Tool tool) { 
    mTool = tool; 
    if (getView() != null) { 
     updateDisplay(); 
    } 
} 

private void updateDisplay() { 
    // change UI here 
} 

Вариант 2: Пропустите инструмент в качестве аргумента вашего фрагмента. Для этого вам нужно сделать инструмент Parcelable, чтобы его можно было разместить внутри Bundle. Если это невозможно, вы можете вместо этого дать некоторый идентификатор инструмента и сделать фрагмент, способный извлекать инструмент на основе этого идентификатора (например, искать его в базе данных).

Это обычно делается с помощью следующей схеме (предполагая, что вы можете сделать инструмент Parcelable):

public static InfoFragment newInstance(Tool tool) { 
    InfoFragment fragment = new InfoFragment(); 
    Bundle args = new Bundle(); 
    args.putParcelable("arg_tool", tool); 
    fragment.setArguments(args); 
    return fragment; 
} 

private Tool mTool; 

@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    Bundle args = getArguments(); 
    mTool = args.getParcelable("arg_tool"); 
} 

@Override 
public void onViewCreated(View view,Bundle savedInstanceState) { 
    // obtain view references 
    if (mTool != null) { 
     updateDisplay(); 
    } 
} 

Тогда в вашей деятельности вы могли бы назвать newInstance() передавая инструмент вместо вызова конструктора. Преимущество этого второго подхода заключается в том, что у вас есть данные всякий раз, когда представления готовы, а аргументы Bundle сохраняются системой, поэтому данные не теряются при изменении конфигурации (например, путем поворота устройства).

+0

Я использовал вариант 1, и он исправил мою проблему. Но для понимания целей вы можете что-то прояснить. Я понимаю, что происходит до линии getView(). Если это возвращает false, что произойдет? Как это узнать, чтобы снова проверить утверждение if? – NappyXIII

+0

@NappyXIII 'setTool()' может произойти до или после представления для этого фрагмента. 'onViewCreated()' - это метод жизненного цикла, вызываемый после создания представления фрагмента; 'getView()' должен возвращать тот же самый вид (или null, если он еще не был создан). Вам нужен инструмент и представление, поэтому я просто жду, пока обе вещи будут существовать. Если сначала создаются представления, вы можете изменить пользовательский интерфейс в 'setTool'; если представления создаются во-вторых, вы можете изменить пользовательский интерфейс в обратном вызове жизненного цикла. – Karakuri

0

Вместо того чтобы просить фрагмент, чтобы показать данные, попробуйте это. Попросите мероприятие предоставить данные. Если это сбивает с толку, пожалуйста, прочитайте дальше,

Определите обратный вызов во фрагменте. И реализовать его в своей деятельности. Теперь после того, как onCreateView в фрагменте вызовет метод интерфейса для отображения. У вас есть ссылка на действие внутри фрагмента, которая может быть передана для обратного вызова.

Для создания обратных вызовов интерфейса для фрагмента можно использовать следующий документ. https://developer.android.com/training/basics/fragments/communicating.html

+0

Я рассмотрю это дальше, поскольку это может быть лучший дизайн. – NappyXIII

0

Вы вызываете f.displayTool(tool) в свой onCreate метод действия после выполнения транзакции фрагмента ... Так что ваш if(mTool != null) равен нулю ... Попробуйте инициализировать инструмент сразу после создания фрагмента.

public void initTool(Tool t){ 
    mTool = t; 
} 

В деятельности:

InfoFragment f = new InfoFragment(); 
// Display the correct tool info on the fragment 
Tool tool = ToolsSource.getInstance(this).getCategory(mCatIndex).getTool(mToolIndex); 
    f.initTool(tool); 
    getSupportFragmentManager().beginTransaction().add(android.R.id.content, f).commit(); 

f.displayTool(tool); 
+0

mTool не является нулевой, эта часть работает нормально. Это был mTitle, который возвращал null из-за не инициализации в OnCreateView. – NappyXIII

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