1

Я искал this answer и, похоже, имел дело только с одним текстовым просмотром.Обновление TextView для разных фрагментов из AsyncTask

В принципе, у меня есть приложение для Android с n фрагментами, каждый из которых имеет текстовое представление, которое заполняется из удаленного вызова в базу данных. Каждый раз, когда фрагмент выбран, этот удаленный вызов срабатывает, и текстовое изображение должно быть повторно заселено.

В настоящее время я использую центральный AsyncTask для выполнения этого, однако я начинаю задаваться вопросом, правильно ли это делается (некоторые текстовые просмотры слишком долго обновляются для небольших объемов данных, t получить обновление вообще и т. д.).

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

public class RetrieveData extends AsyncTask<String, String, String[]> { 
    private int txtViewID = -1; 
    private Activity mainActivity; 

    public RetrieveData(Activity a) { mainActivity = a; } 

    protected String[] doInBackground(String... urls) { 
    String[] data; 

    // call web script to return JSON data 
    ... 

    // figure out which fragment called which script 
    if (urls[0] == "get_A.php") { 
     data = parseJSONdata(); // parse out the JSON 
     txtViewID = R.id.txtViewA; // find INT-based ID 
    } else if (urls[0] == "get_B.php") { 
     data = parseOtherJSONdata(); // different type of call 
     txtViewID = R.id.txtViewB; 
    } else ... { 
     ... 
    } 
    } catch (Exception e) { 
    System.out.println("Error: " + e.toString()); 
    } 

    return data; 
} 

@Override 
protected void onPostExecute(String[] op) { 
    if (txtViewID != -1) { // call was made 
    TextView tv = (TextView)mainActivity.findViewById(txtViewID); 
    tv.setText(op[0]); 
} 

и вот как я называю это из фрагмента:

public class MainFragment extends Fragment { 
    Activity mainActivity; 

    public MainFragment(Activity a) { mainActivity = a; } 

    @Override 
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { 
     View v =inflater.inflate(R.layout.main_tab,container,false); 
     new RetrieveData(mainActivity).execute("get_A.php","1"); 
     return v; 
    } 
} 

мне, его очень запутано и, вероятно, противоречит моей новизну в Android, поэтому любые предложения по улучшению сердечно оценили.

ответ

2

Вы можете сделать несколько вещей, чтобы повысить надежность и производительность, и исправить некоторые проблемы, которые будут ползти в дальнейшем:

  1. Не используйте findViewById() вне методов типа инициализации/установки. Это дорогостоящий вызов, поскольку он должен «искать» вашу иерархию для запрашиваемого идентификатора.

  2. Не используйте перегруженный конструктор для вашего Fragment, который принимает Activity. Конструктор по умолчанию Fragment должен быть пустым. Это позволяет системе правильно воссоздать ваш Fragment при изменении конфигурации (экран вращается.) Fragment получит свое присоединенное Activity в нужное время, когда вызывается его метод onAttach(), поэтому нет необходимости это делать.

  3. Вам не нужно, чтобы Activity для всего, что вы пытаетесь сделать. Вместо этого сделайте свой Fragment верным TextView с вашего макета в своем onCreateView(). Что вы делаете, оттуда действительно до вас:

    • передать экземпляр TextView вашему RetrieveData конструктор класса, как один, чтобы обновить. Это устраняет жестко закодированные идентификаторы в вашем классе RetrieveData, который избавляется от некоторой явной связи и является лучшим подходом. Это все еще очень тесно связано, хотя, поскольку это зависит от наличия конкретного View, так что все еще не отличный вариант IMHO.

    • Определите внутренний интерфейс Callback и внесите его. Конструктор для RetrieveData может затем взять экземпляр интерфейса Callback (например, ваш экземпляр Fragment), и когда его onPostExecute() запускает его, он просто вызывает обратно Fragment с соответствующими данными. Теперь это зависит от вашей реализации Fragment, чтобы принять правильное решение о том, какой элемент пользовательского интерфейса он размещает для обновления данными.Теперь это может быть TextView, но в будущем вы можете сделать что-то еще и т. Д. Теперь вы отделили класс от всех явных связей интерфейса и возложили ответственность на вещи, в которых размещены элементы пользовательского интерфейса: Fragment.

Вот краткий пример 2 пули:

public RetrieveData extends AsyncTask<String, String, String[]> { 
    // Define the interface used to provide results 
    public interface Callback { 
     public void onDataLoaded(String[] result); 
    } 

    private Callback mCb; 

    public RetrieveData(Callback cb) { 
     mCb = cb; 
    } 

    ... 
    @Override 
    public void onPostExecute(String[] result) { 
     mCb.onDataLoaded(result); 
    } 
} 

public MyFragment extends Fragment implements RetrieveData.Callback { 
    TextView  mResult; 
    RetrieveData mAsyncRetriever; 

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

     // Get the TextView now where we want to show results. 
     // This avoids calling findViewById() constantly. 
     mResult = (TextView)root.findViewById(R.id.example_result); 
     ... 
    } 

    @Override 
    public void onResume() { 
     // Keep a reference to the AsyncTask so we can properly 
     // cancel it when our lifecycle events dictate so. 
     mAsyncRetriever = new RetrieveData(this); 
     mAsyncRetriever.execute("get_A.php"); 
    } 

    @Override 
    public void onPause() { 
     // If we have a pending data load going on, kill it. 
     if (mAsyncRetriever != null) { 
      mAsyncRetriever.cancel(true); 
      mAsyncRetriever = null; 
     } 
    } 

    @Override 
    public void onDataLoaded(String[] result) { 
     // Only pulling the first result provided 
     mResult.setText(result[0]); 

     // The RetrieveData is done, get rid of our ref 
     mAsyncRetriever = null; 
    } 
} 
+0

Я думаю, что основные моменты для (1), (2) и (3)/(3) все связанный с тем фактом, что я чувствовал, что мне нужно передать эту ссылку на «Активность» там. Я могу решить эту проблему. Таким образом, с внутренним обратным вызовом, я не буду следовать. Является ли callback реализацией полной AsyncTask или просто обновлением текста? – espais

+0

Я добавлю краткий пример ответа, чтобы помочь уточнить. –

+0

Это выглядит очень полезно ... Я попробую ... спасибо! – espais

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