2015-01-13 4 views
0

Мне нелегко выполнять задачу, которая должна быть простой. Я не уверен, что это из-за плохой конструкции платформы Android или я чего-то не хватает. Я просто хотел бы обновить представление фрагмента на резюме. Вот подробности:Странное поведение при обновлении вида фрагмента Android

У меня есть два вида деятельности: SplashActivity, который извлекает данные с сервера (используя AsyncTask) и передает данные в мою MainActivity. В моей MainActivity я получаю эти данные и передаю их фрагменту с именем SummaryFragment. У меня есть несколько фрагментов и ящик для навигации (в моем MainActivity). Первым видимым фрагментом является SummaryFragment, который считывает данные, переданные ему из MainActivity, и, следовательно, рисует график.

Когда приложение запускается, в этом случае в моем сокращенном фрагменте не может быть активного подключения к Интернету. Я прошу пользователя включить WiFi. Я хочу сделать это, чтобы обновить представление SummaryFragment после того, как пользователь вернется в приложение после включения WiFi. То, что я делаю прямо сейчас, это то, что в onResume() моей MainActivity, я проверяю, является ли SummaryFragment видимым, и если это так, я снова запускаю SplashActivity (и закрываю текущую активность). SplashActivity должен извлекать данные (например, при запуске приложения) и запускать MainActivity (загружается с извлеченными данными), который загружает итоговый фрагмент и показывает график.

Проблема заключается в том, что она занимает значительно длительное время (30-40 секунд) после того, как приложение возобновляется, чтобы перейти от SplashActivity к MainActivity и показать график (пока пользователь видит экран заставки), в то время как когда приложение запускается, для этого требуется 1-2 секунды. Прежде чем использовать текущее решение (перенаправление пользователя на SplashActivity), в MainActivity.onResume() я попытался использовать тот же класс AsyncTask, который я использую в SplashScreen, для извлечения данных и последующего отображения итогового фрагмента, но результат тот же , существует значительная задержка.

Следующий код моего MainActivity в onResume():

Fragment fragment = getVisibleFragment(); 
if (fragment instanceof SummaryFragment) { 
    Intent intentSplashActvity = new Intent(this, SplashActivity.class); 
    Log.d(TAG, "about to start the splash activity"); 
    startActivity(intentSplashActvity); 
    // close current activity 
    finish(); 
    super.onResume(); 
    return; 
} 
super.onResume(); 

SplashActivity:

public class SplashActivity extends ActionBarActivity { 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_splash_screen); 

     new PrefetchData(this).execute(); 
    }  
} 

PrefetchData:

public class PrefetchData extends AsyncTask<Void, Void, Void> { 
    String serverResponseJson = null; 
    private String data1 = null, 
        data2 = null, 
        data3 = null; 

    private SplashActivity mSplashActivity = null; 
    private MainActivity mMainActivity; 

    public PrefetchData(Activity sourceActivity){ 
     if (sourceActivity.getClass() == SplashActivity.class) { 
      mSplashActivity = (SplashActivity) sourceActivity; 
     } 
    } 


    @Override 
    protected Void doInBackground(Void... arg0) { 
     JsonParser jsonParser = new JsonParser(); 
     try { 
      if (CaratApplication.isInternetAvailable()) { 
       serverResponseJson = jsonParser 
         .getJSONFromUrl("http://aURL"); 
      } 
     } catch (Exception e) { 
      Log.d("SplashActivity", e.getStackTrace().toString()); 
     } 
     if (serverResponseJson != null && serverResponseJson != "") { 
      try { 
       JSONArray jsonArray = new JSONObject(serverResponseJson).getJSONArray("arrayName"); 

       // Using Java reflections to set fields by passing their name to a method 
       try { 
        setFieldsFromJson(jsonArray, 0, "data1"); 
        setFieldsFromJson(jsonArray, 1, "data2"); 
        setFieldsFromJson(jsonArray, 2, "data3"); 
       } catch (IllegalArgumentException e) { 
       } catch (IllegalAccessException e) { 
       } 
      } catch (JSONException e) { 
      } 
     } 
     return null; 
    } 

    @Override 
    protected void onPostExecute(Void result) { 
     super.onPostExecute(result); 

     if (mSplashActivity != null) { 
      Intent intentMainActvity = new Intent(mSplashActivity, MainActivity.class); 

      if (gotDataSuccessfully()) { 
       intentMainActvity.putExtra("data1", data1); 
       intentMainActvity.putExtra("data2", data2); 
       intentMainActvity.putExtra("data3", data3); 
      } else { 
       intentMainActvity.putExtra("data1", Constants.DATA_NOT_AVAIABLE); 
       intentMainActvity.putExtra("data2", Constants.DATA_NOT_AVAIABLE); 
       intentMainActvity.putExtra("data3", Constants.DATA_NOT_AVAIABLE); 
      } 

      mSplashActivity.startActivity(intentMainActvity); 

      mSplashActivity.finish(); 
     } 
    } 
} 

В MainActivity, при выборе «Резюме «запись в ящике навигации, я инициализирую SummaryFragment, а затем замените его u петь фрагмент транзакции (replaceFragment (mSummaryFragment, mSummaryFragmentLabel)). Вот метод я использую, чтобы инициализировать сводную фрагмент:

private void initSummaryFragment() { 
    if (mData1 == 0 && mData2 == 0 && mData3 == 0) { 
     Intent intent = getIntent(); 
     String data1 = intent.getStringExtra("data1"); 
     String data2 = intent.getStringExtra("data2"); 
     String data3 = intent.getStringExtra("data3"); 

     boolean isDataAvaiable = !data1.equals(Constants.DATA_NOT_AVAIABLE) 
       && !data2.equals(Constants.DATA_NOT_AVAIABLE) && !data3.equals(Constants.DATA_NOT_AVAIABLE); 
     if (isDataAvaiable) { 
      mData1 = Integer.parseInt(data1); 
      mData2 = Integer.parseInt(data2); 
      mData3 = Integer.parseInt(data3); 
     } 
    } 

    mSummaryFragment = new SummaryFragment(); 
    mArgs = new Bundle();  
    mArgs.putInt("data1", mData1); 
    mArgs.putInt("data2", mData2); 
    mArgs.putInt("data3", mData3);  
    mSummaryFragment.setArguments(mArgs); 
    mSummaryFragmentLabel = getString(R.string.summary); 
} 

SummaryFragment теперь может извлекать данные ему нужно из пакета, переданного ей.

+0

Почему кто-то проголосовал за вопрос? Я предполагаю, что просто случайные вопросы с правом голоса, не давая объяснений, очень странно и невежливо. – Metallica

ответ

0

Проблема была связана с (довольно) недокументированным поведением Android AsyncTask. AsyncTask не запускается в отдельном потоке, он работает в потоке, который используется совместно с другими AsyncTasks, поэтому, если у вас есть другие AsyncTasks (или даже простой поток), если они запускаются до вашей текущей AsyncTask, это AsyncTask ждет, чтобы завершить свое действие. Я явно указал, что я бы хотел, чтобы мой AsyncTask работал в отдельном потоке, и это уменьшило задержку от 20-25 секунд до 3-4 секунд для получения объекта JSON (у меня параллельно идут другие вызовы доступа к сети). Я запускаю следующий код как часть моего метода preInitFragments() в методе onCreate() моей основной деятельности.

// The following PrefetchData class is of type AsyncTask<void, void, void>. I moved this class from a stand-alone class to an inner class inside my main activity for easier refreshing of my fragment. 
PrefetchData prefetchData = new PrefetchData(); 
// run this asyncTask in a new thread [from the thread pool] (run in parallel to other asyncTasks) 
// (do not wait for them to finish, it takes a long time) 
if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.HONEYCOMB) 
    prefetchData.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); 
else 
    prefetchData.execute(); 

После этого я вызываю свой метод initSummaryFragment(). Обратите внимание, что в моей AsyncTask, в doInBackGround(), я установил два поля (mField1 и mField2), которые вы видите ниже (я использовал для передачи их в виде пакета на итоговый экран, но таким образом возникла бы проблема, когда вы были просто снятие и прикрепление фрагмента (для обновления его представления) без передачи пакета вашему фрагменту). В onPostExecute() мой AsyncTask, я призываю мой метод refreshSummaryFragment():

private boolean isStatsDataAvailable() { 
    return mWellbehaved != 0 && mHogs != 0 && mBugs != 0; 
} 

private void initSummaryFragment() {   
    if (! isStatsDataAvailable()) { 
     mSummaryFragment = new SummaryFragment(); 
    }   
    mSummaryFragmentLabel = "Summary"; 
} 

освежающих мой сводный фрагмент, я просто отсоединить и присоединить мой сводной фрагмент, а затем совершить незавершенные транзакции фрагмента:

public void refreshSummaryFragment() { 
    if (isStatsDataAvailable()) { // blank summary fragment already attached. detach and attach to refresh 

     FragmentManager manager = getSupportFragmentManager(); 
     // init the fragment (for later use when user selects an item from the navigation drawer)    
     mSummaryFragment = getSupportFragmentManager().findFragmentByTag("Summary"); 

     FragmentTransaction fragTransaction = manager.beginTransaction(); 
     // refresh the summary fragment: 
     fragTransaction.detach(mSummaryFragment); 
     fragTransaction.attach(mSummaryFragment); 
     fragTransaction.commit(); 
    } else { 
     Log.e(TAG, "refreshSummaryFragment(): stats data not avaiable!"); 
    } 
} 
Смежные вопросы