Подтвердить что ты не робот

Android: мгновенно запустите действие, а затем загрузите контент

Я изучил другие вопросы, блоги и документацию и не могу найти правильный ответ на свои вопросы. У меня есть два действия, A и B. Когда я запускаю действие B (из A), я хочу, чтобы оно открывалось мгновенно, а затем загружало весь контент, отображая индикатор выполнения, вместо того, чтобы открывать только действие, когда контент загружен, делая его кажется, что он замерз на две секунды. Примером может служить приложение Youtube или магазин Play Store.

Вот что я получил:

Button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent goB = new intent(ActivityA.this, ActivityB.class);
            startActivity(goB);
        }
    });

Это действие, которое я загружаю:

public class ActivityB extends AppCompatActivity implements OnDateSelectedListener, OnMonthChangedListener {

    private static final DateFormat FORMATTER = SimpleDateFormat.getDateInstance();

    @Bind(R.id.calendarView) MaterialCalendarView widget;
    @Bind(R.id.textView) TextView textView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_c_calendar);
        ButterKnife.bind(this);
        widget.setOnDateChangedListener(this);
        widget.setOnMonthChangedListener(this);
        textView.setText(getSelectedDatesString());

    }

    @Override
    public void onDateSelected(@NonNull MaterialCalendarView widget, @Nullable CalendarDay date, boolean selected) {
        textView.setText(getSelectedDatesString());
    }

    private String getSelectedDatesString() {
        CalendarDay date = widget.getSelectedDate();
        if (date == null) {
            return "No Selection";
        }
        return FORMATTER.format(date.getDate());
    }

    @Override
    public void onMonthChanged(MaterialCalendarView widget, CalendarDay date) {

    }

}

Я не эксперт, поэтому подробные объяснения будут приветствоваться.

Примечание. В этом упражнении загружается следующий календарь: https://github.com/prolificinteractive/material-calendarview

Вопрос: Как загрузить setContentView() в фоновом режиме?

Обновление: я последовал совету Hitesh Sahu, и теперь у меня есть только одно действие с одним контейнером, который заменяется для каждого фрагмента, я предполагаю, что способ загрузки содержимого XML в фоновом режиме будет одинаковым для фрагмента и действия, но если есть какая-либо разница, пожалуйста, укажите.

4b9b3361

Ответ 1

Замените свои действия на фрагменты и используйте AsynkTask

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

    new addDataAsync().execute();

    return view;
}

    private class addDataAsync extends AsyncTask<Void, Void, Void> {

    protected Void doInBackground(Void... param) {

        //Do your background stuff, initializations, downloads etc
        return null;
    }

    protected void onPostExecute(Void param) {

        // Do the stuff that changes the UI, adding views etc

    }

Ответ 2

Возможное решение

  • От "Я не эксперт" Я предполагаю, что вы можете создавать новую активность при каждом переключении экрана и, возможно, не очищать старые или повторно использовать существующую активность. Опять же, это моя догадка, что я не видел ваш код, но я видел, как разработчики совершают такие ошибки. В то же время производительность вашего приложения со временем ухудшится, и ваше приложение в конечном итоге поедает память.

    Как исправить это: - Заменить действия фрагментом переключения фрагмент относительно быстрее, чем операции переключения, и вы можете повторно использовать их (подробнее об этом).

  • Возможно, вы выполняете какую-то тяжелую задачу в главной теме Ui, ищите choreographer журналы - skipped n number of frames app may be doing too much work on main thread

    Как исправить это: - уже объяснено в других ответах.

Ответ 3

Для загрузки данных и RelativeLayout вам нужно использовать AsyncTask для отображения Rounding Circle в ActivityB.

Первая инициализирующая переменная

private RelativeLayout mRelativeLayout;

а в onCreate вашей активности выполните AsyncTask, как этот

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    mRelativeLayout = (RelativeLayout) findViewbyID(R.id.loadingCircle);

    new PrepareData().execute();
}

поместите этот класс AsyncTask в ActivityB

private class PrepareData extends AsyncTask<Void, Void, Void> {

    protected void onPreExecute(Void param) {
        // THIS WILL DISPLAY THE PROGRESS CIRCLE
        mRelativeLayout.setVisibility(View.VISIBLE)


    }

    protected Void doInBackground(Void... param) {

        // PUT YOUR CODE HERE TO LOAD DATA

        return null;
    }

    protected void onPostExecute(Void param) {
        // THIS WILL DISMISS CIRCLE
        mRelativeLayout.setVisibility(View.GONE)
}

и в XML включить этот макет

Чтобы получить ProgressBar без диалога, нужно использовать этот

<RelativeLayout
    android:id="@+id/loadingCircle"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:visibility="gone"
    android:gravity="center" >

<ProgressBar
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:indeterminate="true" />
</RelativeLayout>

и установите видимость этого RelativeLayout в onPreExecute и onPostExecute соответственно, как показано в примере.

UPDATE:

вам нужно обновить Ui в UiThread, как это,

runOnUiThread(new Runnable() {
 @Override
 public void run() {

 //put the code here that is giving exception

    }
});

Ответ 4

Вы можете использовать AsyncTask.

Например: Добавьте это на свою страницу активности (вне onCreate()).

class OnLoading extends AsyncTask<Void,Void,Void>{

ProgressDialog pd;
@Override
protected void onPreExecute() {
    super.onPreExecute();
    pd=new ProgressDialog(Main2Activity.this);
    pd.setTitle("Title");
    pd.setMessage("Message");
    pd.setCancelable(false);
    pd.show();
}

@Override
protected Void doInBackground(Void... params) {
    //
    //Do all your loading stuff here
    //
    return null;
}

@Override
protected void onPostExecute(Void aVoid) {
    super.onPostExecute(aVoid);
    pd.dismiss();
}

@Override
protected void onProgressUpdate(Void... values) {
    super.onProgressUpdate(values);
}
}    

Этот класс выполняется при вызове

new OnLoading().execute();

При выполнении этого кода первая выполняемая функция будет onPreExecute- > doInBackGround- > onPostExecute.. Обновление выполнения может быть использовано для отображения некоторого прогресса из функции doInBackGround, вызвав

publishProgress(value);

Здесь сначала будет показан ProgressDialog. Предоставьте код для загрузки данных и т.д. В doInBackground. Поскольку название подразумевает все, что вы пишете в этой функции, будет выполняться в фоновом режиме. После завершения этой функции диалог выполнения будет отклонен в onPostExecute().

Ответ 5

Ваша активность B должна иметь AsyncTask для загрузки данных, а затем их отображения. Кроме того, вы можете загрузить некоторые данные по умолчанию внутри OnPreExecute()

@Override
protected void onCreate(Bundle savedInstanceState) {
    setupViews();
}

private void setupViews(){
    someView1 = (TextView) findViewById(R.id.some_view_id1);
    someView2 = (TextView) findViewById(R.id.some_view_id2);
    someView3 = (ImageView) findViewById(R.id.some_view_id3);
    progressBar = (ProgressBar) findViewById(R.id.progress_bar_id);
    new LoadDataForActivity().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}

private class LoadDataForActivity extends AsyncTask<Void, Void, Void> {

String data1;
String data2;
Bitmap data3;

    @Override
    protected void onPreExecute() {
        progressBar.setVisibility(View.VISIBLE);
    }
    @Override
    protected Void doInBackground(Void... params) {
        data1 = loadData1();
        data2 = loadData2();
        data3 = loadData3();
    }

    @Override
    protected void onPostExecute(Void result) {
        someView1.setText(data1);
        someView2.setText(data2);
        someView3.setImageBitmap(data3);
        progressBar.setVisibility(View.GONE);
    }

}

Ответ 6

Просто введите этот код:

Intent goB = new intent(ActivityA.this, ActivityB.class);
startActivity(goB);

В A onCreate. Затем создайте ProgressDialog, как показано здесь: http://www.tutorialspoint.com/android/android_progressbar.htm

Это покажет ход загрузки B. Вы назовете

progress.setProgress(int)

в B onCreate, после чего-то.

Например:

public class B extends Activity {
    public void onCreate(Bundle bundle) {
        progress=new ProgressDialog(this);
        progress.setMessage("Downloading Music");
        progress.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        progress.setIndeterminate(true);
        progress.setProgress(0);
        progress.show();

        //do something
        progress.setProgress(1);
        //do something
        progress.setProgress(2);
        //do something different
        progress.setProgress(3);
    }
    .....

ИЗМЕНИТЬ

Вот как вы можете это сделать, используя ProgressBar:

  • добавить макет ProgressBar to B
  • получите ссылку на этот ProgressBar в B onCreate (используя findViewById()
  • обновляйте ProgressBar с помощью setProgress(int) каждый раз, когда хотите (как показано в первой части вопроса для ProgressDialog)
  • спрячь свой ProgressBar с помощью ProgressBar.setVisibility(View.GONE)

Ответ 7

Похоже, что вы делаете все (включая тяжелую загрузку) в функции onCreate. Взгляните на жизненный цикл деятельности и рассмотрите вопрос о том, чтобы ввести код, например. onStart или onResume. Кроме того, тяжелый материал может быть помещен в рабочий поток . Этот сохраняет ваш пользовательский интерфейс отзывчивым, а пользователь более счастлив.

Ответ 8

Сначала начните свою деятельность как

startActivity(new intent(A.this, B.class));

из любого события, которое вы выбрали, вот как ваша деятельность B должна работать.

 class B extends AppCompatActivity implements OnDateSelectedListener, OnMonthChangedListener {

  private static final DateFormat FORMATTER = SimpleDateFormat.getDateInstance();

  @Bind(R.id.calendarView) MaterialCalendarView widget;
  @Bind(R.id.textView) TextView textView;

  ProgressDialog progressDialog;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_b);
    if(!B.this.isFinishing() && progressDialog != null && !progressDialog.isShowing()) {
        progressDialog.show();
    Handler handler = new Handler();
    handler.postDelayed(new Runnable() {
    @Override
    public void run() {
      ButterKnife.bind(B.this);
      widget.setOnDateChangedListener(B.this);
      widget.setOnMonthChangedListener(B.this);
      textView.setText(getSelectedDatesString());

      if(!B.this.isFinishing() && progressDialog != null &&  progressDialog.isShowing()) {
        progressDialog.hide();
      }
    }, 1500);
  }

  @Override
  public void onDateSelected(@NonNull MaterialCalendarView widget, @Nullable CalendarDay date, boolean selected) {
      textView.setText(getSelectedDatesString());
  }

  private String getSelectedDatesString() {
    CalendarDay date = widget.getSelectedDate();
    if (date == null) {
        return "No Selection";
    }
    return FORMATTER.format(date.getDate());
  }

  @Override
  public void onMonthChanged(MaterialCalendarView widget, CalendarDay date) {

  }
}

Изменить: как @Andre99 показал использование progressbar:

-add макет ProgressBar to B

-get ссылку на этот ProgressBar в B onCreate (используя findViewById()

-подтвердите свой ProgressBar с помощью setProgress (int) каждый раз, когда вы хотите (как показано в первой части вопроса для ProgressDialog)

-hide ваш ProgressBar, используя yourProgressBar.setVisibility(View.GONE)

Ответ 9

Вы должны использовать ViewStub для всего, что вам не нужно немедленно отображать. Раздувание представлений из макетов XML может быть довольно дорогостоящей операцией, особенно если у вас есть несколько вложенных групп представлений. ViewStub работает, компенсируя ненужную инфляцию раскладки от onCreate() до места по вашему выбору, что приводит к ускорению вашей активности, появляющейся на экране.

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView 
        android:id="@+id/textview"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

    <ProgressBar 
        android:id="@+id/progressbar"
        android:layout_width="match_parent"
        android:indeterminate="true"
        android:layout_height="match_parent"/>

    <ViewStub 
        android:id="@+id/view_stub"
        android:inflatedId="@+id/calendarView"
        android:layout="@layout/my_expensive_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

Теперь, когда ProgressBar отображается на экране, мы можем раздуть ViewStub в вызове жизненного цикла после onCreate(), например onPostCreate() или onResume(). Вы можете добиться этого, используя следующее:

viewStub.setOnInflateListener(new OnInflateListener() {
    void onInflate(ViewStub stub, View inflated) {

        calendarView = (MaterialCalendarView) inflated.findViewById(R.id.calendarView);
        // perform any calendar setup here
        progressBar.setVisibility(View.GONE); // hide progressbar, no longer needed
    }
});
viewStub.inflate();

Конечно, стоит проверить иерархию View и упростить любые вложенные группы просмотра, если это возможно, так как это может действительно вызвать хиты, когда дело доходит до представления производительности. Если ваше приложение работает медленно, это может указывать на большие проблемы, такие как утечка памяти, которую вы можете обнаружить с помощью LeakCanary.

Ответ 10

Вы можете попробовать, как показано ниже:

Intent intent= new Intent(currentActivity.this, targetActivity.class);
                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
                startActivity(intent);

Надежда, она будет работать правильно. Удачи.