web-dev-qa-db-fra.com

android: démarrer instantanément une activité, puis charger du contenu

J'ai examiné d'autres questions, les blogs et la documentation, mais je n'arrive pas à trouver la bonne réponse à mes besoins ... J'ai deux activités, A et B. Lorsque je commence l'activité B (de A), je la veux d'ouvrir instantanément puis de charger tout le contenu tout en affichant une barre de progression, au lieu d'ouvrir l'activité uniquement lorsque le contenu est chargé, ce qui donne l'impression qu'il s'est figé pendant deux secondes ... Un exemple serait l'application Youtube ou Play. Le magasin.

C'est ce que j'ai eu:

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

C'est l'activité que je charge:

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) {

    }

}

Je ne suis pas un expert, des explications détaillées seront donc les bienvenues.

Remarque: ce que je charge dans l'activité est ce calandar: https://github.com/prolificinteractive/material-calendarview

Question: Comment charger setContentView() sur le fond?

Mise à jour: J'ai suivi les conseils de Hitesh Sahu et maintenant je n'ai qu'une activité avec un conteneur qui est remplacé pour chaque fragment, je suppose que la façon de charger le contenu xml en arrière-plan sera la même pour un fragment et une activité, mais s'il y a une différence, veuillez le mentionner.

17
John Sardinha

Solution possible

  • De "Je ne suis pas un expert", j’imagine que vous pourriez créer une nouvelle activité à chaque changement d’écran et éventuellement ne pas effacer une ancienne ou de réutiliser une activité existante. Encore une fois, je suppose que je n'ai pas vu votre code, mais j'ai vu des développeurs commettre ce genre d'erreurs. Peu à peu, les performances de votre application vont se dégrader avec le temps et votre application finira par manger de la mémoire. 

    Comment résoudre ce problème: - Remplacer activités par fragment fragment de commutation est relativement plus rapide que de changer d'activité. Vous pouvez également les réutiliser ( plus de détails à ce sujet ).

  • Vous êtes peut-être en train de faire une lourde tâche sur le fil principal de l'interface utilisateur pour rechercher choreographer logs comme - skipped n number of frames app may be doing too much work on main thread

    Comment résoudre ce problème: - déjà expliqué dans d'autres réponses.

4
Hitesh Sahu

Vous devez utiliser AsyncTask pour le chargement des données et RelativeLayout pour afficher le cercle de rotation dans ActivityB.

Première variable d'initialisation

private RelativeLayout mRelativeLayout;

et dans onCreate de votre activité, exécutez AsyncTask comme ceci 

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

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

    new PrepareData().execute();
}

mettre cette classe AsyncTask dans 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)
}

et dans XML inclure cette disposition

Pour obtenir la ProgressBar sans dialogue, il faut utiliser cette 

<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>

et définir la visibilité de ceci RelativeLayout dans onPreExecute et onPostExecute respectivement comme je l’ai montré dans l’exemple.

METTRE À JOUR:

vous devez mettre à jour votre Ui dans UiThread comme ceci 

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

 //put the code here that is giving exception

    }
});
2
Max

Votre activité B doit avoir AsyncTask pour charger des données puis les afficher . Vous pouvez également charger des données par défaut dans la vue à l'intérieur de 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);
    }

}
2

Vous pouvez utiliser une tâche asynchrone.

Ex: Ajoutez ceci dans votre page d'activité (en dehors de 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);
}
}    

Cette classe est exécutée en appelant 

new OnLoading().execute();

Lors de l'exécution de ce code, la première fonction exécutée sera onPreExecute-> doInBackGround-> onPostExecute. . Progress update peut être utilisé pour afficher certains progrès de la fonction doInBackGround en appelant 

publishProgress(value);

Ici tout d'abord, ProgressDialog sera affiché. Fournissez le code pour charger les données, etc. dans doInBackground. Comme son nom l'indique, tout ce que vous écrivez dans cette fonction sera exécuté en arrière-plan. Une fois l'exécution de cette fonction terminée, la boîte de dialogue de progression sera fermée dans onPostExecute ().

2
Akhil Soman

Il suffit de mettre ce code:

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

Dans A onCreate. Créez ensuite un ProgressDialog comme celui-ci: http://www.tutorialspoint.com/Android/android_progressbar.htm

Cela montrera la progression du chargement de B. Tu appelleras 

progress.setProgress(int)

dans B onCreate, après avoir fait quelque chose.

Par exemple:

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);
    }
    .....

MODIFIER

Voici comment vous pouvez le faire en utilisant un ProgressBar:

  • ajouter une disposition ProgressBar à B
  • obtenir une référence à cette ProgressBar dans la onCreate de B (en utilisant findViewById()
  • mettre à jour votre ProgressBar avec setProgress(int) chaque fois que vous le souhaitez (comme indiqué dans la première partie de la question pour ProgressDialog)
  • cacher votre ProgressBar en utilisant votre ProgressBar.setVisibility(View.GONE)
1
Andre99

On dirait que vous faites tout (y compris le chargement lourd) dans la fonction onCreate. Examinez le cycle de vie Activité et envisagez de mettre du code, par exemple. onStart ou onResume. En outre, des éléments lourds peuvent être placés sur un thread worker par exemple. Ceci garde votre interface utilisateur réactive et l'utilisateur plus heureux.

1
Gooey

Vous devez utiliser un ViewStub pour tout ce dont vous n'avez pas besoin immédiatement. Gonfler des vues à partir de dispositions XML peut s'avérer une opération assez coûteuse, en particulier si vous avez plusieurs ViewGroups imbriqués. Un ViewStub fonctionne en décalant une inflation de mise en page inutile de onCreate () à l'endroit de votre choix, ce qui signifie que votre activité s'affiche plus rapidement à l'écran.

<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>

Maintenant que la barre de progression est affichée à l'écran, nous pouvons gonfler le ViewStub dans un appel de cycle de vie après onCreate (), tel que onPostCreate () ou onResume (). Vous pouvez y parvenir en utilisant ce qui suit:

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();

Il serait certainement intéressant d’inspecter votre hiérarchie View et de simplifier autant que possible les ViewGroups imbriqués, dans la mesure où cela peut réellement affecter les performances en termes d’affichage. Si l'ensemble de votre application est lente, cela peut indiquer des problèmes plus graves, tels qu'une fuite de mémoire, que vous pouvez détecter avec LeakCanary .

0
fractalwrench

Commencez d'abord votre activité par

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

quelle que soit l’événement que vous avez choisi, voici comment votre activité B devrait fonctionner.

 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) {

  }
}

Edit: comme @ Andre99 l'a montré en utilisant progressbar:

-ajouter une barre de progression à la disposition B

-obtenir une référence à cette barre de progression dans B onCreate de B (à l'aide de findViewById ()

- Mettez à jour votre barre de progression avec setProgress (int) chaque fois que vous le souhaitez (comme indiqué dans la première partie de la question pour ProgressDialog)

- masquez votre barre de progression à l'aide de votreProgressBar.setVisibility (View.GONE)

0
Akash Raghav

Vous pouvez essayer comme ci-dessous le code:

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);

Espérons que cela fonctionnera correctement. Bonne chance.

0
user4356416