From 665b94de9b8b2e8eda9599909f7d4743669bf981 Mon Sep 17 00:00:00 2001 From: Adam Mihalik Date: Mon, 5 Dec 2016 15:51:51 +0100 Subject: [PATCH 1/8] Sample activity that fails --- .idea/modules.xml | 9 + .idea/runConfigurations.xml | 12 ++ .idea/vcs.xml | 6 + .../support/v4/sample/SimpleFragment.java | 8 + .../inloop/sk/sample/MainActivity.java | 161 ++++++++++++++++++ 5 files changed, 196 insertions(+) create mode 100644 .idea/modules.xml create mode 100644 .idea/runConfigurations.xml create mode 100644 .idea/vcs.xml create mode 100644 app/src/main/java/sk/inloop/support/v4/sample/SimpleFragment.java create mode 100644 app/src/main/java/support/inloop/sk/sample/MainActivity.java diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..224a5ee --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/runConfigurations.xml b/.idea/runConfigurations.xml new file mode 100644 index 0000000..7f68460 --- /dev/null +++ b/.idea/runConfigurations.xml @@ -0,0 +1,12 @@ + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/java/sk/inloop/support/v4/sample/SimpleFragment.java b/app/src/main/java/sk/inloop/support/v4/sample/SimpleFragment.java new file mode 100644 index 0000000..8f604da --- /dev/null +++ b/app/src/main/java/sk/inloop/support/v4/sample/SimpleFragment.java @@ -0,0 +1,8 @@ +package sk.inloop.support.v4.sample; + +/** + * Created by adammihalik on 05/12/2016. + */ + +public class SimpleFragment { +} diff --git a/app/src/main/java/support/inloop/sk/sample/MainActivity.java b/app/src/main/java/support/inloop/sk/sample/MainActivity.java new file mode 100644 index 0000000..09cc7ae --- /dev/null +++ b/app/src/main/java/support/inloop/sk/sample/MainActivity.java @@ -0,0 +1,161 @@ +package support.inloop.sk.sample; + +import android.support.design.widget.FloatingActionButton; +import android.support.design.widget.Snackbar; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; + +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentPagerAdapter; +import android.support.v4.view.ViewPager; +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.Menu; +import android.view.MenuItem; +import android.view.View; +import android.view.ViewGroup; + +import android.widget.TextView; + +import support.inloop.sk.updatablefragmentpageradapter.R; + +public class MainActivity extends AppCompatActivity { + + /** + * The {@link android.support.v4.view.PagerAdapter} that will provide + * fragments for each of the sections. We use a + * {@link FragmentPagerAdapter} derivative, which will keep every + * loaded fragment in memory. If this becomes too memory intensive, it + * may be best to switch to a + * {@link android.support.v4.app.FragmentStatePagerAdapter}. + */ + private SectionsPagerAdapter mSectionsPagerAdapter; + + /** + * The {@link ViewPager} that will host the section contents. + */ + private ViewPager mViewPager; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); + setSupportActionBar(toolbar); + // Create the adapter that will return a fragment for each of the three + // primary sections of the activity. + mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager()); + + // Set up the ViewPager with the sections adapter. + mViewPager = (ViewPager) findViewById(R.id.container); + mViewPager.setAdapter(mSectionsPagerAdapter); + + + FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); + fab.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View view) { + Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) + .setAction("Action", null).show(); + } + }); + + } + + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + // Inflate the menu; this adds items to the action bar if it is present. + getMenuInflater().inflate(R.menu.menu_main, menu); + return true; + } + + @Override + public boolean onOptionsItemSelected(MenuItem item) { + // Handle action bar item clicks here. The action bar will + // automatically handle clicks on the Home/Up button, so long + // as you specify a parent activity in AndroidManifest.xml. + int id = item.getItemId(); + + //noinspection SimplifiableIfStatement + if (id == R.id.action_settings) { + return true; + } + + return super.onOptionsItemSelected(item); + } + + /** + * A placeholder fragment containing a simple view. + */ + public static class PlaceholderFragment extends Fragment { + /** + * The fragment argument representing the section number for this + * fragment. + */ + private static final String ARG_SECTION_NUMBER = "section_number"; + + public PlaceholderFragment() { + } + + /** + * Returns a new instance of this fragment for the given section + * number. + */ + public static PlaceholderFragment newInstance(int sectionNumber) { + PlaceholderFragment fragment = new PlaceholderFragment(); + Bundle args = new Bundle(); + args.putInt(ARG_SECTION_NUMBER, sectionNumber); + fragment.setArguments(args); + return fragment; + } + + @Override + public View onCreateView(LayoutInflater inflater, ViewGroup container, + Bundle savedInstanceState) { + View rootView = inflater.inflate(R.layout.fragment_main, container, false); + TextView textView = (TextView) rootView.findViewById(R.id.section_label); + textView.setText(getString(R.string.section_format, getArguments().getInt(ARG_SECTION_NUMBER))); + return rootView; + } + } + + /** + * A {@link FragmentPagerAdapter} that returns a fragment corresponding to + * one of the sections/tabs/pages. + */ + public class SectionsPagerAdapter extends FragmentPagerAdapter { + + public SectionsPagerAdapter(FragmentManager fm) { + super(fm); + } + + @Override + public Fragment getItem(int position) { + // getItem is called to instantiate the fragment for the given page. + // Return a PlaceholderFragment (defined as a static inner class below). + return PlaceholderFragment.newInstance(position + 1); + } + + @Override + public int getCount() { + // Show 3 total pages. + return 3; + } + + @Override + public CharSequence getPageTitle(int position) { + switch (position) { + case 0: + return "SECTION 1"; + case 1: + return "SECTION 2"; + case 2: + return "SECTION 3"; + } + return null; + } + } +} From 97e9c68327959205d029f677472d3fdf0e928fbb Mon Sep 17 00:00:00 2001 From: Adam Mihalik Date: Tue, 6 Dec 2016 09:20:31 +0100 Subject: [PATCH 2/8] New fixed adapter & usage --- app/build.gradle | 29 ++ app/proguard-rules.pro | 17 ++ .../sample/ExampleInstrumentedTest.java | 26 ++ app/src/main/AndroidManifest.xml | 28 ++ .../support/sample/FixedMainActivity.java | 56 ++++ .../support/sample/IncorrectMainActivity.java | 56 ++++ .../inloop/support/sample/SampleFragment.java | 38 +++ .../adapter/CorrectFragmentAdapter.java | 62 +++++ .../adapter/IncorrectFragmentAdapter.java | 62 +++++ .../v4/app/FragmentStatePagerAdapter.java | 248 ++++++++++++++++++ .../support/v4/sample/SimpleFragment.java | 8 - .../inloop/sk/sample/MainActivity.java | 161 ------------ app/src/main/res/layout/activity_main.xml | 42 +++ app/src/main/res/layout/fragment_template.xml | 20 ++ app/src/main/res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 3418 bytes app/src/main/res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 2206 bytes app/src/main/res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 4842 bytes .../main/res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 7718 bytes .../main/res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 10486 bytes app/src/main/res/values-v21/styles.xml | 9 + app/src/main/res/values-w820dp/dimens.xml | 6 + app/src/main/res/values/colors.xml | 6 + app/src/main/res/values/dimens.xml | 7 + app/src/main/res/values/strings.xml | 8 + app/src/main/res/values/styles.xml | 20 ++ .../support/sample/ExampleUnitTest.java | 17 ++ 26 files changed, 757 insertions(+), 169 deletions(-) create mode 100644 app/build.gradle create mode 100644 app/proguard-rules.pro create mode 100644 app/src/androidTest/java/sk/inloop/support/sample/ExampleInstrumentedTest.java create mode 100644 app/src/main/AndroidManifest.xml create mode 100644 app/src/main/java/sk/inloop/support/sample/FixedMainActivity.java create mode 100644 app/src/main/java/sk/inloop/support/sample/IncorrectMainActivity.java create mode 100644 app/src/main/java/sk/inloop/support/sample/SampleFragment.java create mode 100644 app/src/main/java/sk/inloop/support/sample/adapter/CorrectFragmentAdapter.java create mode 100644 app/src/main/java/sk/inloop/support/sample/adapter/IncorrectFragmentAdapter.java create mode 100644 app/src/main/java/sk/inloop/support/v4/app/FragmentStatePagerAdapter.java delete mode 100644 app/src/main/java/sk/inloop/support/v4/sample/SimpleFragment.java delete mode 100644 app/src/main/java/support/inloop/sk/sample/MainActivity.java create mode 100644 app/src/main/res/layout/activity_main.xml create mode 100644 app/src/main/res/layout/fragment_template.xml create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 app/src/main/res/values-v21/styles.xml create mode 100644 app/src/main/res/values-w820dp/dimens.xml create mode 100644 app/src/main/res/values/colors.xml create mode 100644 app/src/main/res/values/dimens.xml create mode 100644 app/src/main/res/values/strings.xml create mode 100644 app/src/main/res/values/styles.xml create mode 100644 app/src/test/java/sk/inloop/support/sample/ExampleUnitTest.java diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..8cad3d0 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,29 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 25 + buildToolsVersion "25.0.0" + defaultConfig { + applicationId "sk.inloop.support" + minSdkVersion 15 + targetSdkVersion 25 + versionCode 1 + versionName "1.0" + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { + exclude group: 'com.android.support', module: 'support-annotations' + }) + compile 'com.android.support:appcompat-v7:25.0.1' + testCompile 'junit:junit:4.12' +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..eb04d8b --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in /Users/adammihalik/Library/Android/sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/app/src/androidTest/java/sk/inloop/support/sample/ExampleInstrumentedTest.java b/app/src/androidTest/java/sk/inloop/support/sample/ExampleInstrumentedTest.java new file mode 100644 index 0000000..2f12559 --- /dev/null +++ b/app/src/androidTest/java/sk/inloop/support/sample/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package sk.inloop.support.sample; + +import android.content.Context; +import android.support.test.InstrumentationRegistry; +import android.support.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumentation test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() throws Exception { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getTargetContext(); + + assertEquals("sk.inloop.support.sample", appContext.getPackageName()); + } +} diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..fd15528 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/sk/inloop/support/sample/FixedMainActivity.java b/app/src/main/java/sk/inloop/support/sample/FixedMainActivity.java new file mode 100644 index 0000000..8be13bf --- /dev/null +++ b/app/src/main/java/sk/inloop/support/sample/FixedMainActivity.java @@ -0,0 +1,56 @@ +package sk.inloop.support.sample; + +import android.content.Intent; +import android.os.Bundle; +import android.support.v4.view.ViewPager; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; +import android.view.Menu; +import android.view.View; +import android.widget.Button; + +import sk.inloop.support.sample.adapter.CorrectFragmentAdapter; + +public class FixedMainActivity extends AppCompatActivity { + + private CorrectFragmentAdapter mSectionsPagerAdapter; + + private ViewPager mViewPager; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + Toolbar myToolbar = (Toolbar) findViewById(R.id.my_toolbar); + setSupportActionBar(myToolbar); + + mSectionsPagerAdapter = new CorrectFragmentAdapter(getSupportFragmentManager()); + + mViewPager = (ViewPager) findViewById(R.id.container); + mViewPager.setAdapter(mSectionsPagerAdapter); + + ((Button)findViewById(R.id.test_start_btn)).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + mSectionsPagerAdapter.toggleState(); + } + }); + + ((Button)findViewById(R.id.switch_tests_btn)).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(FixedMainActivity.this, IncorrectMainActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + FixedMainActivity.this.startActivity(intent); + } + }); + } + + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + return true; + } + +} diff --git a/app/src/main/java/sk/inloop/support/sample/IncorrectMainActivity.java b/app/src/main/java/sk/inloop/support/sample/IncorrectMainActivity.java new file mode 100644 index 0000000..46a0544 --- /dev/null +++ b/app/src/main/java/sk/inloop/support/sample/IncorrectMainActivity.java @@ -0,0 +1,56 @@ +package sk.inloop.support.sample; + +import android.content.Intent; +import android.os.Bundle; +import android.support.v4.view.ViewPager; +import android.support.v7.app.AppCompatActivity; +import android.support.v7.widget.Toolbar; +import android.view.Menu; +import android.view.View; +import android.widget.Button; + +import sk.inloop.support.sample.adapter.IncorrectFragmentAdapter; + +public class IncorrectMainActivity extends AppCompatActivity { + + private IncorrectFragmentAdapter mSectionsPagerAdapter; + + private ViewPager mViewPager; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + Toolbar myToolbar = (Toolbar) findViewById(R.id.my_toolbar); + setSupportActionBar(myToolbar); + + mSectionsPagerAdapter = new IncorrectFragmentAdapter(getSupportFragmentManager()); + + mViewPager = (ViewPager) findViewById(R.id.container); + mViewPager.setAdapter(mSectionsPagerAdapter); + + ((Button)findViewById(R.id.test_start_btn)).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + mSectionsPagerAdapter.toggleState(); + } + }); + + ((Button)findViewById(R.id.switch_tests_btn)).setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + Intent intent = new Intent(IncorrectMainActivity.this, FixedMainActivity.class); + intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); + IncorrectMainActivity.this.startActivity(intent); + } + }); + } + + + @Override + public boolean onCreateOptionsMenu(Menu menu) { + return true; + } + +} diff --git a/app/src/main/java/sk/inloop/support/sample/SampleFragment.java b/app/src/main/java/sk/inloop/support/sample/SampleFragment.java new file mode 100644 index 0000000..a9c0e9a --- /dev/null +++ b/app/src/main/java/sk/inloop/support/sample/SampleFragment.java @@ -0,0 +1,38 @@ +package sk.inloop.support.sample; + +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +/** + * Created by adammihalik on 05/12/2016. + */ + +public class SampleFragment extends Fragment { + public static SampleFragment newInstance(String label) { + Bundle bundle = new Bundle(); + bundle.putString("label", label); + SampleFragment testFragment = new SampleFragment(); + testFragment.setArguments(bundle); + return testFragment; + } + + public String getLabel() { + return getArguments().getString("label"); + } + + @Nullable + @Override + public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + return inflater.inflate(R.layout.fragment_template, container, false); + } + + @Override + public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { + ((TextView)view.findViewById(R.id.fragment_label)).setText(getLabel()); + } +} diff --git a/app/src/main/java/sk/inloop/support/sample/adapter/CorrectFragmentAdapter.java b/app/src/main/java/sk/inloop/support/sample/adapter/CorrectFragmentAdapter.java new file mode 100644 index 0000000..ab5321d --- /dev/null +++ b/app/src/main/java/sk/inloop/support/sample/adapter/CorrectFragmentAdapter.java @@ -0,0 +1,62 @@ +package sk.inloop.support.sample.adapter; + +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; + +import sk.inloop.support.sample.SampleFragment; +import sk.inloop.support.v4.app.FragmentStatePagerAdapter; + +/** + * Extends {@link sk.inloop.support.v4.app.FragmentStatePagerAdapter}, therefore {@link #notifyDataSetChanged()} will not fail. + */ +public class CorrectFragmentAdapter extends FragmentStatePagerAdapter { + + private boolean mState = true; + + public CorrectFragmentAdapter(FragmentManager fragmentManager) { + super(fragmentManager); + } + + @Override + public int getCount() { + return 3; + } + + public void toggleState() { + mState = !mState; + notifyDataSetChanged(); + } + + private String getLabel(int position) { + switch (position) { + case 0: + return "A"; + case 1: + return mState ? "B" : "C"; + default: + return mState ? "C" : "B"; + } + } + + @Override + public int getItemPosition(Object object) { + String label = ((SampleFragment) object).getLabel(); + if (label.equals("A")) { + return 0; + } else if (label.equals("B")) { + return mState ? 1 : 2; + } else { + return mState ? 2 : 1; + } + } + + @Override + public CharSequence getPageTitle(int position) { + return getLabel(position); + } + + @Override + public Fragment getItem(int position) { + return SampleFragment.newInstance(getLabel(position)); + } +} diff --git a/app/src/main/java/sk/inloop/support/sample/adapter/IncorrectFragmentAdapter.java b/app/src/main/java/sk/inloop/support/sample/adapter/IncorrectFragmentAdapter.java new file mode 100644 index 0000000..9863b06 --- /dev/null +++ b/app/src/main/java/sk/inloop/support/sample/adapter/IncorrectFragmentAdapter.java @@ -0,0 +1,62 @@ +package sk.inloop.support.sample.adapter; + +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentStatePagerAdapter; + +import sk.inloop.support.sample.SampleFragment; + +/** + * Extends {@link FragmentStatePagerAdapter} that fails on {@link #notifyDataSetChanged()}. + */ + +public class IncorrectFragmentAdapter extends FragmentStatePagerAdapter { + private boolean mState = true; + + public IncorrectFragmentAdapter(FragmentManager fragmentManager) { + super(fragmentManager); + } + + @Override + public int getCount() { + return 3; + } + + public void toggleState() { + mState = !mState; + notifyDataSetChanged(); + } + + private String getLabel(int position) { + switch (position) { + case 0: + return "A"; + case 1: + return mState ? "B" : "C"; + default: + return mState ? "C" : "B"; + } + } + + @Override + public int getItemPosition(Object object) { + String label = ((SampleFragment) object).getLabel(); + if (label.equals("A")) { + return 0; + } else if (label.equals("B")) { + return mState ? 1 : 2; + } else { + return mState ? 2 : 1; + } + } + + @Override + public CharSequence getPageTitle(int position) { + return getLabel(position); + } + + @Override + public Fragment getItem(int position) { + return SampleFragment.newInstance(getLabel(position)); + } +} diff --git a/app/src/main/java/sk/inloop/support/v4/app/FragmentStatePagerAdapter.java b/app/src/main/java/sk/inloop/support/v4/app/FragmentStatePagerAdapter.java new file mode 100644 index 0000000..13f65b9 --- /dev/null +++ b/app/src/main/java/sk/inloop/support/v4/app/FragmentStatePagerAdapter.java @@ -0,0 +1,248 @@ +package sk.inloop.support.v4.app; + +import android.os.Bundle; +import android.os.Parcelable; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.support.v4.app.Fragment; +import android.support.v4.app.FragmentManager; +import android.support.v4.app.FragmentTransaction; +import android.support.v4.view.PagerAdapter; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; + +import java.util.ArrayList; +import java.util.List; + +/** + * Created by adammihalik on 05/12/2016. + */ + +public abstract class FragmentStatePagerAdapter extends PagerAdapter { + + private static final String TAG = FragmentStatePagerAdapter.class.getSimpleName(); + private static final boolean DEBUG = false; + + private final FragmentManager mFragmentManager; + private FragmentTransaction mCurTransaction = null; + + private List mSavedState; + private List mFragments; + private Fragment mCurrentPrimaryItem = null; + + public FragmentStatePagerAdapter(FragmentManager fm) { + mFragmentManager = fm; + mFragments = buildFragmentsList(); + mSavedState = buildFragmentStatesList(); + } + + /** + * Return not null and empty {@link List} for storing of {@link android.support.v4.app.Fragment.SavedState}s. Depend on adapter's purpose (only-read, only-insert, insert-delete), developer have to decide which implementation if list should be used. Default is {@link ArrayList}. + */ + @NonNull + protected List buildFragmentStatesList() { + return new ArrayList(); + } + + /** + * Return not null and empty {@link List} for storing of initialized {@link Fragment}s. Depend on adapter's purpose (only-read, only-insert, insert-delete), developer have to decide which implementation if list should be used. Default is {@link ArrayList}. + */ + @NonNull + protected List buildFragmentsList() { + return new ArrayList(); + } + + /** + * Return the Fragment associated with a specified position. + */ + public abstract Fragment getItem(int position); + + @Override + public void startUpdate(ViewGroup container) { + if (container.getId() == View.NO_ID) { + throw new IllegalStateException("ViewPager with adapter " + this + " requires a view id"); + } + } + + @Override + public Object instantiateItem(ViewGroup container, int position) { + Fragment result = tryGetExistingFragment(position); //performance, if fragment has been initialized before, just return it + if (result != null) { + return result; + } + + Fragment fragment = getItem(position); + if (DEBUG) { + Log.v(TAG, "Adding item #" + position + ": f=" + fragment); + } + Fragment.SavedState fss = tryGetSavedState(position); + if (fss != null) { + fragment.setInitialSavedState(fss); + } + setupFragmentAsSecondary(fragment); + addFragmentToList(position, fragment); + getOrCreateFragmentTransaction().add(container.getId(), fragment); + + return fragment; + } + + /** + * Add given {@link Fragment} to fragments list. Ensure, that this fragment will be found on given 'position' anytime (except if fragment will be removed). + */ + protected void addFragmentToList(int position, @Nullable Fragment fragment) { + while (mFragments.size() <= position) { + //TODO: could be more effective??? + mFragments.add(null); + } + mFragments.set(position, fragment); + } + + /** + * Get existing {@link FragmentTransaction}. If transaction is not initialized, create it. + */ + @NonNull + protected FragmentTransaction getOrCreateFragmentTransaction() { + if (mCurTransaction == null) { + mCurTransaction = mFragmentManager.beginTransaction(); + } + return mCurTransaction; + } + + /** + * Return saved {@link android.support.v4.app.Fragment.SavedState} for given 'position'. If state is not saved, NULL is returned. + */ + @Nullable + protected Fragment.SavedState tryGetSavedState(int position) { + if (position >= 0 && mSavedState.size() > position) { + return mSavedState.get(position); + } + return null; + } + + /** + * Return existing {@link Fragment} at defined 'position'. If fragment does not exist, NULL is returned. + */ + @Nullable + protected Fragment tryGetExistingFragment(int position) { + if (position >= 0 && mFragments.size() > position) { + return mFragments.get(position); + } + return null; + } + + @Override + public void destroyItem(ViewGroup container, int position, Object object) { + Fragment fragment = (Fragment) object; + if (DEBUG) { + Log.v(TAG, "Removing item #" + position + ": f=" + object + " v=" + fragment.getView()); + } + addStateOfFragmentToList(position, (fragment.isAdded() ? mFragmentManager.saveFragmentInstanceState(fragment) : null)); + addFragmentToList(position, null); + getOrCreateFragmentTransaction().remove(fragment); + } + + + protected void addStateOfFragmentToList(int position, Fragment.SavedState state) { + while (mSavedState.size() <= position) { + //TODO: could be more effective??? + mSavedState.add(null); + } + mSavedState.set(position, state); + } + + @Override + public void setPrimaryItem(ViewGroup container, int position, Object object) { + Fragment fragment = (Fragment)object; + if (fragment != mCurrentPrimaryItem) { + if (mCurrentPrimaryItem != null) { + setupFragmentAsSecondary(mCurrentPrimaryItem); + } + if (fragment != null) { + setupFragmentAsPrimary(fragment); + } + mCurrentPrimaryItem = fragment; + } + } + + /** + * Setup given {@link Fragment} to be ready as primary. + */ + protected void setupFragmentAsPrimary(Fragment fragment) { + fragment.setMenuVisibility(true); + fragment.setUserVisibleHint(true); + } + + /** + * Setup given {@link Fragment} to be ready as NOT primary. + */ + protected void setupFragmentAsSecondary(Fragment fragment) { + fragment.setMenuVisibility(false); + fragment.setUserVisibleHint(false); + } + + @Override + public void finishUpdate(ViewGroup container) { + if (mCurTransaction != null) { + mCurTransaction.commitNowAllowingStateLoss(); + mCurTransaction = null; + } + } + + @Override + public boolean isViewFromObject(View view, Object object) { + return ((Fragment)object).getView() == view; + } + + @Override + public Parcelable saveState() { + Bundle state = null; + if (mSavedState.size() > 0) { + state = new Bundle(); + Fragment.SavedState[] fss = new Fragment.SavedState[mSavedState.size()]; + mSavedState.toArray(fss); + state.putParcelableArray("states", fss); + } + for (int i=0; i keys = bundle.keySet(); + for (String key: keys) { + if (key.startsWith("f")) { + int index = Integer.parseInt(key.substring(1)); + Fragment f = mFragmentManager.getFragment(bundle, key); + if (f != null) { + f.setMenuVisibility(false); + addFragmentToList(index, f); + } else { + Log.w(TAG, "Bad fragment at key " + key); + } + } + } + } + } + +} diff --git a/app/src/main/java/sk/inloop/support/v4/sample/SimpleFragment.java b/app/src/main/java/sk/inloop/support/v4/sample/SimpleFragment.java deleted file mode 100644 index 8f604da..0000000 --- a/app/src/main/java/sk/inloop/support/v4/sample/SimpleFragment.java +++ /dev/null @@ -1,8 +0,0 @@ -package sk.inloop.support.v4.sample; - -/** - * Created by adammihalik on 05/12/2016. - */ - -public class SimpleFragment { -} diff --git a/app/src/main/java/support/inloop/sk/sample/MainActivity.java b/app/src/main/java/support/inloop/sk/sample/MainActivity.java deleted file mode 100644 index 09cc7ae..0000000 --- a/app/src/main/java/support/inloop/sk/sample/MainActivity.java +++ /dev/null @@ -1,161 +0,0 @@ -package support.inloop.sk.sample; - -import android.support.design.widget.FloatingActionButton; -import android.support.design.widget.Snackbar; -import android.support.v7.app.AppCompatActivity; -import android.support.v7.widget.Toolbar; - -import android.support.v4.app.Fragment; -import android.support.v4.app.FragmentManager; -import android.support.v4.app.FragmentPagerAdapter; -import android.support.v4.view.ViewPager; -import android.os.Bundle; -import android.view.LayoutInflater; -import android.view.Menu; -import android.view.MenuItem; -import android.view.View; -import android.view.ViewGroup; - -import android.widget.TextView; - -import support.inloop.sk.updatablefragmentpageradapter.R; - -public class MainActivity extends AppCompatActivity { - - /** - * The {@link android.support.v4.view.PagerAdapter} that will provide - * fragments for each of the sections. We use a - * {@link FragmentPagerAdapter} derivative, which will keep every - * loaded fragment in memory. If this becomes too memory intensive, it - * may be best to switch to a - * {@link android.support.v4.app.FragmentStatePagerAdapter}. - */ - private SectionsPagerAdapter mSectionsPagerAdapter; - - /** - * The {@link ViewPager} that will host the section contents. - */ - private ViewPager mViewPager; - - @Override - protected void onCreate(Bundle savedInstanceState) { - super.onCreate(savedInstanceState); - setContentView(R.layout.activity_main); - - Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); - setSupportActionBar(toolbar); - // Create the adapter that will return a fragment for each of the three - // primary sections of the activity. - mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager()); - - // Set up the ViewPager with the sections adapter. - mViewPager = (ViewPager) findViewById(R.id.container); - mViewPager.setAdapter(mSectionsPagerAdapter); - - - FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); - fab.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) - .setAction("Action", null).show(); - } - }); - - } - - - @Override - public boolean onCreateOptionsMenu(Menu menu) { - // Inflate the menu; this adds items to the action bar if it is present. - getMenuInflater().inflate(R.menu.menu_main, menu); - return true; - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - // Handle action bar item clicks here. The action bar will - // automatically handle clicks on the Home/Up button, so long - // as you specify a parent activity in AndroidManifest.xml. - int id = item.getItemId(); - - //noinspection SimplifiableIfStatement - if (id == R.id.action_settings) { - return true; - } - - return super.onOptionsItemSelected(item); - } - - /** - * A placeholder fragment containing a simple view. - */ - public static class PlaceholderFragment extends Fragment { - /** - * The fragment argument representing the section number for this - * fragment. - */ - private static final String ARG_SECTION_NUMBER = "section_number"; - - public PlaceholderFragment() { - } - - /** - * Returns a new instance of this fragment for the given section - * number. - */ - public static PlaceholderFragment newInstance(int sectionNumber) { - PlaceholderFragment fragment = new PlaceholderFragment(); - Bundle args = new Bundle(); - args.putInt(ARG_SECTION_NUMBER, sectionNumber); - fragment.setArguments(args); - return fragment; - } - - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, - Bundle savedInstanceState) { - View rootView = inflater.inflate(R.layout.fragment_main, container, false); - TextView textView = (TextView) rootView.findViewById(R.id.section_label); - textView.setText(getString(R.string.section_format, getArguments().getInt(ARG_SECTION_NUMBER))); - return rootView; - } - } - - /** - * A {@link FragmentPagerAdapter} that returns a fragment corresponding to - * one of the sections/tabs/pages. - */ - public class SectionsPagerAdapter extends FragmentPagerAdapter { - - public SectionsPagerAdapter(FragmentManager fm) { - super(fm); - } - - @Override - public Fragment getItem(int position) { - // getItem is called to instantiate the fragment for the given page. - // Return a PlaceholderFragment (defined as a static inner class below). - return PlaceholderFragment.newInstance(position + 1); - } - - @Override - public int getCount() { - // Show 3 total pages. - return 3; - } - - @Override - public CharSequence getPageTitle(int position) { - switch (position) { - case 0: - return "SECTION 1"; - case 1: - return "SECTION 2"; - case 2: - return "SECTION 3"; - } - return null; - } - } -} diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..aa20778 --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,42 @@ + + + + +