Tuesday, August 13, 2013

CursorLoader - asynchronous loader of data

Today I want to show how to work with CursorLoader for asynchronously loading data from a database.
While doing my "pet" project I noticed that now I have a lot of data and its loading takes some time especially for the first start of app when db is also initialized. I do not want to get "ANR" in my app, so I started looking for the solution.

So I had an activity - child of ListActivity on which I show result. Code looks like as shown below:

public class MainActivity extends ListActivity {

  private final Uri VOCABULARY_URI = Uri.EMPTY; //Only for example you need added real Uri to your data
    
  private final String[] COUNM_NAMES = new String[] { "native_word", "translation_word" };

  private final int[] VIEW_IDS = new int[] { R.id.native_word, R.id.translated_word };
  private final String[] PROJECTION = new String[] { "_id", "native_word", "translation_word" };

  @Override
  public void onCreate(final Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
        
    Cursor cursor = getContentResolver().query(VOCABULARY_URI, PROJECTION, null, null, null); //The most expensive operation
        
    SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.two_item_in_line, cursor, COUNM_NAMES, VIEW_IDS);
    setListAdapter(adapter);
  }
}

CursorLoader was added in API level 11, but if your app supported a lower api level it is not a problem  as you could use Support Library. This library provides backward-compatible features like Fragment which were added in last revisions.
Now my activity is needed to implement LoaderManager.LoaderCallbacks with following methods:

onCreateLoader(int id, Bundle args) - instantiate and return a new Loader for given id
onLoadFinished(Loader<Cursor> loader, Cursor cursor) - called when a previously created loader has finished its load
onLoaderReset(Loader<Cursor>) - called when a previously created loader is being reset, and thus its data unavailable.

And following is my realization:
  @Override
  public Loader<Cursor>onCreateLoader(final int loaderId, final Bundle bundle) {
    switch (loaderId) {
    case VOCABLUARY_LOADER_ID:
      return new CursorLoader(getActivity(), VOCABULARY_URI, PROJECTION, null, null, null);
    default:
      return null;
    }
  }

  @Override
  public void onLoadFinished(final Loader<Cursor> cursorLoader, final Cursor cursor) {
    adapter.changeCursor(cursor);
  }

  @Override
  public void onLoaderReset(final Loader<Cursor> cursorLoader) {
    adapter.changeCursor(null);
  }

That`s all, nice work :-)

Monday, August 5, 2013

Restrict user management in BCC

Sometimes we need to customize out of the box behaviour of BCC. Today I want to show how to restrict "user management" in BCC, only user with super admin role can manage "internal user", so the other users will not see the menu "Internal Users" in the "Personalization" tab, as it is shown on the image:



For implementing this task you need to change the next config files for publishing server:
...\atg\web\personalization\activity\genericActivities.xml:

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE generic-activities SYSTEM "dynamosystemresource:/atg/dtds/activitymanager/activitymanager_1.0.dtd">

<generic-activities>
  <activity xml-combine="replace">
    <id>personalization.internalUsers</id>
    <resource-bundle>atg.web.personalization.internalusers.WebAppResources</resource-bundle>
    <display-name-resource>personalization.internalUsers.displayName</display-name-resource>
    <description-resource>personalization.internalUsers.description</description-resource>
    <destination-page>
      <url>/AssetManager/assetManager.jsp</url>
      <clear-context>true</clear-context>
      <acl>Profile$role$epubSuperAdmin:read;</acl>
    </destination-page>
  </activity>
</generic-activities>


and  ..\atg\remote\controlcenter\service\internalUsers.xml

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE applications SYSTEM "dynamosystemresource:/atg/dtds/application-configuration/application-configuration_1.0.dtd">

<applications>
  <application id="personalization.internalUsers" xml-combine="replace">
    <resource-bundle>
      atg.web.personalization.internalusers.WebAppResources
    </resource-bundle>

    <display-name-resource>
      personalization.internalUsers.displayName
    </display-name-resource>

    <destination-page>
      <url>
        /AssetManager/assetManager.jsp
      </url>
      <query-parameter value="-1" key="project"/>
      <query-parameter value="personalization.internalUsers" key="activity"/>
    </destination-page>

    <acl>
      Profile$role$epubSuperAdmin:read;
    </acl>

    <initializer>
    </initializer>

    <sort-priority>
      31
    </sort-priority>

    <category>
      internalExternalUsers
    </category>
  </application>
</applications>

Usefull links: Configuring BCC Home Page Security, Configuring the Asset Manager