Skip to content

Commit

Permalink
Use AsyncLayoutInflater in CardFilters widget
Browse files Browse the repository at this point in the history
CardFilters widget uses a complex layout which was slowing down app
initialization, restore from background and screen rotation. In other
words, anything which caused its views to be inflated.

In order to mitigate that, now CardFilters widget inflates
asynchronously its layout so the UI thread is free.

This required a lot of changes regarding initialization of the widget as
well as saving and restoring its state. As the layout would be inflated
later, a lot of initialization code was migrated to the callback of the
layout inflation.

Thanks guys of Android team for providing such a nice utility class!

Fix #51, #52
  • Loading branch information
franciscojunior committed Feb 2, 2018
1 parent d3ce194 commit 36139c6
Showing 1 changed file with 109 additions and 45 deletions.
154 changes: 109 additions & 45 deletions app/src/main/java/name/vampidroid/ui/widget/CardFilters.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,21 @@
import android.os.Bundle;
import android.os.Parcelable;
import android.support.v4.content.ContextCompat;
import android.support.v4.view.AsyncLayoutInflater;
import android.util.AttributeSet;
import android.util.Log;
import android.util.SparseArray;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.Transformation;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.TextView;


import com.github.florent37.expansionpanel.ExpansionLayout;

import name.vampidroid.R;


Expand Down Expand Up @@ -50,6 +48,17 @@ public class CardFilters extends LinearLayout {


boolean isResetting = false;
private SparseArray<Parcelable> restoreInstanceStateData;

private boolean clanExpansionLayoutExpanded;
private boolean cryptDisciplinesExpansionLayoutExpanded;
private boolean cardTypesExpansionLayoutExpanded;
private boolean libraryDisciplinesExpansionLayoutExpanded;

private boolean isInflateFinished;
private boolean showCryptFiltersAfterLayoutInflated = false;
private boolean showLibraryFiltersAfterLayoutInflated = false;


public interface OnCardFiltersChangeListener {

Expand Down Expand Up @@ -92,40 +101,69 @@ public CardFilters(Context context, AttributeSet attrs, int defStyleAttr, int de

private void init() {

LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
isInflateFinished = false;
AsyncLayoutInflater asyncLayoutInflater = new AsyncLayoutInflater(getContext());
asyncLayoutInflater.inflate(R.layout.widget_card_filters_layout, this, new AsyncLayoutInflater.OnInflateFinishedListener() {
@Override
public void onInflateFinished(View view, int resid, ViewGroup parent) {

addView(view);

isInflateFinished = true;

if (restoreInstanceStateData != null) {

// Only update header status when the layout has been inflated.
updateFilterHeaderStatus((TextView) findViewById(R.id.textClans), numberOfClansFiltersApplied);
updateFilterHeaderStatus((TextView) findViewById(R.id.textCardTypes), numberOfCardTypesFiltersApplied);
updateFilterHeaderStatus((TextView) findViewById(R.id.textLibraryDisciplines), numberOfLibraryDisciplineFiltersApplied);
updateFilterHeaderStatus((TextView) findViewById(R.id.textDisciplines), numberOfCryptDisciplineFiltersApplied);


View inflated = inflater.inflate(R.layout.widget_card_filters_layout, this, false);
// Update expanded state of the expansion layouts
updateExpansionLayoutExpanded((ExpansionLayout) findViewById(R.id.expansionDisciplinesLayout), cryptDisciplinesExpansionLayoutExpanded);
updateExpansionLayoutExpanded((ExpansionLayout) findViewById(R.id.expansionClansLayout), clanExpansionLayoutExpanded);
updateExpansionLayoutExpanded((ExpansionLayout) findViewById(R.id.expansionLibraryTypesLayout), cardTypesExpansionLayoutExpanded);
updateExpansionLayoutExpanded((ExpansionLayout) findViewById(R.id.expansionLibraryDisciplinesLayout), libraryDisciplinesExpansionLayoutExpanded);

addView(inflated);
initViews();
// Restore state from the view which was just inflated.
// Here we use the state given by the dispatchRestoreState method. As at the time dispatchRestoreIntanceState method
// was called the view hasn't been inflated yet, we just stored that state to be used here when the view finishes being
// inflated.
view.restoreHierarchyState(restoreInstanceStateData);

// AsyncLayoutInflater asyncLayoutInflater = new AsyncLayoutInflater(getContext());
// asyncLayoutInflater.inflate(R.layout.widget_card_filters_layout, this, new AsyncLayoutInflater.OnInflateFinishedListener() {
// @Override
// public void onInflateFinished(View view, int resid, ViewGroup parent) {
//
// if (container != null) {
// CardFilters.super.dispatchRestoreInstanceState(container);
// container = null;
// }
//
// addView(view);
// initViews();
//
// }
// });
restoreInstanceStateData = null;
}

cryptFiltersLayoutGroup = findViewById(R.id.cryptFiltersLayoutGroup);
libraryFiltersLayoutGroup = findViewById(R.id.libraryFiltersLayoutGroup);

setupViewHandlers();

// Check if it was requested to show a group of filters before layout inflated.
if (showCryptFiltersAfterLayoutInflated) {
showCryptFilters();
} else if (showLibraryFiltersAfterLayoutInflated) {
showLibraryFilters();
}


}
});


}

void initViews() {
void updateExpansionLayoutExpanded(ExpansionLayout expansionLayout, boolean expanded) {
if (expanded) {
expansionLayout.expand(false);
}
}

cryptFiltersLayoutGroup = findViewById(R.id.cryptFiltersLayoutGroup);
libraryFiltersLayoutGroup = findViewById(R.id.libraryFiltersLayoutGroup);
void setupViewHandlers() {

setupGroupsHandler();


setupCryptDisciplinesHandler();

setupClansHandler();
Expand Down Expand Up @@ -186,11 +224,11 @@ public void onStopTrackingTouch(SeekBar seekBar) {

@Override
protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
Log.d(TAG, "dispatchRestoreInstanceState() called with: container = [" + container + "]");
super.dispatchRestoreInstanceState(container);
// Doesn't restore child states yet because they may not have been inflated yet.
// Don't restore child states yet because they may not have been inflated yet.
// Keep the state to be used later.
// this.container = container;
this.restoreInstanceStateData = container;

super.dispatchRestoreInstanceState(container);
}

@Override
Expand All @@ -201,33 +239,48 @@ protected Parcelable onSaveInstanceState() {
Parcelable superState = super.onSaveInstanceState();
state.putParcelable("superState", superState);

// Only save numberOf*FiltersApplied state which can't be reproduced. The filters which have a handler for the checkbox click will
// restore the values when restoring checkbox state.

state.putInt("numberOfGroupFiltersApplied", numberOfGroupFiltersApplied);
state.putInt("numberOfCapacityFiltersApplied", numberOfCapacityFiltersApplied);
state.putInt("numberOfCryptDisciplineFiltersApplied", numberOfCryptDisciplineFiltersApplied);
state.putInt("numberOfLibraryDisciplineFiltersApplied", numberOfLibraryDisciplineFiltersApplied);
state.putInt("numberOfClansFiltersApplied", numberOfClansFiltersApplied);
state.putInt("numberOfCardTypesFiltersApplied", numberOfCardTypesFiltersApplied);
state.putInt("numberOfLibraryDisciplineFiltersApplied", numberOfLibraryDisciplineFiltersApplied);

ExpansionLayout expansionDisciplinesLayout = findViewById(R.id.expansionDisciplinesLayout);
state.putBoolean("cryptDisciplinesExpansionLayoutExpanded", expansionDisciplinesLayout.isExpanded());

ExpansionLayout expansionClansLayout = findViewById(R.id.expansionClansLayout);
state.putBoolean("clanExpansionLayoutExpanded", expansionClansLayout.isExpanded());

ExpansionLayout expansionLibraryTypesLayout = findViewById(R.id.expansionLibraryTypesLayout);
state.putBoolean("cardTypesExpansionLayoutExpanded", expansionLibraryTypesLayout.isExpanded());

ExpansionLayout expansionLibraryDisciplinesLayout = findViewById(R.id.expansionLibraryDisciplinesLayout);
state.putBoolean("libraryDisciplinesExpansionLayoutExpanded", expansionLibraryDisciplinesLayout.isExpanded());

return state;
}

@Override
protected void onRestoreInstanceState(Parcelable state) {
Log.d(TAG, "onRestoreInstanceState() called with: state = [" + state + "]");

if (state instanceof Bundle) {
Log.d(TAG, "onRestoreInstanceState: Restoring from bundle");
Bundle bundle = (Bundle) state;
super.onRestoreInstanceState(bundle.getParcelable("superState"));


numberOfGroupFiltersApplied = bundle.getInt("numberOfGroupFiltersApplied");
numberOfCapacityFiltersApplied = bundle.getInt("numberOfCapacityFiltersApplied");
numberOfCryptDisciplineFiltersApplied = bundle.getInt("numberOfCryptDisciplineFiltersApplied");
numberOfLibraryDisciplineFiltersApplied = bundle.getInt("numberOfLibraryDisciplineFiltersApplied");
numberOfClansFiltersApplied = bundle.getInt("numberOfClansFiltersApplied");
numberOfCardTypesFiltersApplied = bundle.getInt("numberOfCardTypesFiltersApplied");
numberOfLibraryDisciplineFiltersApplied = bundle.getInt("numberOfLibraryDisciplineFiltersApplied");

updateFilterHeaderStatus((TextView) findViewById(R.id.textClans), numberOfClansFiltersApplied);
updateFilterHeaderStatus((TextView) findViewById(R.id.textCardTypes), numberOfCardTypesFiltersApplied);
updateFilterHeaderStatus((TextView) findViewById(R.id.textLibraryDisciplines), numberOfLibraryDisciplineFiltersApplied);
cryptDisciplinesExpansionLayoutExpanded = bundle.getBoolean("cryptDisciplinesExpansionLayoutExpanded");
clanExpansionLayoutExpanded = bundle.getBoolean("clanExpansionLayoutExpanded");
cardTypesExpansionLayoutExpanded = bundle.getBoolean("cardTypesExpansionLayoutExpanded");
libraryDisciplinesExpansionLayoutExpanded = bundle.getBoolean("libraryDisciplinesExpansionLayoutExpanded");

} else {
super.onRestoreInstanceState(state);
Expand Down Expand Up @@ -419,16 +472,27 @@ public void setOnCardFiltersChangeListener(OnCardFiltersChangeListener listener)

public void showCryptFilters() {

cryptFiltersLayoutGroup.setVisibility(VISIBLE);
libraryFiltersLayoutGroup.setVisibility(GONE);
if (isInflateFinished) {
cryptFiltersLayoutGroup.setVisibility(VISIBLE);
libraryFiltersLayoutGroup.setVisibility(GONE);
} else {
showCryptFiltersAfterLayoutInflated = true;
showLibraryFiltersAfterLayoutInflated = false;
}


}

public void showLibraryFilters() {

libraryFiltersLayoutGroup.setVisibility(VISIBLE);
cryptFiltersLayoutGroup.setVisibility(GONE);

if (isInflateFinished) {
libraryFiltersLayoutGroup.setVisibility(VISIBLE);
cryptFiltersLayoutGroup.setVisibility(GONE);
} else {
showCryptFiltersAfterLayoutInflated = false;
showLibraryFiltersAfterLayoutInflated = true;
}

}

Expand Down

0 comments on commit 36139c6

Please sign in to comment.