I'm developing an Activity with a ViewPager
that contains Fragments (Max 4 fragment each time) when each containing TableLayout
. So basically 4 Tables are loaded. This is the code for loading the data into the Fragment
which is later attached to the ViewPager
:
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
if (container == null) {
return null;
}
LinearLayout.LayoutParams layoutParams=new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
layoutParams.gravity=Gravity.CENTER_VERTICAL;
layoutParams.setMargins(10, 0, 0, 0);
fragmetLayout = (LinearLayout)inflater.inflate(R.layout.grid_fragment_layout, container, false);
table = (TableLayout) fragmetLayout.findViewById(R.id.tlGridTable);
llParameterContainer = (LinearLayout) fragmetLayout.findViewById(R.id.llParametersContainer);
tabName = (TextView) fragmetLayout.findViewById(R.id.tvTabName);
tabName.setText(tab.getTabName());
//tabName.setLayoutParams(layoutParams);
for (Parameter parameter : SGRaportManagerAppObj.getInstance().parametersRepository.getParametersRepository())
{
ImageView parameterPoint = new ImageView(getActivity());
parameterPoint.setImageResource(R.drawable.parameter_chosen_point);
parameterPoint.setPadding(10, 10, 10, 0);
parameterPoint.setLayoutParams(layoutParams);
llParameterContainer.addView(parameterPoint);
TextView parameterTextView = new TextView(getActivity());
parameterTextView.setText(parameter.getName()+":");
parameterTextView.setGravity(Gravity.CENTER);
parameterTextView.setTextColor(getResources().getColor(R.color.my_black));
parameterTextView.setPadding(5, 10, 3, 10);
parameterTextView.setLayoutParams(layoutParams);
llParameterContainer.addView(parameterTextView);
TextView parameterChosenValueTextView = new TextView(getActivity());
parameterChosenValueTextView.setText(parameter.getChosenValue());
parameterChosenValueTextView.setGravity(Gravity.CENTER);
parameterChosenValueTextView.setPadding(0, 10, 0, 10);
parameterChosenValueTextView.setLayoutParams(layoutParams);
parameterChosenValueTextView.setTextColor(getResources().getColor(R.color.my_black));
llParameterContainer.addView(parameterChosenValueTextView);
}
//table.setStretchAllColumns(true);
//table.setShrinkAllColumns(true);
TableRow tableRow = new TableRow(getActivity());
TableLayout.LayoutParams tableRowParams=new TableLayout.LayoutParams(TableLayout.LayoutParams.WRAP_CONTENT,TableLayout.LayoutParams.WRAP_CONTENT);
tableRowParams.setMargins(2, 0, 0, 0);
tableRow.setLayoutParams(tableRowParams);
Log.d(TAG, "TAB FROM FRAGMENT:"+tab.toString());
TableRow.LayoutParams tlparamsFirstColumn = new TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT);
tlparamsFirstColumn.setMargins(4, 0, 2, 0);
TableRow.LayoutParams tlparams = new TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT);
tlparams.setMargins(0, 0, 2, 0);
//The First row for the column names.
for (int i= 0; i < tab.getGrid().getGridColumnsList().size(); i++)
{
TextView tvName = new TextView(getActivity());
String columnName = tab.getGrid().getGridColumnsList().get(i).getGridColumnAlias();
tvName.setText(columnName);
Log.d(TAG, "COLUMN ALIAS FROM FRAGMENT: "+columnName);
if (i == 0)
{
tvName.setLayoutParams(tlparamsFirstColumn);
}
else
{
tvName.setLayoutParams(tlparams);
}
tvName.setGravity(Gravity.CENTER);
tvName.setTextColor(getResources().getColor(R.color.my_white));
tvName.setPadding(10, 10, 10, 10);
tvName.setBackgroundDrawable(getResources().getDrawable(R.drawable.grid_column_name_background));
tableRow.addView(tvName);
}
table.addView(tableRow);
for (int j = 0; j < tab.getGrid().getGridData().getNumRows(); j++)
{
TableRow newRow = new TableRow(getActivity());
TableLayout.LayoutParams insideRowParams=new TableLayout.LayoutParams(TableLayout.LayoutParams.WRAP_CONTENT,TableLayout.LayoutParams.WRAP_CONTENT);
tableRowParams.setMargins(0, 2, 0, 0);
for (int k = 0; k < tab.getGrid().getGridData().getNumCols(j); k++)
{
TextView tvName = new TextView(getActivity());
String columnName = tab.getGrid().getGridData().get(j, k);
tvName.setText(columnName);
if ( (j % 2) == 0)
{
tvName.setBackgroundDrawable(getResources().getDrawable(R.drawable.grid_first_row_background));
}
else
{
tvName.setBackgroundDrawable(getResources().getDrawable(R.drawable.grid_second_row_background));
}
if (k == 0)
{
tvName.setLayoutParams(tlparamsFirstColumn);
}
else
{
tvName.setLayoutParams(tlparams);
}
tvName.setGravity(Gravity.CENTER);
tvName.setTextColor(getResources().getColor(R.color.my_black));
tvName.setPadding(10, 10, 10, 10);
newRow.addView(tvName);
}
table.addView(newRow);
}
return fragmetLayout;
}
UPDATE:
My ViewPagerActivity Layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<TabHost
android:id="@android:id/tabhost"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_below="@+id/imageView3" >
<LinearLayout
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<FrameLayout
android:id="@android:id/tabcontent"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_weight="0"/>
<android.support.v4.view.ViewPager
android:id="@+id/pager"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1" >
</android.support.v4.view.ViewPager>
<TabWidget
android:id="@android:id/tabs"
android:orientation="horizontal"
android:layout_gravity="center_horizontal"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</TabHost>
<ImageView
android:id="@+id/imageView3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="-3dp"
android:background="@drawable/login_scr_top_bar"
android:contentDescription="@drawable/login_scr_top_bar" />
<TextView
android:id="@+id/tvReportName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top|left"
android:paddingLeft="15dp"
android:paddingTop="13dp"
android:text="@string/report_tabs"
android:textColor="@color/my_black"
android:textSize="18sp"
android:textStyle="bold" />
<LinearLayout
android:id="@+id/llTabsButtonsContainer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:gravity="center_horizontal"
android:orientation="horizontal"
android:paddingBottom="5dp"
android:paddingTop="5dp" >
</LinearLayout>
<TextView
android:id="@+id/tvReportTitle"
android:layout_width="wrap_content"
android:layout_height="20dp"
android:layout_alignBaseline="@+id/tvReportName"
android:layout_alignBottom="@+id/tvReportName"
android:layout_toLeftOf="@+id/bBackToParameters"
android:layout_toRightOf="@+id/tvReportName"
android:text="TextView"
android:textSize="18sp" />
<Button
android:id="@+id/bBackToParameters"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@+id/tvReportTitle"
android:layout_marginRight="10dp"
android:layout_alignParentRight="true"
android:background="@drawable/button_back_to_parameters_selector"
android:clickable="true"
android:onClick="backToParametersButtonOnClick"
android:padding="3dp"
android:text="@string/back_to_parameters"
android:textColor="@color/my_white"
android:textStyle="bold" />
</RelativeLayout>
and My GridFramgnet Layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<LinearLayout
android:id="@+id/llParametersContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal" >
</LinearLayout>
<TextView
android:id="@+id/tvTabName"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="@color/my_black"
android:textStyle="bold"
android:textSize="18sp"
android:layout_marginLeft="10dp"
android:text="It a test string for report Name"/>
<ScrollView
android:id="@+id/layout"
android:layout_height="match_parent"
android:scrollbars="horizontal|vertical"
android:layout_width="match_parent"
android:layout_marginTop="5dip"
android:scrollbarStyle="outsideInset"
android:fillViewport="true">
<HorizontalScrollView
android:id="@+id/horizontalView"
android:layout_height="wrap_content"
android:scrollbars="horizontal|vertical"
android:layout_width="wrap_content"
android:layout_marginTop="5dip">
<TableLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/tlGridTable" >
</TableLayout>
</HorizontalScrollView>
</ScrollView>
</LinearLayout>
The Problem This for 3 Fragments
takes about 10 seconds to load, so the user get a black screen for 10 second before the Activity
is actually loaded. how can I avoid it? Running all the process of populating the tables in an AsyncTask
will make my ViewPager
Activity
to load faster? can it even be done?
UPDATE:
Most of the time is beeing spend to populate/create the TableLayout
. If there is a big amount of data recieved from the server then it's needed to create a big amount of TextView
s and set them in the TableLayout
.
UPDATE #2:
Well I'm over eliminating the problem because as I understand for my needs (horizontal and vertical scrolling of whole view) I have to use TableLayout
, So I need to wait this time it takes to load it. But I need to find a way to load the data in the fragments at least with the user knowing that the data is being populated (displaying appropriate Dialog
). I tried to put a dialog in the onCreate
of the ViewPager
before I start the initialization of the fragment but for some reason it not showing and I only see the black screen until the fragments are loaded.
Please refer to last question as I understand it's not possible to fix the loading times:
The Question:
Is there a way to create a ViewPager
with almost empty fragments(only a separate headline for each one), present them to the user and then, after the activity is already loaded and visible (and not a black screen is shown), present a Dialog
and populate the fragments in while the Dialog is shown?
Any help would be appreciated.
Thanks.
ViewPager2 is an improved version of the ViewPager library that offers enhanced functionality and addresses common difficulties with using ViewPager . If your app already uses ViewPager , read this page to learn more about migrating to ViewPager2 .
setOnPageChangeListener (listener: ViewPager. OnPageChangeListener!) This function is deprecated.
This for 3 Fragments takes about 10 seconds to load, so the user get a black screen for 10 second before the Activity is actually loaded.
The reason for that is the amount of widgets you use in your layouts plus the depth of the view hierarchy of your Activity
. From what you posted you have something like this:
Possible wrapper for
ViewPager
in theActivity
->ViewPager
-> At least aScrollView
(as you say something about scrolling vertically and horizontally) ->Linearlayout
-> TableLayout -> TableRow -> content ofTableRow
That is a depth of 7(if I'm not mistaken the support fragment framework also inserts some views in between). This is very bad for performance.
You also have a lot of widgets(assuming those for
loops run for at most 10 iterations, otherwise it's just really bad) in a single Fragment
and taking in consideration that the second fragment will also have its view loaded you can see that this will be again a performance hit.
It would be helpful to post your current layouts to see if they couldn't be optimized.
There are small improvements that you could make to your current code but this will not help you to go from 10 seconds to at most 1 second like you should:
There is no point in this code:
if (container == null) {
return null;
}
I don't know what this does:
SGRaportManagerAppObj.getInstance().parametersRepository.getParametersRepository()
but see if you don't create useless objects(Is that a singleton?). Don't put it in the for
loop as it will be run every time, use a normal for
to avoid the use of the Iterator
:
final int count = SGRaportManagerAppObj.getInstance().parametersRepository.getParametersRepository().size();
for (int i = 0; i < count; i++) {
final Parameter parameter = SGRaportManagerAppObj.getInstance().parametersRepository.getParametersRepository().get(i);
// ... rest of code
You should do the same in the other for
loops.
Retrieve those resources(colors and drawables) outside the for
loops, in the loop only assign them to the views.
Edit: Your layout is very deep and with too many views so the performance will be poor. The only way to overcome this is to use a widget that recycles its views(I know what you said). Alternatives would be:
onCreateView
and return combined with showing a loading ProgressDialog
. After the Fragment
becomes visible you would start creating the real view of the Fragment
in chunks and finally attach it to the fragment. This would be very bad for the user experience.And as you use a ViewPager
will have additional work to make things go alright between the page switch. Maybe you could rethink your current setup.
Since you use pager, you load more then just the first fragment when you start the activity. Make the initial fragment view with a progress bar visible and the table hidden and load the data only when you switch to that Fragment.
in the activity use
mPager.setOnPageChangeListener(new OnPageChangeListener() {
@Override
public void onPageSelected(int position) {
Fragment f = mAdapter.getFragment(mPager.getCurrentItem());
f.loadData(); // when you finish loading the data, hide the progress bar and show the table
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
To use mAdapter.getFragment(), inherit your adapter from:
public abstract class SmartFragmentPagerAdapter extends FragmentPagerAdapter{
private SparseArray<String> mFragmentTags;
private FragmentManager mFragmentManager;
public SmartFragmentPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
mFragmentManager = fragmentManager;
mFragmentTags = new SparseArray<String>();
}
@Override
public Object instantiateItem(ViewGroup container, int position) {
Object obj = super.instantiateItem(container, position);
if (obj instanceof Fragment) {
// record the fragment tag here.
Fragment f = (Fragment) obj;
String tag = f.getTag();
mFragmentTags.put(position, tag);
}
return obj;
}
public Fragment getFragment(int position) {
String tag = mFragmentTags.get(position);
if (tag == null)
return null;
return mFragmentManager.findFragmentByTag(tag);
}
public FragmentManager getFragmentManager(){
return mFragmentManager;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With