Skip to content

Commit 41ecd77

Browse files
committed
Add the ability to retrieve the adapter and avoid null pointer exceptions when null adapter is passed
1 parent 2b17a2b commit 41ecd77

10 files changed

Lines changed: 176 additions & 68 deletions

File tree

adapterlayout/build.gradle

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
apply plugin: 'com.android.library'
2+
apply plugin: 'com.novoda.bintray-release'
23

34
android {
45
compileSdkVersion 23
@@ -22,3 +23,13 @@ dependencies {
2223
compile fileTree(include: ['*.jar'], dir: 'libs')
2324
compile 'com.android.support:recyclerview-v7:23.1.1'
2425
}
26+
27+
// ./gradlew clean build bintrayUpload -PbintrayUser=BINTRAY_USERNAME -PbintrayKey=BINTRAY_KEY -PdryRun=false
28+
publish {
29+
userOrg = 'commit451'
30+
groupId = 'com.commit451'
31+
artifactId = 'adapterlayout'
32+
publishVersion = '1.0.0'
33+
desc = 'ViewGroup backed by RecyclerView.Adapter = magic'
34+
website = 'https://github.com/Commit451/AdapterLayout'
35+
}

adapterlayout/src/main/java/com/commit451/adapterlayout/AdapterLayoutDelegate.java

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.commit451.adapterlayout;
22

3+
import android.support.annotation.Nullable;
34
import android.support.v7.widget.RecyclerView;
45
import android.view.View;
56
import android.view.ViewGroup;
@@ -21,6 +22,7 @@ public class AdapterLayoutDelegate {
2122
@Override
2223
public void onChanged() {
2324
super.onChanged();
25+
//TODO make this smarter so that it will actually remove the proper views
2426
updateViews();
2527
}
2628
};
@@ -45,14 +47,37 @@ public void setAdapter(RecyclerView.Adapter adapter) {
4547
}
4648

4749
mAdapter = adapter;
48-
mAdapter.registerAdapterDataObserver(mObserver);
50+
if (mAdapter != null) {
51+
mAdapter.registerAdapterDataObserver(mObserver);
52+
}
4953
updateViews();
5054
}
5155

56+
public @Nullable RecyclerView.Adapter getAdapter() {
57+
return mAdapter;
58+
}
59+
60+
/**
61+
* Return the {@link android.support.v7.widget.RecyclerView.ViewHolder} at the specified position.
62+
* @param index the position at which to get the ViewHolder
63+
* @return the ViewHolder at the index, or null if none exists
64+
*/
65+
public @Nullable RecyclerView.ViewHolder getViewHolderAt(int index) {
66+
View view = mViewGroup.getChildAt(index);
67+
if (view == null) {
68+
return null;
69+
}
70+
return (RecyclerView.ViewHolder) view.getTag(R.id.adapter_layout_list_holder);
71+
}
72+
5273
/**
5374
* Updates all the views to match the dataset changing
5475
*/
5576
private void updateViews() {
77+
if (mAdapter == null) {
78+
mViewGroup.removeAllViews();
79+
return;
80+
}
5681
for (int i = 0; i < mAdapter.getItemCount() || i < mViewGroup.getChildCount(); i++) {
5782

5883
//Within the bounds of the dataset

adapterlayout/src/main/java/com/commit451/adapterlayout/AdapterLinearLayout.java

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import android.annotation.TargetApi;
44
import android.content.Context;
5+
import android.support.annotation.Nullable;
56
import android.support.v7.widget.RecyclerView;
67
import android.util.AttributeSet;
78
import android.widget.Adapter;
@@ -18,30 +19,38 @@ public class AdapterLinearLayout extends LinearLayout {
1819

1920
public AdapterLinearLayout(Context context) {
2021
super(context);
21-
init();
2222
}
2323

2424
public AdapterLinearLayout(Context context, AttributeSet attrs) {
2525
super(context, attrs);
26-
init();
2726
}
2827

2928
public AdapterLinearLayout(Context context, AttributeSet attrs, int defStyleAttr) {
3029
super(context, attrs, defStyleAttr);
31-
init();
3230
}
3331

3432
@TargetApi(21)
3533
public AdapterLinearLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
3634
super(context, attrs, defStyleAttr, defStyleRes);
37-
init();
38-
}
39-
40-
private void init() {
41-
mAdapterLayoutDelegate = new AdapterLayoutDelegate(this);
4235
}
4336

4437
public void setAdapter(RecyclerView.Adapter adapter) {
38+
if (mAdapterLayoutDelegate == null) {
39+
mAdapterLayoutDelegate = new AdapterLayoutDelegate(this);
40+
}
4541
mAdapterLayoutDelegate.setAdapter(adapter);
4642
}
43+
44+
@Nullable
45+
public RecyclerView.Adapter getAdapter() {
46+
if (mAdapterLayoutDelegate != null) {
47+
return mAdapterLayoutDelegate.getAdapter();
48+
}
49+
return null;
50+
}
51+
52+
@Nullable
53+
public RecyclerView.ViewHolder getViewHolderAt(int index) {
54+
return mAdapterLayoutDelegate.getViewHolderAt(index);
55+
}
4756
}

app/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,5 +24,6 @@ dependencies {
2424
testCompile 'junit:junit:4.12'
2525
compile 'com.android.support:appcompat-v7:23.1.1'
2626
compile 'com.jakewharton:butterknife:7.0.1'
27+
compile "com.wefika:flowlayout:0.4.1"
2728
compile project(':adapterlayout')
2829
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package com.commit451.adapterlayout.sample;
2+
3+
import android.annotation.TargetApi;
4+
import android.content.Context;
5+
import android.support.annotation.Nullable;
6+
import android.support.v7.widget.RecyclerView;
7+
import android.util.AttributeSet;
8+
import android.widget.Adapter;
9+
import android.widget.LinearLayout;
10+
11+
import com.commit451.adapterlayout.AdapterLayoutDelegate;
12+
13+
/**
14+
* LinearLayout with {@link Adapter} support. See {@link AdapterLayoutDelegate} for
15+
* the good bits, and follow the convention here to create your own {@link android.support.v7.widget.RecyclerView.Adapter}
16+
* backed {@link android.view.ViewGroup}
17+
*/
18+
public class AdapterFlowLayout extends LinearLayout {
19+
20+
private AdapterLayoutDelegate mAdapterLayoutDelegate;
21+
22+
public AdapterFlowLayout(Context context) {
23+
super(context);
24+
}
25+
26+
public AdapterFlowLayout(Context context, AttributeSet attrs) {
27+
super(context, attrs);
28+
}
29+
30+
public AdapterFlowLayout(Context context, AttributeSet attrs, int defStyleAttr) {
31+
super(context, attrs, defStyleAttr);
32+
}
33+
34+
@TargetApi(21)
35+
public AdapterFlowLayout(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
36+
super(context, attrs, defStyleAttr, defStyleRes);
37+
}
38+
39+
public void setAdapter(RecyclerView.Adapter adapter) {
40+
if (mAdapterLayoutDelegate == null) {
41+
mAdapterLayoutDelegate = new AdapterLayoutDelegate(this);
42+
}
43+
mAdapterLayoutDelegate.setAdapter(adapter);
44+
}
45+
46+
@Nullable
47+
public RecyclerView.Adapter getAdapter() {
48+
if (mAdapterLayoutDelegate != null) {
49+
return mAdapterLayoutDelegate.getAdapter();
50+
}
51+
return null;
52+
}
53+
54+
@Nullable
55+
public RecyclerView.ViewHolder getViewHolderAt(int index) {
56+
return mAdapterLayoutDelegate.getViewHolderAt(index);
57+
}
58+
}

app/src/main/java/com/commit451/adapterlayout/sample/CheeseAdapter.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
package com.commit451.adapterlayout.sample;
22

3-
import android.content.Context;
43
import android.support.v7.widget.RecyclerView;
54
import android.view.View;
65
import android.view.ViewGroup;
@@ -25,7 +24,7 @@ public void onClick(View v) {
2524
}
2625
};
2726

28-
public CheeseAdapter(Context context, Listener listener) {
27+
public CheeseAdapter(Listener listener) {
2928
mListener = listener;
3029
mValues = new ArrayList<>();
3130
}
@@ -57,7 +56,7 @@ public void removeMiddle() {
5756
@Override
5857
public CheeseViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
5958
CheeseViewHolder holder = CheeseViewHolder.inflate(parent);
60-
//holder.itemView.setOnClickListener(mOnClickListener);
59+
holder.itemView.setOnClickListener(mOnClickListener);
6160
return holder;
6261
}
6362

app/src/main/java/com/commit451/adapterlayout/sample/MainActivity.java

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,27 @@ void onRemoveMiddleClicked() {
3030
mAdapter.removeMiddle();
3131
}
3232

33+
@OnClick(R.id.new_adapter)
34+
void onNewAdapterClicked() {
35+
mAdapterLinearLayout.setAdapter(null);
36+
mAdapter = new CheeseAdapter(mListener);
37+
mAdapterLinearLayout.setAdapter(mAdapter);
38+
}
39+
40+
private CheeseAdapter.Listener mListener = new CheeseAdapter.Listener() {
41+
@Override
42+
public void onItemClicked(Cheese cheese) {
43+
Toast.makeText(MainActivity.this, cheese.getName() + " clicked", Toast.LENGTH_SHORT)
44+
.show();
45+
}
46+
};
47+
3348
@Override
3449
protected void onCreate(Bundle savedInstanceState) {
3550
super.onCreate(savedInstanceState);
3651
setContentView(R.layout.activity_main);
3752
ButterKnife.bind(this);
38-
mAdapter = new CheeseAdapter(this, new CheeseAdapter.Listener() {
39-
@Override
40-
public void onItemClicked(Cheese cheese) {
41-
Toast.makeText(MainActivity.this, "Clicked", Toast.LENGTH_SHORT).show();
42-
}
43-
});
53+
mAdapter = new CheeseAdapter(mListener);
4454
mAdapterLinearLayout.setAdapter(mAdapter);
4555
}
4656
}
Lines changed: 38 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,48 @@
11
<?xml version="1.0" encoding="utf-8"?>
2-
<ScrollView
3-
xmlns:android="http://schemas.android.com/apk/res/android"
2+
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
43
android:layout_width="match_parent"
54
android:layout_height="match_parent">
65

76
<LinearLayout
87
android:layout_width="match_parent"
98
android:layout_height="wrap_content"
10-
android:orientation="vertical"
11-
android:animateLayoutChanges="true">
12-
13-
<com.commit451.adapterlayout.AdapterLinearLayout
14-
android:id="@+id/adapter_layout"
15-
android:layout_width="match_parent"
16-
android:layout_height="wrap_content"
17-
android:animateLayoutChanges="true"
18-
android:paddingBottom="@dimen/activity_vertical_margin"
19-
android:paddingLeft="@dimen/activity_horizontal_margin"
20-
android:paddingRight="@dimen/activity_horizontal_margin"
21-
android:paddingTop="@dimen/activity_vertical_margin"
22-
android:orientation="vertical"/>
23-
24-
<LinearLayout
25-
android:layout_width="match_parent"
26-
android:layout_height="wrap_content"
27-
android:orientation="horizontal">
28-
29-
<Button
30-
android:id="@+id/add_cheese"
31-
android:layout_width="wrap_content"
32-
android:layout_height="wrap_content"
33-
android:text="Add"/>
34-
35-
<Button
36-
android:id="@+id/remove_cheese"
37-
android:layout_width="wrap_content"
38-
android:layout_height="wrap_content"
39-
android:text="Remove Last"/>
40-
41-
<Button
42-
android:id="@+id/remove_middle"
43-
android:layout_width="wrap_content"
44-
android:layout_height="wrap_content"
45-
android:text="Remove Middle"/>
46-
47-
</LinearLayout>
9+
android:orientation="vertical">
10+
11+
<com.commit451.adapterlayout.AdapterLinearLayout
12+
android:id="@+id/adapter_layout"
13+
android:layout_width="wrap_content"
14+
android:layout_height="wrap_content"
15+
android:orientation="vertical"/>
16+
17+
<com.wefika.flowlayout.FlowLayout
18+
android:layout_width="match_parent"
19+
android:layout_height="wrap_content">
20+
21+
<Button
22+
android:id="@+id/add_cheese"
23+
android:layout_width="wrap_content"
24+
android:layout_height="wrap_content"
25+
android:text="Add" />
26+
27+
<Button
28+
android:id="@+id/remove_cheese"
29+
android:layout_width="wrap_content"
30+
android:layout_height="wrap_content"
31+
android:text="Remove Last" />
32+
33+
<Button
34+
android:id="@+id/remove_middle"
35+
android:layout_width="wrap_content"
36+
android:layout_height="wrap_content"
37+
android:text="Remove Middle" />
38+
39+
<Button
40+
android:id="@+id/new_adapter"
41+
android:layout_width="wrap_content"
42+
android:layout_height="wrap_content"
43+
android:text="New Adapter" />
44+
45+
</com.wefika.flowlayout.FlowLayout>
4846
</LinearLayout>
4947

5048
</ScrollView>
Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,7 @@
11
<?xml version="1.0" encoding="utf-8"?>
2-
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
3-
android:orientation="vertical" android:layout_width="match_parent"
4-
android:layout_height="match_parent">
5-
6-
<TextView
7-
android:id="@+id/text"
8-
android:layout_width="wrap_content"
9-
android:layout_height="wrap_content" />
10-
11-
</LinearLayout>
2+
<TextView
3+
xmlns:android="http://schemas.android.com/apk/res/android"
4+
android:id="@+id/text"
5+
android:layout_width="wrap_content"
6+
android:layout_height="wrap_content"
7+
android:layout_margin="16dp"/>

build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ buildscript {
66
}
77
dependencies {
88
classpath 'com.android.tools.build:gradle:1.5.0'
9+
classpath 'com.novoda:bintray-release:0.3.4'
910

1011
// NOTE: Do not place your application dependencies here; they belong
1112
// in the individual module build.gradle files

0 commit comments

Comments
 (0)