diff --git a/CommonAdapter/.gitignore b/CommonAdapter/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/CommonAdapter/.gitignore @@ -0,0 +1 @@ +/build diff --git a/CommonAdapter/build.gradle b/CommonAdapter/build.gradle new file mode 100644 index 0000000..e642db8 --- /dev/null +++ b/CommonAdapter/build.gradle @@ -0,0 +1,24 @@ +apply plugin: 'com.android.library' + +android { + compileSdkVersion 22 + buildToolsVersion "22.0.1" + + defaultConfig { + minSdkVersion 15 + targetSdkVersion 22 + versionCode 1 + versionName "1.0" + } + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + compile fileTree(include: ['*.jar'], dir: 'libs') + compile 'com.android.support:appcompat-v7:22.2.1' +} diff --git a/CommonAdapter/proguard-rules.pro b/CommonAdapter/proguard-rules.pro new file mode 100644 index 0000000..c25e0d4 --- /dev/null +++ b/CommonAdapter/proguard-rules.pro @@ -0,0 +1,17 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in E:\as_android_sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} diff --git a/CommonAdapter/src/androidTest/java/click/gank/commonadapter/ApplicationTest.java b/CommonAdapter/src/androidTest/java/click/gank/commonadapter/ApplicationTest.java new file mode 100644 index 0000000..1a986e2 --- /dev/null +++ b/CommonAdapter/src/androidTest/java/click/gank/commonadapter/ApplicationTest.java @@ -0,0 +1,13 @@ +package click.gank.commonadapter; + +import android.app.Application; +import android.test.ApplicationTestCase; + +/** + * Testing Fundamentals + */ +public class ApplicationTest extends ApplicationTestCase { + public ApplicationTest() { + super(Application.class); + } +} \ No newline at end of file diff --git a/CommonAdapter/src/main/AndroidManifest.xml b/CommonAdapter/src/main/AndroidManifest.xml new file mode 100644 index 0000000..6657597 --- /dev/null +++ b/CommonAdapter/src/main/AndroidManifest.xml @@ -0,0 +1,10 @@ + + + + + + + diff --git a/CommonAdapter/src/main/java/ganke/adapter/BaseAdapterHelper.java b/CommonAdapter/src/main/java/ganke/adapter/BaseAdapterHelper.java new file mode 100644 index 0000000..f998104 --- /dev/null +++ b/CommonAdapter/src/main/java/ganke/adapter/BaseAdapterHelper.java @@ -0,0 +1,487 @@ +/** + * Copyright 2013 Joan Zapata + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ganke.adapter; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Paint; +import android.graphics.Typeface; +import android.graphics.drawable.Drawable; +import android.os.Build; +import android.text.util.Linkify; +import android.util.SparseArray; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.view.animation.AlphaAnimation; +import android.widget.Adapter; +import android.widget.AdapterView; +import android.widget.Checkable; +import android.widget.ImageView; +import android.widget.ProgressBar; +import android.widget.RatingBar; +import android.widget.TextView; + +/** + * Allows an abstraction of the ViewHolder pattern.
+ *
+ *

+ * Usage + *

+ *

+ * return BaseAdapterHelper.get(context, convertView, parent, R.layout.item)
+ *         .setText(R.id.tvName, contact.getName())
+ *         .setText(R.id.tvEmails, contact.getEmails().toString())
+ *         .setText(R.id.tvNumbers, contact.getNumbers().toString())
+ *         .getView();
+ * 
+ */ +public class BaseAdapterHelper { + + /** Views indexed with their IDs */ + private final SparseArray views; + + private final Context context; + + protected int position; + + private View convertView; + + /** Package private field to retain the associated user object and detect a change */ + Object associatedObject; + + protected BaseAdapterHelper(Context context, ViewGroup parent, int layoutId, int position) { + this.context = context; + this.position = position; + this.views = new SparseArray(); + convertView = LayoutInflater.from(context).inflate(layoutId, parent, false); + convertView.setTag(this); + } + + /** + * This method is the only entry point to get a BaseAdapterHelper. + * @param context The current context. + * @param convertView The convertView arg passed to the getView() method. + * @param parent The parent arg passed to the getView() method. + * @return A BaseAdapterHelper instance. + */ + public static BaseAdapterHelper get(Context context, View convertView, ViewGroup parent, int layoutId) { + return get(context, convertView, parent, layoutId, -1); + } + + /** This method is package private and should only be used by QuickAdapter. */ + static BaseAdapterHelper get(Context context, View convertView, ViewGroup parent, int layoutId, int position) { + if (convertView == null) { + return new BaseAdapterHelper(context, parent, layoutId, position); + } + + // Retrieve the existing helper and update its position + BaseAdapterHelper existingHelper = (BaseAdapterHelper) convertView.getTag(); + existingHelper.position = position; + return existingHelper; + } + + /** + * This method allows you to retrieve a view and perform custom + * operations on it, not covered by the BaseAdapterHelper.
+ * If you think it's a common use case, please consider creating + * a new issue at https://github.com/JoanZapata/base-adapter-helper/issues. + * @param viewId The id of the view you want to retrieve. + */ + public T getView(int viewId) { + return retrieveView(viewId); + } + + /** + * Will set the text of a TextView. + * @param viewId The view id. + * @param value The text to put in the text view. + * @return The BaseAdapterHelper for chaining. + */ + public BaseAdapterHelper setText(int viewId, String value) { + TextView view = retrieveView(viewId); + view.setText(value); + return this; + } + + /** + * Will set the image of an ImageView from a resource id. + * @param viewId The view id. + * @param imageResId The image resource id. + * @return The BaseAdapterHelper for chaining. + */ + public BaseAdapterHelper setImageResource(int viewId, int imageResId) { + ImageView view = retrieveView(viewId); + view.setImageResource(imageResId); + return this; + } + + /** + * Will set background color of a view. + * @param viewId The view id. + * @param color A color, not a resource id. + * @return The BaseAdapterHelper for chaining. + */ + public BaseAdapterHelper setBackgroundColor(int viewId, int color) { + View view = retrieveView(viewId); + view.setBackgroundColor(color); + return this; + } + + /** + * Will set background of a view. + * @param viewId The view id. + * @param backgroundRes A resource to use as a background. + * @return The BaseAdapterHelper for chaining. + */ + public BaseAdapterHelper setBackgroundRes(int viewId, int backgroundRes) { + View view = retrieveView(viewId); + view.setBackgroundResource(backgroundRes); + return this; + } + + /** + * Will set text color of a TextView. + * @param viewId The view id. + * @param textColor The text color (not a resource id). + * @return The BaseAdapterHelper for chaining. + */ + public BaseAdapterHelper setTextColor(int viewId, int textColor) { + TextView view = retrieveView(viewId); + view.setTextColor(textColor); + return this; + } + + /** + * Will set text color of a TextView. + * @param viewId The view id. + * @param textColorRes The text color resource id. + * @return The BaseAdapterHelper for chaining. + */ + public BaseAdapterHelper setTextColorRes(int viewId, int textColorRes) { + TextView view = retrieveView(viewId); + view.setTextColor(context.getResources().getColor(textColorRes)); + return this; + } + + /** + * Will set the image of an ImageView from a drawable. + * @param viewId The view id. + * @param drawable The image drawable. + * @return The BaseAdapterHelper for chaining. + */ + public BaseAdapterHelper setImageDrawable(int viewId, Drawable drawable) { + ImageView view = retrieveView(viewId); + view.setImageDrawable(drawable); + return this; + } + + /** + * 异步下载图片,需自行实现 + * @param viewId The view id. + * @param imageUrl The image URL. + * @return The BaseAdapterHelper for chaining. + */ + public BaseAdapterHelper setImageUrl(int viewId, String imageUrl) { + ImageView view = retrieveView(viewId); +// Picasso.with(context).load(imageUrl).into(view); + return this; + } + + /** Add an action to set the image of an image view. Can be called multiple times. */ + public BaseAdapterHelper setImageBitmap(int viewId, Bitmap bitmap) { + ImageView view = retrieveView(viewId); + view.setImageBitmap(bitmap); + return this; + } + + /** + * Add an action to set the alpha of a view. Can be called multiple times. + * Alpha between 0-1. + */ + public BaseAdapterHelper setAlpha(int viewId, float value) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) { + retrieveView(viewId).setAlpha(value); + } else { + // Pre-honeycomb hack to set Alpha value + AlphaAnimation alpha = new AlphaAnimation(value, value); + alpha.setDuration(0); + alpha.setFillAfter(true); + retrieveView(viewId).startAnimation(alpha); + } + return this; + } + + /** + * Set a view visibility to VISIBLE (true) or GONE (false). + * @param viewId The view id. + * @param visible True for VISIBLE, false for GONE. + * @return The BaseAdapterHelper for chaining. + */ + public BaseAdapterHelper setVisible(int viewId, boolean visible) { + View view = retrieveView(viewId); + view.setVisibility(visible ? View.VISIBLE : View.GONE); + return this; + } + + /** + * Add links into a TextView. + * @param viewId The id of the TextView to linkify. + * @return The BaseAdapterHelper for chaining. + */ + public BaseAdapterHelper linkify(int viewId) { + TextView view = retrieveView(viewId); + Linkify.addLinks(view, Linkify.ALL); + return this; + } + + /** Apply the typeface to the given viewId, and enable subpixel rendering. */ + public BaseAdapterHelper setTypeface(int viewId, Typeface typeface) { + TextView view = retrieveView(viewId); + view.setTypeface(typeface); + view.setPaintFlags(view.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG); + return this; + } + + /** Apply the typeface to all the given viewIds, and enable subpixel rendering. */ + public BaseAdapterHelper setTypeface(Typeface typeface, int... viewIds) { + for (int viewId : viewIds) { + TextView view = retrieveView(viewId); + view.setTypeface(typeface); + view.setPaintFlags(view.getPaintFlags() | Paint.SUBPIXEL_TEXT_FLAG); + } + return this; + } + + /** + * Sets the progress of a ProgressBar. + * @param viewId The view id. + * @param progress The progress. + * @return The BaseAdapterHelper for chaining. + */ + public BaseAdapterHelper setProgress(int viewId, int progress) { + ProgressBar view = retrieveView(viewId); + view.setProgress(progress); + return this; + } + + /** + * Sets the progress and max of a ProgressBar. + * @param viewId The view id. + * @param progress The progress. + * @param max The max value of a ProgressBar. + * @return The BaseAdapterHelper for chaining. + */ + public BaseAdapterHelper setProgress(int viewId, int progress, int max) { + ProgressBar view = retrieveView(viewId); + view.setMax(max); + view.setProgress(progress); + return this; + } + + /** + * Sets the range of a ProgressBar to 0...max. + * @param viewId The view id. + * @param max The max value of a ProgressBar. + * @return The BaseAdapterHelper for chaining. + */ + public BaseAdapterHelper setMax(int viewId, int max) { + ProgressBar view = retrieveView(viewId); + view.setMax(max); + return this; + } + + /** + * Sets the rating (the number of stars filled) of a RatingBar. + * @param viewId The view id. + * @param rating The rating. + * @return The BaseAdapterHelper for chaining. + */ + public BaseAdapterHelper setRating(int viewId, float rating) { + RatingBar view = retrieveView(viewId); + view.setRating(rating); + return this; + } + + /** + * Sets the rating (the number of stars filled) and max of a RatingBar. + * @param viewId The view id. + * @param rating The rating. + * @param max The range of the RatingBar to 0...max. + * @return The BaseAdapterHelper for chaining. + */ + public BaseAdapterHelper setRating(int viewId, float rating, int max) { + RatingBar view = retrieveView(viewId); + view.setMax(max); + view.setRating(rating); + return this; + } + + /** + * Sets the on click listener of the view. + * @param viewId The view id. + * @param listener The on click listener; + * @return The BaseAdapterHelper for chaining. + */ + public BaseAdapterHelper setOnClickListener(int viewId, View.OnClickListener listener) { + View view = retrieveView(viewId); + view.setOnClickListener(listener); + return this; + } + + /** + * Sets the on touch listener of the view. + * @param viewId The view id. + * @param listener The on touch listener; + * @return The BaseAdapterHelper for chaining. + */ + public BaseAdapterHelper setOnTouchListener(int viewId, View.OnTouchListener listener) { + View view = retrieveView(viewId); + view.setOnTouchListener(listener); + return this; + } + + /** + * Sets the on long click listener of the view. + * @param viewId The view id. + * @param listener The on long click listener; + * @return The BaseAdapterHelper for chaining. + */ + public BaseAdapterHelper setOnLongClickListener(int viewId, View.OnLongClickListener listener) { + View view = retrieveView(viewId); + view.setOnLongClickListener(listener); + return this; + } + + /** + * Sets the listview or gridview's item click listener of the view + * @param viewId The view id. + * @param listener The item on click listener; + * @return The BaseAdapterHelper for chaining. + */ + public BaseAdapterHelper setOnItemClickListener(int viewId,AdapterView.OnItemClickListener listener) { + AdapterView view = retrieveView(viewId); + view.setOnItemClickListener(listener); + return this; + } + /** + * Sets the listview or gridview's item long click listener of the view + * @param viewId The view id. + * @param listener The item long click listener; + * @return The BaseAdapterHelper for chaining. + */ + public BaseAdapterHelper setOnItemLongClickListener(int viewId,AdapterView.OnItemLongClickListener listener) { + AdapterView view = retrieveView(viewId); + view.setOnItemLongClickListener(listener); + return this; + } + /** + * Sets the listview or gridview's item selected click listener of the view + * @param viewId The view id. + * @param listener The item selected click listener; + * @return The BaseAdapterHelper for chaining. + */ + public BaseAdapterHelper setOnItemSelectedClickListener(int viewId,AdapterView.OnItemSelectedListener listener) { + AdapterView view = retrieveView(viewId); + view.setOnItemSelectedListener(listener); + return this; + } + /** + * Sets the tag of the view. + * @param viewId The view id. + * @param tag The tag; + * @return The BaseAdapterHelper for chaining. + */ + public BaseAdapterHelper setTag(int viewId, Object tag) { + View view = retrieveView(viewId); + view.setTag(tag); + return this; + } + + /** + * Sets the tag of the view. + * @param viewId The view id. + * @param key The key of tag; + * @param tag The tag; + * @return The BaseAdapterHelper for chaining. + */ + public BaseAdapterHelper setTag(int viewId, int key, Object tag) { + View view = retrieveView(viewId); + view.setTag(key, tag); + return this; + } + + /** + * Sets the checked status of a checkable. + * @param viewId The view id. + * @param checked The checked status; + * @return The BaseAdapterHelper for chaining. + */ + public BaseAdapterHelper setChecked(int viewId, boolean checked) { + Checkable view = (Checkable) retrieveView(viewId); + view.setChecked(checked); + return this; + } + + /** + * Sets the adapter of a adapter view. + * @param viewId The view id. + * @param adapter The adapter; + * @return The BaseAdapterHelper for chaining. + */ + public BaseAdapterHelper setAdapter(int viewId, Adapter adapter) { + AdapterView view = retrieveView(viewId); + view.setAdapter(adapter); + return this; + } + + /** Retrieve the convertView */ + public View getView() { + return convertView; + } + + /** + * Retrieve the overall position of the datas in the list. + * @throws IllegalArgumentException If the position hasn't been set at the construction of the this helper. + */ + public int getPosition() { + if (position == -1) + throw new IllegalStateException("Use BaseAdapterHelper constructor " + + "with position if you need to retrieve the position."); + return position; + } + + @SuppressWarnings("unchecked") + protected T retrieveView(int viewId) { + View view = views.get(viewId); + if (view == null) { + view = convertView.findViewById(viewId); + views.put(viewId, view); + } + return (T) view; + } + + /** Retrieves the last converted object on this view. */ + public Object getAssociatedObject() { + return associatedObject; + } + + /** Should be called during convert */ + public void setAssociatedObject(Object associatedObject) { + this.associatedObject = associatedObject; + } + +} diff --git a/CommonAdapter/src/main/java/ganke/adapter/BaseQuickAdapter.java b/CommonAdapter/src/main/java/ganke/adapter/BaseQuickAdapter.java new file mode 100644 index 0000000..5b871ec --- /dev/null +++ b/CommonAdapter/src/main/java/ganke/adapter/BaseQuickAdapter.java @@ -0,0 +1,163 @@ +/** + * Copyright 2013 Joan Zapata + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ganke.adapter; + +import android.content.Context; +import android.view.View; +import android.view.ViewGroup; +import android.widget.BaseAdapter; + +import java.util.ArrayList; +import java.util.List; + +/** + * Abstraction class of a BaseAdapter in which you only need + * to provide the convert() implementation.
+ * Using the provided BaseAdapterHelper, your code is minimalist. + * @param The type of the items in the list. + */ +public abstract class BaseQuickAdapter extends BaseAdapter { + + protected static final String TAG = BaseQuickAdapter.class.getSimpleName(); + + protected final Context context; + + protected final int layoutResId; + + protected final List datas; + + /** + * Create a QuickAdapter. + * @param context The context. + * @param layoutResId The layout resource id of each item. + */ + public BaseQuickAdapter(Context context, int layoutResId) { + this(context, layoutResId, null); + } + + /** + * Same as QuickAdapter#QuickAdapter(Context,int) but with + * some initialization datas. + * @param context The context. + * @param layoutResId The layout resource id of each item. + * @param datas A new list is created out of this one to avoid mutable list + */ + public BaseQuickAdapter(Context context, int layoutResId, List datas) { + this.datas = datas == null ? new ArrayList() : new ArrayList(datas); + this.context = context; + this.layoutResId = layoutResId; + } + + @Override + public int getCount() { + return datas.size(); + } + + @Override + public T getItem(int position) { + if (position >= datas.size()) return null; + return datas.get(position); + } + + @Override + public long getItemId(int position) { + return position; + } + + + @Override + public View getView(int position, View convertView, ViewGroup parent) { + final H helper = getAdapterHelper(position, convertView, parent); + T item = getItem(position); + convert(helper, item, position); + helper.setAssociatedObject(item); + return helper.getView(); + } + + + @Override + public boolean isEnabled(int position) { + return position < datas.size(); + } + + public void add(T elem) { + datas.add(elem); + notifyDataSetChanged(); + } + + public void addAll(List elem) { + datas.addAll(elem); + notifyDataSetChanged(); + } + + public void set(T oldElem, T newElem) { + set(datas.indexOf(oldElem), newElem); + } + + public void set(int index, T elem) { + datas.set(index, elem); + notifyDataSetChanged(); + } + + public void remove(T elem) { + datas.remove(elem); + notifyDataSetChanged(); + } + + public void remove(int index) { + datas.remove(index); + notifyDataSetChanged(); + } + + public void replaceAll(List elem) { + datas.clear(); + datas.addAll(elem); + notifyDataSetChanged(); + } + + public boolean contains(T elem) { + return datas.contains(elem); + } + + /** Clear datas list */ + public void clear() { + datas.clear(); + notifyDataSetChanged(); + } + + + /** + * Implement this method and use the helper to adapt the view to the given item. + * @param helper A fully initialized helper. + * @param item The item that needs to be displayed. + */ + protected abstract void convert(H helper, T item, int position); + + /** + * You can override this method to use a custom BaseAdapterHelper in order to fit your needs + * @param position The position of the item within the adapter's datas set of the item whose view we want. + * @param convertView The old view to reuse, if possible. Note: You should check that this view + * is non-null and of an appropriate type before using. If it is not possible to convert + * this view to display the correct datas, this method can create a new view. + * Heterogeneous lists can specify their number of view types, so that this View is + * always of the right type (see {@link #getViewTypeCount()} and + * {@link #getItemViewType(int)}). + * @param parent The parent that this view will eventually be attached to + * @return An instance of BaseAdapterHelper + */ + protected abstract H getAdapterHelper(int position, View convertView, ViewGroup parent); + +} diff --git a/CommonAdapter/src/main/java/ganke/adapter/EnhancedQuickAdapter.java b/CommonAdapter/src/main/java/ganke/adapter/EnhancedQuickAdapter.java new file mode 100644 index 0000000..585ebdb --- /dev/null +++ b/CommonAdapter/src/main/java/ganke/adapter/EnhancedQuickAdapter.java @@ -0,0 +1,56 @@ +/** + * Copyright 2013 Joan Zapata + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ganke.adapter; + +import android.content.Context; + +import java.util.List; + +/** + * Same as QuickAdapter, but adds an "itemChanged" boolean in the + * convert() method params, which allows you to know if you are + * adapting the new view to the same item or not, and therefore + * make a difference between dataset changed / dataset invalidated. + *

+ * Abstraction class of a BaseAdapter in which you only need + * to provide the convert() implementation.
+ * Using the provided BaseAdapterHelper, your code is minimalist. + * @param The type of the items in the list. + */ +public abstract class EnhancedQuickAdapter extends QuickAdapter { + + public EnhancedQuickAdapter(Context context, int layoutResId) { + super(context, layoutResId); + } + + public EnhancedQuickAdapter(Context context, int layoutResId, List datas) { + super(context, layoutResId, datas); + } + + @Override + protected final void convert(BaseAdapterHelper helper, T item, int position) { + boolean itemChanged = helper.associatedObject == null || !helper.associatedObject.equals(item); + helper.associatedObject = item; + convert(helper, item, position, itemChanged); + } + + /** + * @param helper The helper to use to adapt the view. + * @param item The item you should adapt the view to. + * @param itemChanged Whether or not the helper was bound to another object before. + */ + protected abstract void convert(BaseAdapterHelper helper, T item, int position, boolean itemChanged); +} diff --git a/CommonAdapter/src/main/java/ganke/adapter/QuickAdapter.java b/CommonAdapter/src/main/java/ganke/adapter/QuickAdapter.java new file mode 100644 index 0000000..c1bccfe --- /dev/null +++ b/CommonAdapter/src/main/java/ganke/adapter/QuickAdapter.java @@ -0,0 +1,45 @@ +/** + * Copyright 2013 Joan Zapata + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package ganke.adapter; + +import android.content.Context; +import android.view.View; +import android.view.ViewGroup; + +import java.util.List; + + +/** + * Abstraction class of a BaseAdapter in which you only need + * to provide the convert() implementation.
+ * Using the provided BaseAdapterHelper, your code is minimalist. + * @param The type of the items in the list. + */ +public abstract class QuickAdapter extends BaseQuickAdapter { + + public QuickAdapter(Context context, int layoutResId) { + super(context, layoutResId); + } + + public QuickAdapter(Context context, int layoutResId, List datas) { + super(context, layoutResId, datas); + } + + protected BaseAdapterHelper getAdapterHelper(int position, View convertView, ViewGroup parent) { + return BaseAdapterHelper.get(context, convertView, parent, layoutResId, position); + } + +} diff --git a/CommonAdapter/src/main/res/values/strings.xml b/CommonAdapter/src/main/res/values/strings.xml new file mode 100644 index 0000000..6d51856 --- /dev/null +++ b/CommonAdapter/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + Library + diff --git a/app/build.gradle b/app/build.gradle index 62aabd7..084f9cb 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -35,4 +35,5 @@ dependencies { compile 'com.jakewharton:butterknife:7.0.1' compile 'com.mcxiaoke.volley:library:1.0.18' compile 'com.github.kassadin:PullToRefresh:1.0.2' + compile project(':CommonAdapter') } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 95ddb9e..7d979c9 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,6 +2,8 @@ + + kassadin@foxmail.com on 15/8/21 21:38 */ public class GankeApp extends Application { - private static GankeApp INSTANCE; - - public static GankeApp getInstance() { - return INSTANCE; - } + private static RequestQueue requestQueue; @Override public void onCreate() { super.onCreate(); - INSTANCE = this; + requestQueue = Volley.newRequestQueue(this); } + + public static RequestQueue getRequestQueue() { + return requestQueue; + } + } diff --git a/app/src/main/java/com/github/koooe/ganke/api/Api.java b/app/src/main/java/com/github/koooe/ganke/api/Api.java index 69135d4..19e51d7 100644 --- a/app/src/main/java/com/github/koooe/ganke/api/Api.java +++ b/app/src/main/java/com/github/koooe/ganke/api/Api.java @@ -1,14 +1,40 @@ package com.github.koooe.ganke.api; +import com.android.volley.Response; +import com.android.volley.toolbox.StringRequest; +import com.github.koooe.ganke.GankeApp; +import com.github.koooe.ganke.util.DebugLog; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; + /** * Created by kassadin@foxmail.com on 15/8/21 22:32 */ public class Api { - public static final String[] categories = {"iOS", - "Android", - "瞎推荐", - "拓展资源", - "福利", - "休息视频"}; + public static final String[] categories = {"Android", "iOS", + "前端", "拓展资源","福利", "休息视频"}; + + public static final int PAGE_ZISE = 10; + public static final String GANK_DATA = "http://gank.avosapps.com/api/data/%s/" + PAGE_ZISE + "/%d"; + public static final String GANK_DAY = "http://gank.avosapps.com/api/day/2015/08/06"; + public static final String GANK_RAMDOM = "http://gank.avosapps.com/api/random/data/Android/20"; + + + public static void getData(String category, int page, Response.Listener listener, + Response.ErrorListener errorListener){ + try { + category = URLEncoder.encode(category, "utf-8"); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + + String url = String.format(GANK_DATA, category, page); + DebugLog.d(url); + StringRequest request = new StringRequest(url, listener, errorListener); + GankeApp.getRequestQueue().add(request); + + } + } diff --git a/app/src/main/java/com/github/koooe/ganke/bean/BaseResponse.java b/app/src/main/java/com/github/koooe/ganke/bean/BaseResponse.java new file mode 100644 index 0000000..703aff3 --- /dev/null +++ b/app/src/main/java/com/github/koooe/ganke/bean/BaseResponse.java @@ -0,0 +1,25 @@ +package com.github.koooe.ganke.bean; + +import java.util.List; + +public class BaseResponse { + + private boolean error; + private List results; + + public boolean isError() { + return error; + } + + public void setError(boolean error) { + this.error = error; + } + + public List getResults() { + return results; + } + + public void setResults(List results) { + this.results = results; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/github/koooe/ganke/bean/DayData.java b/app/src/main/java/com/github/koooe/ganke/bean/DayData.java new file mode 100644 index 0000000..2bc9c6e --- /dev/null +++ b/app/src/main/java/com/github/koooe/ganke/bean/DayData.java @@ -0,0 +1,94 @@ +package com.github.koooe.ganke.bean; + +public class DayData { + private String who; + + private String publishedAt; + + private String desc; + + private String type; + + private String url; + + private boolean used; + + private String objectId; + + private String createdAt; + + private String updatedAt; + + public String getWho() { + return this.who; + } + + public void setWho(String who) { + this.who = who; + } + + public String getPublishedAt() { + return this.publishedAt; + } + + public void setPublishedAt(String publishedAt) { + this.publishedAt = publishedAt; + } + + public String getDesc() { + return this.desc; + } + + public void setDesc(String desc) { + this.desc = desc; + } + + public String getType() { + return this.type; + } + + public void setType(String type) { + this.type = type; + } + + public String getUrl() { + return this.url; + } + + public void setUrl(String url) { + this.url = url; + } + + public boolean getUsed() { + return this.used; + } + + public void setUsed(boolean used) { + this.used = used; + } + + public String getObjectId() { + return this.objectId; + } + + public void setObjectId(String objectId) { + this.objectId = objectId; + } + + public String getCreatedAt() { + return this.createdAt; + } + + public void setCreatedAt(String createdAt) { + this.createdAt = createdAt; + } + + public String getUpdatedAt() { + return this.updatedAt; + } + + public void setUpdatedAt(String updatedAt) { + this.updatedAt = updatedAt; + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/github/koooe/ganke/ui/BaseFragment.java b/app/src/main/java/com/github/koooe/ganke/ui/BaseFragment.java index e5a02a7..b5a98b0 100644 --- a/app/src/main/java/com/github/koooe/ganke/ui/BaseFragment.java +++ b/app/src/main/java/com/github/koooe/ganke/ui/BaseFragment.java @@ -6,22 +6,39 @@ import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.widget.Toast; +import com.android.volley.Response; +import com.android.volley.VolleyError; import com.github.koooe.ganke.R; +import com.github.koooe.ganke.api.Api; +import com.github.koooe.ganke.bean.BaseResponse; +import com.github.koooe.ganke.bean.DayData; +import com.github.koooe.ganke.util.DebugLog; +import com.google.gson.Gson; import com.markmao.pulltorefresh.widget.XListView; +import java.util.ArrayList; +import java.util.List; + import butterknife.Bind; import butterknife.ButterKnife; +import ganke.adapter.BaseAdapterHelper; +import ganke.adapter.QuickAdapter; - -public class BaseFragment extends Fragment { +public class BaseFragment extends Fragment implements XListView.IXListViewListener { private static final String ARG_CATEGORY = "category"; - - private String category; - + public QuickAdapter adapter; + int currentPage; @Bind(R.id.list_view) XListView mListView; + private String category; + private List dayDatas = new ArrayList<>(); + + public BaseFragment() { + // Required empty public constructor + } public static BaseFragment newInstance(String category) { BaseFragment fragment = new BaseFragment(); @@ -31,10 +48,6 @@ public static BaseFragment newInstance(String category) { return fragment; } - public BaseFragment() { - // Required empty public constructor - } - @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -56,20 +69,67 @@ public void onViewCreated(View view, Bundle savedInstanceState) { mListView.setPullLoadEnable(true); mListView.setPullRefreshEnable(true); mListView.setAutoLoadEnable(true); - mListView.setXListViewListener(new XListView.IXListViewListener() { + mListView.setXListViewListener(this); + mListView.autoRefresh(); + adapter = new QuickAdapter(getActivity(), R.layout.listitem_base, dayDatas) { @Override - public void onRefresh() { - + protected void convert(BaseAdapterHelper helper, DayData item, int position) { + String meta = "Via" + item.getWho() + " @ " + item.getPublishedAt(); + helper.setText(R.id.tv_desc, item.getDesc()); + helper.setText(R.id.tv_meta, meta); } + }; + mListView.setAdapter(adapter); - @Override - public void onLoadMore() { + } - } - }); - mListView.autoRefresh(); - } + @Override + public void onRefresh() { + currentPage = 1; + Api.getData(category, currentPage, + new Response.Listener() { + @Override + public void onResponse(String response) { + Gson gson = new Gson(); + BaseResponse baseResponse = gson.fromJson(response, BaseResponse.class); + if (!baseResponse.isError()) { + adapter.replaceAll(baseResponse.getResults()); + } + + mListView.stopRefresh(); + } + + }, new Response.ErrorListener() { + @Override + public void onErrorResponse(VolleyError error) { + DebugLog.e(error.toString()); + Toast.makeText(getActivity(), error.getMessage(), Toast.LENGTH_SHORT).show(); + } + }); + } + @Override + public void onLoadMore() { + Api.getData(category, ++currentPage, + new Response.Listener() { + @Override + public void onResponse(String response) { + Gson gson = new Gson(); + BaseResponse baseResponse = gson.fromJson(response, BaseResponse.class); + if (!baseResponse.isError()) { + adapter.addAll(baseResponse.getResults()); + } + + mListView.stopLoadMore(); + } + + }, new Response.ErrorListener() { + @Override + public void onErrorResponse(VolleyError error) { + Toast.makeText(getActivity(), error.getLocalizedMessage(), Toast.LENGTH_SHORT).show(); + } + }); + } } diff --git a/app/src/main/java/com/github/koooe/ganke/ui/MainActivity.java b/app/src/main/java/com/github/koooe/ganke/ui/MainActivity.java index fdf7e3a..a5e1a18 100644 --- a/app/src/main/java/com/github/koooe/ganke/ui/MainActivity.java +++ b/app/src/main/java/com/github/koooe/ganke/ui/MainActivity.java @@ -4,7 +4,7 @@ import android.support.design.widget.TabLayout; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentManager; -import android.support.v4.app.FragmentPagerAdapter; +import android.support.v4.app.FragmentStatePagerAdapter; import android.support.v4.view.ViewPager; import com.github.koooe.ganke.R; @@ -19,7 +19,7 @@ public class MainActivity extends ToolbarActivity { TabLayout tabLayout; @Bind(R.id.viewPager) - private ViewPager viewPager; + ViewPager viewPager; FragmentManager fm; private MainFragmentPagerAdapter mainAdapter; @@ -41,7 +41,7 @@ private void init() { fm = getSupportFragmentManager(); for (int i = 0; i < Api.categories.length; i++) { - tabLayout.addTab(tabLayout.newTab().setText(Api.categories[i] + i)); + tabLayout.addTab(tabLayout.newTab().setText(Api.categories[i])); } mainAdapter = new MainFragmentPagerAdapter(fm, Api.categories.length); @@ -52,7 +52,7 @@ private void init() { } - static class MainFragmentPagerAdapter extends FragmentPagerAdapter { + static class MainFragmentPagerAdapter extends FragmentStatePagerAdapter { int size; diff --git a/app/src/main/java/com/github/koooe/ganke/util/DebugLog.java b/app/src/main/java/com/github/koooe/ganke/util/DebugLog.java new file mode 100644 index 0000000..e20334d --- /dev/null +++ b/app/src/main/java/com/github/koooe/ganke/util/DebugLog.java @@ -0,0 +1,109 @@ + +/*** +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +For more information, please refer to +*/ + +package com.github.koooe.ganke.util; + +import android.util.Log; + +import com.github.koooe.ganke.BuildConfig; + + +/** + * @date 21.06.2012 + * @author Mustafa Ferhan Akman + * + * Create a simple and more understandable Android logs. + * */ + +public class DebugLog{ + + static String className; + static String methodName; + static int lineNumber; + + private DebugLog(){ + /* Protect from instantiations */ + } + + public static boolean isDebuggable() { + return BuildConfig.DEBUG; + } + + private static String createLog( String log ) { + + StringBuffer buffer = new StringBuffer(); + buffer.append("["); + buffer.append(methodName); + buffer.append(":"); + buffer.append(lineNumber); + buffer.append("]"); + buffer.append(log); + + return buffer.toString(); + } + + private static void getMethodNames(StackTraceElement[] sElements){ + className = sElements[1].getFileName(); + methodName = sElements[1].getMethodName(); + lineNumber = sElements[1].getLineNumber(); + } + + public static void e(String message){ + if (!isDebuggable()) + return; + + // Throwable instance must be created before any methods + getMethodNames(new Throwable().getStackTrace()); + Log.e(className, createLog(message)); + } + + public static void i(String message){ + if (!isDebuggable()) + return; + + getMethodNames(new Throwable().getStackTrace()); + Log.i(className, createLog(message)); + } + + public static void d(String message){ + if (!isDebuggable()) + return; + + getMethodNames(new Throwable().getStackTrace()); + Log.d(className, createLog(message)); + } + + public static void v(String message){ + if (!isDebuggable()) + return; + + getMethodNames(new Throwable().getStackTrace()); + Log.v(className, createLog(message)); + } + + public static void w(String message){ + if (!isDebuggable()) + return; + + getMethodNames(new Throwable().getStackTrace()); + Log.w(className, createLog(message)); + } + + public static void wtf(String message){ + if (!isDebuggable()) + return; + + getMethodNames(new Throwable().getStackTrace()); + Log.wtf(className, createLog(message)); + } + +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml index 7641cc5..615f717 100644 --- a/app/src/main/res/layout/activity_main.xml +++ b/app/src/main/res/layout/activity_main.xml @@ -15,9 +15,12 @@ android:background="@color/primary" android:layout_height="48dp" /> - + android:layout_height="match_parent" + + /> + diff --git a/app/src/main/res/layout/listitem_base.xml b/app/src/main/res/layout/listitem_base.xml new file mode 100644 index 0000000..f4399ad --- /dev/null +++ b/app/src/main/res/layout/listitem_base.xml @@ -0,0 +1,19 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/view_toolbar.xml b/app/src/main/res/layout/view_toolbar.xml index 0e4ae82..1a82420 100644 --- a/app/src/main/res/layout/view_toolbar.xml +++ b/app/src/main/res/layout/view_toolbar.xml @@ -10,7 +10,7 @@ @@ -20,6 +20,7 @@ android:layout_width="wrap_content" android:layout_height="match_parent" android:layout_gravity="center" + android:gravity="center" android:textSize="20sp" android:textColor="@color/black" android:textStyle="bold" diff --git a/settings.gradle b/settings.gradle index e7b4def..9dde99a 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -include ':app' +include ':app', ':CommonAdapter'