clone() method and Singleton pattern in Java

When we are writing a class using the Singleton pattern, there should be only one instance of that class at a time. We implement this by making the constructor private and adding a getInstance() method.

But what happens if we clone an instance of this class? You might think it won’t work because the constructor is private. But it works!! So we can actually make two instances of that class. Java does NOT handle this and we should do that by ourselves.

So how can we stop this? We need to override the clone() method like this,

@Override
protected Object clone() throws CloneNotSupportedException{
	throw new CloneNotSupportedException();
}

Now whenever we try to make a clone it will throw this CloneNotSupportedException.

Android ViewPager with Multiple Views

Recently I had to customize the standard ViewPager in order to make multiple Views visible at the same time. Here’s how I achieved this.

First let’s add a standard ViewPager to our Activity.

In the layout XML file,

<FrameLayout
android:id="@+id/container"
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:background="#FFFFFF">

<android.support.v4.view.ViewPager
android:id="@+id/viewpager"
android:layout_width="200dip"
android:layout_height="200dip"
android:layout_gravity="center_horizontal|center_vertical"/>
</FrameLayout>

In the Activity we need to set a PagerAdapter which will supply views to the ViewPager.

@Override
protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	setContentView(R.layout.activity_main);
	ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
	viewPager.setAdapter(new ViewAdapter());
}

private class ViewAdapter extends PagerAdapter{

@Override
public int getCount() {
	return 4;
}

@Override
public boolean isViewFromObject(View view, Object object) {
	return (view == object);
}

@Override
public Object instantiateItem(ViewGroup container, int position) {
	TextView textView = new TextView(MainActivity.this);
	textView.setText(“Item “+position);
	textView.setBackgroundResource(R.drawable.ic_launcher);
	((ViewPager)container).addView(textView, 0);
	return textView;
}

@Override
public void destroyItem(ViewGroup container, int position, Object object) {
	((ViewPager) container).removeView((TextView)object);
}

}

When we Run the application the output looks like this.

viewpager1

We can swipe left and right to navigate through Views. But we can see only one View at a time! 

We can modify this code and make the hidden views visible all the time.

First we need to create a custom container for the ViewPager by extending FrameLayout. Let’s call it ViewPagerContainer. And call this init method in its constructor.

private void init() {
	setClipChildren(false);
	setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}

We have to use this as the container instead of the FrameLayout in the layout XML file.

<com.example.viewpagerexample.ViewPagerContainer

android:id=”@+id/container”
android:layout_width=”match_parent”
android:layout_height=”fill_parent”
android:background=”#FFFFFF”>

<android.support.v4.view.ViewPager
android:id=”@+id/viewpager”
android:layout_width=”200dip”
android:layout_height=”200dip”
android:layout_gravity=”center_horizontal|center_vertical”/>

</com.example.viewpagerexample.ViewPagerContainer>

Finally in the Activity add these lines.

ViewPager viewPager = (ViewPager) findViewById(R.id.viewpager);
viewPager.setAdapter(new ViewAdapter());
viewPager.setOffscreenPageLimit(5);
viewPager.setPageMargin(15);
viewPager.setClipChildren(false);

Now when we run the application it should look like this. It will not clip the child views now.

viewpager2

But there’s a problem here. We can swipe only the middle view. This is because the touch events occur outside the ViewPagers bounds. We can override the onTouchEvent of the ViewPagerContainer and dispatch the events to the ViewPager to solve this.

private ViewPager mPager;

@Override
protected void onFinishInflate() {
	mPager = (ViewPager) getChildAt(0);
}

@Override
public boolean onTouchEvent(MotionEvent ev) {
	return mPager.dispatchTouchEvent(ev);
}