Monday, June 8, 2015

My first real-life example of Fragment's reuse.

When you start to learn Android one of the first thing, that course or book trying to put in your head - "use Fragments".
 Why? Because you can put two and more Fragments on one Activity. Ok... But I also can reuse XML code to include needed layout. This was my first thought. But I used fragments in every application. Just because I was taught.
But now I have real example of reusing Fragment for Activities, that contains exactly one Fragment.
We have applications that is simply catalog of  blogs, grouped by categories. So, on my MainActivity I have list of categories and sub-categories. And when you click on category - you get list of blogs from this category. Very simple app.



For showing these lists I use CursorLoader. So, BlogsFragment implements LoaderCallback, from onCreateLoader I return CursorLoader, that query blogs by category. This is common approach.

From screenshots you can see that there are also searching and favorites. By the way, searching implemented using FTS3, but this is theme for other post.
So, when I started to implement search, I used common android practice with searchable activity. So, I created such activity... And on search result I have to show list of blogs. Again. So I used BlogsFragment again. Only thing I have to change - it's query for cursor loader.
The same is for favorite blogs - only new query, all other code is the same.
I understand, that absolutely right approach is to use something like Strategy pattern. But for my goals I added extra flag for intent, that run activities, that use BlogsFragment. So here are some code snippets from blogs fragment:
 public class BlogsFragment extends ListFragment implements LoaderManager.LoaderCallbacks<Cursor>  
   public static final String EXTRA_MODE = "extra_mode";  
   public static final int MODE_FROM_CATEGORY = 0;  
   public static final int MODE_FAVOURITES = 1;  
   public static final int MODE_SEARCH = 2;  
 .....  
   @Override  
   public void onActivityCreated(Bundle savedInstanceState) {  
     Intent intent = getActivity().getIntent();  
     if (intent != null) {  
       String title = intent.getStringExtra(EXTRA_CATEGORY_NAME);  
       if (title != null && !title.isEmpty())  
         getActivity().setTitle(title);  
       if (Intent.ACTION_SEARCH.equals(intent.getAction()))  
         currentMode = MODE_SEARCH;  
       else  
         currentMode = intent.getIntExtra(EXTRA_MODE, MODE_FAVOURITES);  
     }  
     initLoader();  
     super.onActivityCreated(savedInstanceState);  
   }  
 .....  
   @Override  
   public Loader<Cursor> onCreateLoader(int id, Bundle args) {  
     Intent intent = getActivity().getIntent();  
     if (intent == null)  
       return null;  
     if (currentMode == MODE_SEARCH) {  
      .....  
       return new CursorLoader(getActivity(), blogsUri, BLOGS_COLUMNS, BlogKeywordsTable.COLUMN_WORDS + " match '"  
           + query.toLowerCase(locale) + "*'", null, BlogTable.COLUMN_PRIORITY + " DESC");  
     } else if (currentMode == MODE_FROM_CATEGORY) {  
      .....   
       return new CursorLoader(getActivity(), blogsUri, BLOGS_COLUMNS, BlogTable.COLUMN_CATEGORY_1_ID + " = "  
           + categoryId, null, BlogTable.COLUMN_PRIORITY + " DESC");  
     } else /* MODE_FAVOURITES */{  
      .....   
       return new CursorLoader(getActivity(), blogsUri, BLOGS_COLUMNS, BlogTable.TABLE_NAME + "." + BlogTable._ID  
           + " in (" + favourites + ")", null, BlogTable.COLUMN_PRIORITY + " DESC");  
     }  
   }  

No comments:

Post a Comment