How to do lazy loading when using ViewPager2? - androidx

I'm changing my code to androidX, I used to store fragments in viewpager and each fragment contains several lists, now I have problems about lazy loading when using viewpager2, is there some sample code from google?

Try this
abstract class LazyFragment : Fragment() {
private var isInitData : Boolean = false // flag bit to determine whether the data is initialized
private var isVisibleToUser : Boolean = false // flags to determine whether fragments are visible
private var isPrepareView : Boolean = false // flag bit to determine that view has been loaded to avoid null pointer operations
override fun onViewCreated(#NonNull view: View, #Nullable savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
isPrepareView = true // At this point the view has been loaded and set to true
}
override fun onHiddenChanged(hidden: Boolean) {
super.onHiddenChanged(hidden)
if (!hidden) {
lazyInitData()
}
}
override fun onResume() {
super.onResume()
isVisibleToUser = true
lazyInitData() // Load lazily
}
override fun onPause() {
super.onPause()
isVisibleToUser = false
}
override fun onAttach(context: Context) {
super.onAttach(context)
lazyInitData() // Load lazily
}
//
/**
* Lazy Loading Method
*/
private fun lazyInitData(){
if(setFragmentTarget()){
if(!isInitData && isVisibleToUser && isPrepareView) {
loadData()
}
}else {
if(!isInitData && isVisibleToUser && isPrepareView) {
loadData()
}else if (!isInitData && parentFragment ==null && isPrepareView ){
loadData()
}
}
}
private fun loadData() {
initData(); // Load data
isInitData = true; // Has the data flag been loaded and reassigned to true
}
/**
* Method of loading data, implemented by subclasses
*/
abstract fun initData()
/**
* Setting Fragment target, implemented by subclasses
*/
abstract fun setFragmentTarget(): Boolean
What you need to do is this
(For each of the fragments you use in ViewPager2, make the fragment extend LazyFragment):
override onCreateView() to inflate the layout
override setFragmentTarget () where it returns true or false based on whether or not you want that fragment to be loaded immediately or lazily
override initData() and put your logic into it

Related

JavaFX – ObservableList and list's item change

This answer provides a solution for an observable list that will send "list updated" notifications if properties of elements of the list change.
In my case, elements (a Element class) of such observable list are complex and I don't like to implement property for each member variable. Due to this, I added into the Element class a BooleanProperty that indicates change of the class.
Element Class
import javafx.beans.property.ReadOnlyBooleanProperty;
import javafx.beans.property.ReadOnlyBooleanWrapper;
public class Element {
// ...
private ReadOnlyBooleanWrapper changeIndicatorWrapper;
public Element() {
//...
changeIndicatorWrapper = new ReadOnlyBooleanWrapper(false);
}
public ReadOnlyBooleanProperty changeIndicatorProperty() {
return changeIndicatorWrapper.getReadOnlyProperty();
}
public void someMethod() {
// Some update
changeIndicatorWrapper.set(!changeIndicatorWrapper.get());
}
}
Observable List
ObservableList<Element> elementsObservableList = FXCollections.observableList(
new ArrayList<>(),
(Element element) -> new Observable[] { element.changeIndicatorProperty() }
);
elementsObservableList.addListener(new ListChangeListener<Element>() {
#Override
public void onChanged(Change<? extends Element> c) {
System.out.println("CHANGE");
while(c.next()) {
if (c.wasUpdated()) {
for (int i = c.getFrom(); i < c.getTo(); ++i)
System.out.println(elementsObservableList.get(i));
}
}
}
});
My question is about this approach. Repeatedly set the changeIndicatorProperty to true not fire the change event. So, I need to reverse changeIndicatorProperty value changeIndicatorWrapper.set(!changeIndicatorWrapper.get()) each time. It is strange, isn't it?
Can I force programatically the update event?
It is strange, isn't it?
No this isn't surprising. For a change to be triggered a change needs to happen. If the BooleanProperty determines no change does happen and therefore the listeners are not notified of anything, this still satisfies the contract of Property.
Actually a Property isn't needed anyways. What is needed is a Observable that notifies it's observers. You could do this by using the following class and calling invalidate:
public class SimpleObservable implements Observable {
private final List<InvalidationListener> listeners = new LinkedList<>();
#Override
public void addListener(InvalidationListener listener) {
listeners.add(listener);
}
#Override
public void removeListener(InvalidationListener listener) {
listeners.remove(listener);
}
public void invalidate() {
for (InvalidationListener listener : listeners) {
try {
listener.invalidated(this);
} catch (RuntimeException ex) {
}
}
}
}
Example:
public class Element {
protected final SimpleObservable observable = new SimpleObservable();
public Observable getObservable() {
return observable;
}
public static <T extends Element> ObservableList<T> observableArrayList() {
return FXCollections.observableArrayList(e -> new Observable[]{e.observable});
}
private void update() {
observable.invalidate();
}
public static void main(String[] args) {
ObservableList<Element> list = Element.observableArrayList();
list.addListener((ListChangeListener.Change<? extends Element> c) -> {
while (c.next()) {
if (c.wasUpdated()) {
System.out.println("update: [" + c.getFrom() + ", " + c.getTo() + ")");
}
}
});
list.addAll(new Element(), new Element(), new Element());
list.get(1).update();
}
}

JavaFX PropertyGrid/Editor

I am trying to write a JavaFx component which is generally called a "property editor" or a "property grid". A property being a name-value pair.
I guess the property sheet is made for this, but I'd like to use a TreeTableView. Mainly because I have nested properties and eventually several columns.
The component on the right is exactly what I try to achieve.
The problem I encountered with the TreeTableView, is the fact that the cell customisation must occur in the CellFactory which leads to a switch on the item type. This solution makes things really unflexible.
For example, what happens if a string value must be updated via a TextField for a given property and via a ComboBox for another property?
Any suggestion is more than welcome!
Relating questions: javafx-8-custom-listview-cells-its-evil
Update1
I tried to implement the #fabian's 1st suggestion.
I have my bean:
public class PropertyItem {
private StringProperty name = new SimpleStringProperty("");
private EditableItem value;
...
}
A default implementation of the EditableItem, to edit a string via in a TextField:
public class DefaultEditableItem implements EditableItem {
String value = "init value";
private TextField textField = new TextField();
public DefaultEditableItem(String value) {
this.setValue(value);
}
// implementations of assignItem, removeItem, startEdit, cancelEdit,... as suggested for the cell behavior
}
My implementation of the TableView:
PropertyItem rootProp = new PropertyItem("ROOT", new DefaultEditableItem("test roots"));
TreeItem<PropertyItem> root = new TreeItem(rootProp);
// the name column is straightforward ...
// value column
TreeTableColumn<PropertyItem, EditableItem> valueColumn = new TreeTableColumn<>("VALUE");
valueColumn.setCellValueFactory(new Callback<TreeTableColumn.CellDataFeatures<PropertyItem, EditableItem>, ObservableValue<EditableItem>>() {
#Override
public ObservableValue<EditableItem> call(TreeTableColumn.CellDataFeatures<PropertyItem, EditableItem> cellData) {
TreeItem<PropertyItem> treeItem = cellData.getValue();
PropertyItem propertyItem = treeItem.getValue();
// this will not compile...
return propertyItem.value();
}
});
valueColumn.setCellFactory(new Callback<TreeTableColumn<PropertyItem, EditableItem>, TreeTableCell<PropertyItem, EditableItem>>() {
#Override
public TreeTableCell<PropertyItem, EditableItem> call(TreeTableColumn<PropertyItem, EditableItem> param) {
return new EditingTreeTableCell();
}
});
valueColumn.setOnEditCommit(...)
treeTableView.getColumns().addAll(nameColumn, valueColumn);
treeTableView.setEditable(true);
My problem is on the cellValueFactory which needs to return a ObservableValue. What should I do, given that I want this column to be editable?
I guess that EditableItem must extends Property? But then, could my DefaultEditableItem extends SimpleStringProperty?
You could store information about how the item should be edited in the item itself (either directly or by allowing you to retrieve it from a map or similar data structure using a suitable key stored in the item).
Example:
public interface EditableItem {
/**
* Modify cell ui the way updateItem would do it, when the item is
* added to the cell
*/
void assignItem(EditingTreeTableCell<?, ?> cell);
/**
* Modify cell ui to remove the item the way it would be done in the updateItem method
*/
void removeItem(EditingTreeTableCell<?, ?> cell);
}
public class EditingTreeTableCell<U, V> extends TreeTableCell<U, V> {
#Override
public void updateItem(V item, boolean empty) {
boolean cleared = false;
V oldItem = getItem();
if (oldItem instanceof EditableItem) {
((EditableItem) oldItem).removeItem(this);
cleared = true;
}
super.updateItem(item, empty);
if (empty) {
if (!cleared) {
setText("");
setGraphic(null);
}
} else {
if (item instanceof EditableItem) {
((EditableItem) item).assignItem(this);
} else {
setText(Objects.toString(item, ""));
// or other default initialistation
}
}
}
}
As this however would increase the size of the items, you could also store the info based on the type of the bean the property recides in and the name of the property, that is if the bean and the name property are assigned for the property:
public interface CellEditor<U, V> {
/**
* Modify cell ui the way updateItem would do it, when the item is
* added to the cell
*/
void assignItem(EditorTreeTableCell<U, V> cell, V item);
/**
* Modify cell ui to remove the item the way it would be done in the updateItem method
*/
void removeItem(EditorTreeTableCell<U, V> cell);
}
public class EditorTreeTableCell<U, V> extends TreeTableCell<U, V> {
public EditorTreeTableCell(Map<Class, Map<String, CellEditor<U, ?>>> editors) {
this.editors = editors;
}
private CellEditor<U, V> editor;
private final Map<Class, Map<String, CellEditor<U, ?>>> editors;
#Override
public void updateIndex(int i) {
if (editor != null) {
editor.removeItem(this);
editor = null;
}
ObservableValue<V> observable = getTableColumn().getCellObservableValue(i);
if (observable instanceof ReadOnlyProperty) {
ReadOnlyProperty prop = (ReadOnlyProperty) observable;
String name = prop.getName();
Object bean = prop.getBean();
if (name != null && bean != null) {
Class cl = bean.getClass();
while (editor == null && cl != null) {
Map<String, CellEditor<U, ?>> map = editors.get(cl);
if (map != null) {
editor = (CellEditor) map.get(name);
}
cl = cl.getSuperclass();
}
}
}
super.updateIndex(i);
}
public void updateItem(V item, boolean empty) {
super.updateItem();
if (editor == null) {
setGraphic(null);
setText(Objects.toString(item, ""));
} else {
editor.assignItem(this, item);
}
}
}
This would allow you to select the editor based on the object name and type of bean the object belongs to...

Android: Prevent notfying Parent/Descendent uri's in ContentProvider while using CursorLoader?

I have a CursorLoader that observes a directory with this URI:
uriDirectory = content://com.myapp.stocks/stocks
and another CursorLoader that observes an item with this URI:
uriItem = content://com.myapp.stocks/stocks/GOOG
When I update uriItem and call getContext().getContentResolver().notifyChange(uriItem , null); in my ContentProvider, how can I prevent it from notifying uriDirectory as well?
Thanks!
Edit: So my solution so far is just to have a boolean that is set to true when I notify a uriItem. Then when it notifies the parent, uriDirectory, it will see that the boolean is true and won't perform any operations. After, I set the boolean back to false.
You can write your own CursorLoader. The default cursor loaders register a content observer via Cursor.RegisterContentObserver(ContentObserver observer). Instead, we want to use registerContentObserver(Uri uri, boolean notifyForDescendants, ContentObserver observer).
I'm not sure if you are using the support library CursorLoader but for the greatest applicability, that's what I'm using.
The only changes from the stock android versions are in loadInBackground(). You should create an entire class instead of just extending android's and overriding loadInBackground because it protects you from future changes made to Android. Be advised that this will not use any notification url you set for the cursor in your ContentProvider unless you the device is KitKat or newer
Uri notificationUri;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
notificationUri = cursor.getNotificationUri();
} else {
notificationUri = mUri;
}
getContext().getContentResolver().registerContentObserver(
notificationUri != null ? notificationUri : mUri,
false, //don't notify for descendants
mObserver
);
Full class descendantChangeIgnoringCursorLoader.java:
package com.innomatixdata.busscan.utils;
import android.content.ContentResolver;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.ContentResolverCompat;
import android.support.v4.content.Loader;
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.Arrays;
public class DescendantChangeIgnoringCursorLoader extends AsyncTaskLoader<Cursor> {
final Loader.ForceLoadContentObserver mObserver;
Uri mUri;
String[] mProjection;
String mSelection;
String[] mSelectionArgs;
String mSortOrder;
Cursor mCursor;
android.support.v4.os.CancellationSignal mCancellationSignal;
/* Runs on a worker thread */
#Override
public Cursor loadInBackground() {
synchronized (this) {
if (isLoadInBackgroundCanceled()) {
throw new android.support.v4.os.OperationCanceledException();
}
mCancellationSignal = new android.support.v4.os.CancellationSignal();
}
try {
Cursor cursor = ContentResolverCompat.query(getContext().getContentResolver(),
mUri, mProjection, mSelection, mSelectionArgs, mSortOrder,
mCancellationSignal);
if (cursor != null) {
try {
// Ensure the cursor window is filled.
cursor.getCount();
Uri notificationUri;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
notificationUri = cursor.getNotificationUri();
} else {
notificationUri = mUri;
}
getContext().getContentResolver().registerContentObserver(
notificationUri != null ? notificationUri : mUri,
false, //don't notify for descendants
mObserver
);
} catch (RuntimeException ex) {
cursor.close();
throw ex;
}
}
return cursor;
} finally {
synchronized (this) {
mCancellationSignal = null;
}
}
}
#Override
public void cancelLoadInBackground() {
super.cancelLoadInBackground();
synchronized (this) {
if (mCancellationSignal != null) {
mCancellationSignal.cancel();
}
}
}
/* Runs on the UI thread */
#Override
public void deliverResult(Cursor cursor) {
if (isReset()) {
// An async query came in while the loader is stopped
if (cursor != null) {
cursor.close();
}
return;
}
Cursor oldCursor = mCursor;
mCursor = cursor;
if (isStarted()) {
super.deliverResult(cursor);
}
if (oldCursor != null && oldCursor != cursor && !oldCursor.isClosed()) {
oldCursor.close();
}
}
/**
* Creates an empty unspecified CursorLoader. You must follow this with
* calls to {#link #setUri(Uri)}, {#link #setSelection(String)}, etc
* to specify the query to perform.
*/
public DescendantChangeIgnoringCursorLoader(Context context) {
super(context);
mObserver = new Loader.ForceLoadContentObserver();
}
/**
* Creates a fully-specified CursorLoader. See {#link ContentResolver#query(Uri, String[],
* String, String[], String) ContentResolver.query()} for documentation on the meaning of the
* parameters. These will be passed as-is to that call.
*/
public DescendantChangeIgnoringCursorLoader(Context context, Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
super(context);
mObserver = new Loader.ForceLoadContentObserver();
mUri = uri;
mProjection = projection;
mSelection = selection;
mSelectionArgs = selectionArgs;
mSortOrder = sortOrder;
}
/**
* Starts an asynchronous load of the contacts list data. When the result is ready the callbacks
* will be called on the UI thread. If a previous load has been completed and is still valid
* the result may be passed to the callbacks immediately.
*
* Must be called from the UI thread
*/
#Override
protected void onStartLoading() {
if (mCursor != null) {
deliverResult(mCursor);
}
if (takeContentChanged() || mCursor == null) {
forceLoad();
}
}
/**
* Must be called from the UI thread
*/
#Override
protected void onStopLoading() {
// Attempt to cancel the current load task if possible.
cancelLoad();
}
#Override
public void onCanceled(Cursor cursor) {
if (cursor != null && !cursor.isClosed()) {
cursor.close();
}
}
#Override
protected void onReset() {
super.onReset();
// Ensure the loader is stopped
onStopLoading();
if (mCursor != null && !mCursor.isClosed()) {
mCursor.close();
}
mCursor = null;
}
public Uri getUri() {
return mUri;
}
public void setUri(Uri uri) {
mUri = uri;
}
public String[] getProjection() {
return mProjection;
}
public void setProjection(String[] projection) {
mProjection = projection;
}
public String getSelection() {
return mSelection;
}
public void setSelection(String selection) {
mSelection = selection;
}
public String[] getSelectionArgs() {
return mSelectionArgs;
}
public void setSelectionArgs(String[] selectionArgs) {
mSelectionArgs = selectionArgs;
}
public String getSortOrder() {
return mSortOrder;
}
public void setSortOrder(String sortOrder) {
mSortOrder = sortOrder;
}
#Override
public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
super.dump(prefix, fd, writer, args);
writer.print(prefix); writer.print("mUri="); writer.println(mUri);
writer.print(prefix); writer.print("mProjection=");
writer.println(Arrays.toString(mProjection));
writer.print(prefix); writer.print("mSelection="); writer.println(mSelection);
writer.print(prefix); writer.print("mSelectionArgs=");
writer.println(Arrays.toString(mSelectionArgs));
writer.print(prefix); writer.print("mSortOrder="); writer.println(mSortOrder);
writer.print(prefix); writer.print("mCursor="); writer.println(mCursor);
}
}

How do you abstract page session properties?

I was following this example
example code:
public class Global : HttpApplication
{
private Poster _posterDetails;
private Posting _postingDetails;
private Property _propertyDetails;
protected void Application_PostRequestHandlerExecute(object sender, EventArgs e)
{
if (HttpContext.Current.Session == null) return;
_posterDetails = HttpContext.Current.Session["Poster"] as Poster;
_postingDetails = HttpContext.Current.Session["Posting"] as Posting;
_propertyDetails = HttpContext.Current.Session["Property"] as Property;
}
}
these session variables are littered throughout the app and I need to abstract the retrieval of them. Say, later I get them from a db instead of the current session.
Session is baked into the Page or Context. How do I inject that dependency into the concrete implementation of a possible current property getter.
Create an abstraction around HttpContext:
public interface IHttpContextFactory
{
HttpContextBase Create();
}
public class HttpContextFactory
: IHttpContextFactory
{
public HttpContextBase Create()
{
return new HttpContextWrapper(HttpContext.Current);
}
}
Then inject it into a specialized service for these settings.
public interface ISettings
{
T GetValue<T>(string key);
void SetValue<T>(string key, T value);
}
public class ContextSettings
: ISettings
{
private readonly IHttpContextFactory httpContextFactory;
private HttpContextBase context;
public RequestCache(
IHttpContextFactory httpContextFactory
)
{
if (httpContextFactory == null)
throw new ArgumentNullException("httpContextFactory");
this.httpContextFactory = httpContextFactory;
}
protected HttpContextBase Context
{
get
{
if (this.context == null)
{
this.context = this.httpContextFactory.Create();
}
return context;
}
}
public virtual T GetValue<T>(string key)
{
if (this.Context.Session.Contains(key))
{
return (T)this.Context.Session[key];
}
return default(T);
}
public virtual void SetValue<T>(string key, T value)
{
this.Context.Session[key] = value;
}
}
It will later be possible to replace the service with another storage mechanism by implementing ISettings and providing different constructor dependencies. Note that changing the constructor signature does not require a different interface.
That said, you should provide another service (or perhaps more than one) that takes ISettings as a dependency so you can make explicit properties. You should aim to provide focused sets of related properties for specific purposes. Your application also shouldn't have to know the type of property in order to retrieve its value - it should just call a property that hides those details.
public class SomeSettingsService: ISomeSettingsService
{
private readonly ISettings settings;
public SomeSettingsService(ISettings settings)
{
if (settings == null)
throw new ArgumentNullException("settings");
this.settings = settings;
}
public Poster Poster
{
get { return this.settings.GetValue<Poster>("Poster"); }
set { this.settings.SetValue<Poster>("Poster", value); }
}
public Posting Posting
{
get { return this.settings.GetValue<Posting>("Posting"); }
set { this.settings.SetValue<Posting>("Posting", value); }
}
public Property Property
{
get { return this.settings.GetValue<Property>("Property"); }
set { this.settings.SetValue<Property>("Property", value); }
}
}
Not sure if this is what you are asking... What I often do is create a service:
public interface ISessionService
{
object Get(string key);
void Save(string key, object value);
}
And then I implement this, which calls HttpContext.Current.Session[key] and returns the value. It shouldn't be hard to create a Get<T>(string key) to return an object either. Break all of your dependencies to use this (which is the hard part).
There is no seamless way to break the dependency... it has to be through a manual change.

implementing singleton class for Actionscript

I know actionscript does not allowed private contstructor at any time and But if i want to write a sinlgleton class in action script So how to implement it in actionscript.
Can anyone provide an sample example of a singleton pattern in actionscript?
I use something like this:
package singletons
{
[Bindable]
public class MySingleton
{
private static var _instance:MySingleton;
public function MySingleton(e:Enforcer) {
if(e == null) {
throw new Error("Hey! You can't do that! Call getInstance() instead!");
}
}
public static function getInstance():MySingleton {
if(_instance == null) {
_instance = new MySingleton (new Enforcer);
}
return _instance;
}
}
}
// an empty, private class, used to prevent outside sources from instantiating this locator
// directly, without using the getInstance() function....
class Enforcer{}
You need to alter Alxx's answer slightly as it doesn't stop new Singleton() from working...
public class Singleton {
private static var _instance : Singleton;
public function Singleton( newBlocker : ClassLock ) {
}
public static function getInstance() : Singleton {
if ( _instance == null ) {
_instance = new Singleton( new ClassLock() );
}
return _instance;
}
}
class ClassLock{}
The private class is used by the Singleton to stop other classes simply doing new Singleton() initially and then getting a second instance by doing getInstance().
Note that this still isn't watertight... If someone is determined to break it, they can get access to the private class, but this is about the best option for Singletons.
basically, all answers are right, those of reid and gregor provide more compile time safety. I suppose, the best thing is however, to declare an interface for the singleton and a private implementor exposed through a static class:
package {
interface IFoo {
function foo():void;
}
}
and then:
package Foo {
private static var _instance:IFoo;
public static function getInstance():IFoo {
if (_instance == null) _instance = new Impl();
return _instance;
}
}
class Impl implements IFoo {
public function foo():void {
trace("fooooooooooooooooooo");
}
}
this doesn't rely on runtime errors for safety. Also, it lowers coupling.
greetz
back2dos
public class Singleton {
private static var _instance:Singleton;
public **static** function get instance():Singleton
{
if (_instance == null)
{
_instance = new Singleton();
}
return _instance;
}
public function Singleton()
{
if (_instance != null) throw new Error("You can't create Singleton twice!");
}
}
Runtime check in lack of private constructor.
I use this approach ...
package
{
public class Main
{
private static var _instance:Main;
private static var _singletonLock:Boolean = false;
/**
* Creates a new instance of the class.
*/
public function Main()
{
if (!_singletonLock) throw new SingletonException(this);
}
/**
* Returns the singleton instance of the class.
*/
public static function get instance():Main
{
if (_instance == null)
{
_singletonLock = true;
_instance = new Main();
_singletonLock = false;
}
return _instance;
}
}
}
... not as terse as some other methods but it's absolutely safe and there's no need for an empty package-level class. Also note the shortcut with SingletonException which is a class that extends the AS3 Error class and saves typing some code when using more than one Singleton ...
package
{
public class SingletonException extends Error
{
public function SingletonException(object:Object)
{
super("Tried to instantiate the singleton " + object + " through it's constructor."
+ " Use the 'instance' property to get an instance of this singleton.");
}
}
}

Resources