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.
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.
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
}
});
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);
}
}
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 ().
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:
ProgressBar
à BProgressBar
dans la onCreate
de B (en utilisant findViewById()
ProgressBar
avec setProgress(int)
chaque fois que vous le souhaitez (comme indiqué dans la première partie de la question pour ProgressDialog
)ProgressBar
en utilisant votre ProgressBar.setVisibility(View.GONE)
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.
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 .
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)
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.