").append(fa.parseHTML(a)).find(e):a)}).complete(d&&function(a,b){h.each(d,g||[a.responseText,b,a])}),this},fa.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(a,b){fa.fn[b]=function(a){return this.on(b,a)}}),fa.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:gb,type:"GET",isLocal:mb.test(fb[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":tb,text:"text/plain",html:"text/html",xml:"application/xml, text/xml",json:"application/json, text/javascript"},contents:{xml:/xml/,html:/html/,json:/json/},responseFields:{xml:"responseXML",text:"responseText",json:"responseJSON"},converters:{"* text":String,"text html":!0,"text json":fa.parseJSON,"text xml":fa.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(a,b){return b?E(E(a,fa.ajaxSettings),b):E(fa.ajaxSettings,a)},ajaxPrefilter:C(rb),ajaxTransport:C(sb),ajax:function(a,c){function d(a,c,d,h){var j,l,s,t,v,x=c;2!==u&&(u=2,i&&clearTimeout(i),e=b,g=h||"",w.readyState=a>0?4:0,j=a>=200&&300>a||304===a,d&&(t=F(m,w,d)),t=G(m,t,w,j),j?(m.ifModified&&(v=w.getResponseHeader("Last-Modified"),v&&(fa.lastModified[f]=v),v=w.getResponseHeader("etag"),v&&(fa.etag[f]=v)),204===a||"HEAD"===m.type?x="nocontent":304===a?x="notmodified":(x=t.state,l=t.data,s=t.error,j=!s)):(s=x,(a||!x)&&(x="error",0>a&&(a=0))),w.status=a,w.statusText=(c||x)+"",j?p.resolveWith(n,[l,x,w]):p.rejectWith(n,[w,x,s]),w.statusCode(r),r=b,k&&o.trigger(j?"ajaxSuccess":"ajaxError",[w,m,j?l:s]),q.fireWith(n,[w,x]),k&&(o.trigger("ajaxComplete",[w,m]),--fa.active||fa.event.trigger("ajaxStop")))}"object"==typeof a&&(c=a,a=b),c=c||{};var e,f,g,h,i,j,k,l,m=fa.ajaxSetup({},c),n=m.context||m,o=m.context&&(n.nodeType||n.jquery)?fa(n):fa.event,p=fa.Deferred(),q=fa.Callbacks("once memory"),r=m.statusCode||{},s={},t={},u=0,v="canceled",w={readyState:0,getResponseHeader:function(a){var b;if(2===u){if(!h)for(h={};b=lb.exec(g);)h[b[1].toLowerCase()]=b[2];b=h[a.toLowerCase()]}return null==b?null:b},getAllResponseHeaders:function(){return 2===u?g:null},setRequestHeader:function(a,b){var c=a.toLowerCase();return u||(a=t[c]=t[c]||a,s[a]=b),this},overrideMimeType:function(a){return u||(m.mimeType=a),this},statusCode:function(a){var b;if(a)if(2>u)for(b in a)r[b]=[r[b],a[b]];else w.always(a[w.status]);return this},abort:function(a){var b=a||v;return e&&e.abort(b),d(0,b),this}};if(p.promise(w).complete=q.add,w.success=w.done,w.error=w.fail,m.url=((a||m.url||gb)+"").replace(jb,"").replace(ob,fb[1]+"//"),m.type=c.method||c.type||m.method||m.type,m.dataTypes=fa.trim(m.dataType||"*").toLowerCase().match(ha)||[""],null==m.crossDomain&&(j=pb.exec(m.url.toLowerCase()),m.crossDomain=!(!j||j[1]===fb[1]&&j[2]===fb[2]&&(j[3]||("http:"===j[1]?"80":"443"))===(fb[3]||("http:"===fb[1]?"80":"443")))),m.data&&m.processData&&"string"!=typeof m.data&&(m.data=fa.param(m.data,m.traditional)),D(rb,m,c,w),2===u)return w;k=m.global,k&&0===fa.active++&&fa.event.trigger("ajaxStart"),m.type=m.type.toUpperCase(),m.hasContent=!nb.test(m.type),f=m.url,m.hasContent||(m.data&&(f=m.url+=(ib.test(f)?"&":"?")+m.data,delete m.data),m.cache===!1&&(m.url=kb.test(f)?f.replace(kb,"$1_="+hb++):f+(ib.test(f)?"&":"?")+"_="+hb++)),m.ifModified&&(fa.lastModified[f]&&w.setRequestHeader("If-Modified-Since",fa.lastModified[f]),fa.etag[f]&&w.setRequestHeader("If-None-Match",fa.etag[f])),(m.data&&m.hasContent&&m.contentType!==!1||c.contentType)&&w.setRequestHeader("Content-Type",m.contentType),w.setRequestHeader("Accept",m.dataTypes[0]&&m.accepts[m.dataTypes[0]]?m.accepts[m.dataTypes[0]]+("*"!==m.dataTypes[0]?", "+tb+"; q=0.01":""):m.accepts["*"]);for(l in m.headers)w.setRequestHeader(l,m.headers[l]);if(m.beforeSend&&(m.beforeSend.call(n,w,m)===!1||2===u))return w.abort();v="abort";for(l in{success:1,error:1,complete:1})w[l](m[l]);if(e=D(sb,m,c,w)){w.readyState=1,k&&o.trigger("ajaxSend",[w,m]),m.async&&m.timeout>0&&(i=setTimeout(function(){w.abort("timeout")},m.timeout));try{u=1,e.send(s,d)}catch(x){if(!(2>u))throw x;d(-1,x)}}else d(-1,"No Transport");return w},getJSON:function(a,b,c){return fa.get(a,b,c,"json")},getScript:function(a,c){return fa.get(a,b,c,"script")}}),fa.each(["get","post"],function(a,c){fa[c]=function(a,d,e,f){return fa.isFunction(d)&&(f=f||e,e=d,d=b),fa.ajax({url:a,type:c,dataType:f,data:d,success:e})}}),fa.ajaxSetup({accepts:{script:"text/javascript, application/javascript, application/ecmascript, application/x-ecmascript"},contents:{script:/(?:java|ecma)script/},converters:{"text script":function(a){return fa.globalEval(a),a}}}),fa.ajaxPrefilter("script",function(a){a.cache===b&&(a.cache=!1),a.crossDomain&&(a.type="GET")}),fa.ajaxTransport("script",function(a){if(a.crossDomain){var b,c;return{send:function(d,e){b=fa("\n"
+ ""
+ "\n"
+ "\n\n
\n"
+ body
+ "\n
\n");
getBinding().wv.loadDataWithBaseURL("x-data://base", result, "text/html", "utf-8", null);
}
}
================================================
FILE: guokr/src/main/java/me/shouheng/guokr/view/fragment/NewsListFragment.java
================================================
package me.shouheng.guokr.view.fragment;
import android.app.Activity;
import androidx.lifecycle.ViewModelProviders;
import android.os.Bundle;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.alibaba.android.arouter.facade.annotation.Route;
import me.shouheng.commons.config.BaseConstants;
import me.shouheng.commons.tools.ToastUtils;
import me.shouheng.commons.view.fragment.CommonFragment;
import me.shouheng.commons.view.widget.DividerItemDecoration;
import me.shouheng.guokr.R;
import me.shouheng.guokr.databinding.FragmentNewsListBinding;
import me.shouheng.guokr.model.data.GuokrNews;
import me.shouheng.guokr.view.adapter.GuokrNewsAdapter;
import me.shouheng.guokr.viewmodel.GuokrViewModel;
/**
* @author shouh
* @version $Id: NewsListFragment, v 0.1 2018/6/10 12:08 shouh Exp$
*/
@Route(path = BaseConstants.GUOKR_NEWS_LIST)
public class NewsListFragment extends CommonFragment
{
private GuokrViewModel guokrViewModel;
private GuokrNewsAdapter adapter;
@Override
protected int getLayoutResId() {
return R.layout.fragment_news_list;
}
@Override
protected void doCreateView(Bundle savedInstanceState) {
Activity activity = getActivity();
if (!(activity instanceof FragmentInteraction)) {
throw new IllegalArgumentException("The associated activity must implement FragmentInteraction");
}
guokrViewModel = ViewModelProviders.of(this).get(GuokrViewModel.class);
configViews();
registerObservers();
guokrViewModel.fetchFirstPage();
}
@Override
public void onResume() {
super.onResume();
Activity activity = getActivity();
if (activity != null) {
ActionBar actionBar = ((AppCompatActivity) activity).getSupportActionBar();
if (actionBar != null) {
actionBar.setTitle(R.string.menu_item_title_2);
actionBar.setSubtitle(R.string.menu_item_desc_2);
}
}
}
private void configViews() {
adapter = new GuokrNewsAdapter(getContext());
adapter.setOnItemClickListener(((adapter1, view, position) -> {
GuokrNews.Result result = adapter.getData().get(position);
Activity activity = getActivity();
if (activity != null) ((FragmentInteraction) activity).onArticleClicked(result);
}));
adapter.setEnableLoadMore(true);
adapter.setOnLoadMoreListener(() -> guokrViewModel.fetchNextPage(), getBinding().rv);
getBinding().rv.setAdapter(adapter);
getBinding().rv.addItemDecoration(new DividerItemDecoration(getContext(),
DividerItemDecoration.VERTICAL_LIST, false));
getBinding().rv.setLayoutManager(new LinearLayoutManager(getContext()));
}
private void registerObservers() {
guokrViewModel.getGuokrNewsLiveData().observe(this, resources -> {
if (resources == null) return;
switch (resources.status) {
case FAILED:
ToastUtils.makeToast(resources.message);
break;
case SUCCESS:
adapter.addData(resources.data.getResult());
adapter.notifyDataSetChanged();
break;
}
});
}
public interface FragmentInteraction {
void onArticleClicked(GuokrNews.Result result);
}
}
================================================
FILE: guokr/src/main/java/me/shouheng/guokr/viewmodel/GuokrViewModel.java
================================================
package me.shouheng.guokr.viewmodel;
import androidx.lifecycle.LiveData;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;
import me.shouheng.commons.model.Resource;
import me.shouheng.guokr.model.data.GuokrNews;
import me.shouheng.guokr.model.data.GuokrNewsContent;
import me.shouheng.guokr.model.repository.GuokrRetrofit;
/**
* @author shouh
* @version $Id: GuokrViewModel, v 0.1 2018/6/10 11:10 shouh Exp$
*/
public class GuokrViewModel extends ViewModel {
private int offset = 0;
private final int limit = 20;
private MutableLiveData> guokrNewsLiveData;
private MutableLiveData> guokrNewsContentLiveData;
public LiveData> getGuokrNewsLiveData() {
if (guokrNewsLiveData == null) {
guokrNewsLiveData = new MutableLiveData<>();
}
return guokrNewsLiveData;
}
public LiveData> getGuokrNewsContentLiveData() {
if (guokrNewsContentLiveData == null) {
guokrNewsContentLiveData = new MutableLiveData<>();
}
return guokrNewsContentLiveData;
}
public void fetchFirstPage() {
fetchGuokrNews(offset, limit);
}
public void fetchNextPage() {
offset += limit;
fetchGuokrNews(offset, limit);
}
private void fetchGuokrNews(int offset, int limit) {
offset += limit;
GuokrRetrofit.getGuokrService().getNews(offset, limit)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer() {
@Override
public void onError(Throwable e) {
guokrNewsLiveData.setValue(Resource.error(e.getMessage(), null));
}
@Override
public void onComplete() { }
@Override
public void onSubscribe(Disposable d) { }
@Override
public void onNext(GuokrNews guokrNews) {
guokrNewsLiveData.setValue(Resource.success(guokrNews));
}
});
}
public void fetchGuokrNewsContent(int id) {
GuokrRetrofit.getGuokrService().getGuokrContent(id)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Observer() {
@Override
public void onError(Throwable e) {
guokrNewsContentLiveData.setValue(Resource.error(e.getMessage(), null));
}
@Override
public void onComplete() { }
@Override
public void onSubscribe(Disposable d) { }
@Override
public void onNext(GuokrNewsContent guokrNewsContent) {
guokrNewsContentLiveData.setValue(Resource.success(guokrNewsContent));
}
});
}
}
================================================
FILE: guokr/src/main/res/drawable/ic_launcher_background.xml
================================================
================================================
FILE: guokr/src/main/res/drawable-v24/ic_launcher_foreground.xml
================================================
================================================
FILE: guokr/src/main/res/layout/activity_guokr_bews.xml
================================================
================================================
FILE: guokr/src/main/res/layout/fragment_news_detail.xml
================================================
================================================
FILE: guokr/src/main/res/layout/fragment_news_list.xml
================================================
================================================
FILE: guokr/src/main/res/layout/item_guokr_news.xml
================================================
================================================
FILE: guokr/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
================================================
================================================
FILE: guokr/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
================================================
================================================
FILE: guokr/src/main/res/values/strings.xml
================================================
Guokr
================================================
FILE: guokr/src/main/res/values/styles.xml
================================================
================================================
FILE: guokr/src/test/java/me/shouheng/guokr/ExampleUnitTest.java
================================================
package me.shouheng.guokr;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see Testing documentation
*/
public class ExampleUnitTest {
@Test
public void addition_isCorrect() {
assertEquals(4, 2 + 2);
}
}
================================================
FILE: knife-annotation/.gitignore
================================================
/build
================================================
FILE: knife-annotation/build.gradle
================================================
apply plugin: 'java-library'
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
}
sourceCompatibility = "1.8"
targetCompatibility = "1.8"
================================================
FILE: knife-annotation/src/main/java/me/shouheng/knife/annotation/BindView.java
================================================
package me.shouheng.knife.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 用来将View与指定的id进行绑定
*
* @author shouh
* @version $Id: BindView, v 0.1 2018/8/22 22:22 shouh Exp$
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.CLASS)
public @interface BindView {
/**
* 与该View进行绑定的id
*
* @return id
*/
int id();
}
================================================
FILE: knife-annotation/src/main/java/me/shouheng/knife/annotation/OnClick.java
================================================
package me.shouheng.knife.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 将单击事件与指定的多个id绑定到一起
*
* @author shouh
* @version $Id: OnClick, v 0.1 2018/8/22 22:20 shouh Exp$
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.CLASS)
public @interface OnClick {
/**
* 与该单击事件进行绑定的多个 id
*
* @return 用于绑定的多个 id
*/
int[] ids();
}
================================================
FILE: knife-api/.gitignore
================================================
/build
================================================
FILE: knife-api/build.gradle
================================================
apply plugin: 'com.android.library'
android {
compileSdkVersion 27
defaultConfig {
minSdkVersion 17
targetSdkVersion 27
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.1.0'
}
================================================
FILE: knife-api/src/main/AndroidManifest.xml
================================================
================================================
FILE: knife-api/src/main/java/me/shouheng/knife/api/Injector.java
================================================
package me.shouheng.knife.api;
import me.shouheng.knife.api.finder.Finder;
/**
* @author shouh
* @version $Id: Injector, v 0.1 2018/8/22 22:41 shouh Exp$
*/
public interface Injector {
void inject(T host, Object source, Finder finder);
}
================================================
FILE: knife-api/src/main/java/me/shouheng/knife/api/MyKnife.java
================================================
package me.shouheng.knife.api;
import android.app.Activity;
import android.view.View;
import java.util.HashMap;
import java.util.Map;
import me.shouheng.knife.api.finder.ActivityFinder;
import me.shouheng.knife.api.finder.Finder;
import me.shouheng.knife.api.finder.ViewFinder;
/**
* @author shouh
* @version $Id: MyKnife, v 0.1 2018/8/22 22:50 shouh Exp$
*/
public class MyKnife {
public MyKnife() {
throw new AssertionError("Not available for instance");
}
private final static ActivityFinder ACTIVITY_FINDER = new ActivityFinder();
private final static ViewFinder VIEW_FINDER = new ViewFinder();
private final static Map FINDER_MAPPER = new HashMap<>();
public static void bind(Activity activity) {
bind(activity, activity, ACTIVITY_FINDER);
}
public static void bind(View view) {
bind(view, view);
}
public static void bind(Object host, View view) {
bind(host, view, VIEW_FINDER);
}
public static void bind(Object host, Object source, Finder finder) {
String className = host.getClass().getName();
try {
Injector injector = FINDER_MAPPER.get(className);
if (injector == null) {
Class> finderClass = Class.forName(className + "$$Injector");
injector = (Injector) finderClass.newInstance();
FINDER_MAPPER.put(className, injector);
}
injector.inject(host, source, finder);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
}
================================================
FILE: knife-api/src/main/java/me/shouheng/knife/api/Unbinder.java
================================================
package me.shouheng.knife.api;
/**
* @author shouh
* @version $Id: Unbinder, v 0.1 2018/8/22 22:42 shouh Exp$
*/
public interface Unbinder {
void unbind();
Unbinder EMPTY = new Unbinder() {
@Override
public void unbind() {
}
};
}
================================================
FILE: knife-api/src/main/java/me/shouheng/knife/api/finder/ActivityFinder.java
================================================
package me.shouheng.knife.api.finder;
import android.app.Activity;
import android.content.Context;
import android.view.View;
/**
* @author shouh
* @version $Id: ActivityFinder, v 0.1 2018/8/22 22:34 shouh Exp$
*/
public class ActivityFinder implements Finder {
@Override
public Context getContext(Object source) {
return (Activity) source;
}
@Override
public View findView(Object source, int id) {
return ((Activity) source).findViewById(id);
}
}
================================================
FILE: knife-api/src/main/java/me/shouheng/knife/api/finder/Finder.java
================================================
package me.shouheng.knife.api.finder;
import android.content.Context;
import android.view.View;
/**
* @author shouh
* @version $Id: Finder, v 0.1 2018/8/22 22:27 shouh Exp$
*/
public interface Finder {
Context getContext(Object source);
View findView(Object source, int id);
}
================================================
FILE: knife-api/src/main/java/me/shouheng/knife/api/finder/ViewFinder.java
================================================
package me.shouheng.knife.api.finder;
import android.content.Context;
import android.view.View;
/**
* @author shouh
* @version $Id: ViewFinder, v 0.1 2018/8/22 22:45 shouh Exp$
*/
public class ViewFinder implements Finder {
@Override
public Context getContext(Object source) {
return ((View) source).getContext();
}
@Override
public View findView(Object source, int id) {
return ((View) source).findViewById(id);
}
}
================================================
FILE: knife-api/src/main/res/values/strings.xml
================================================
Knife api
================================================
FILE: knife-compiler/.gitignore
================================================
/build
================================================
FILE: knife-compiler/build.gradle
================================================
apply plugin: 'java-library'
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
compile 'com.squareup:javapoet:1.8.0'
compile 'com.google.auto.service:auto-service:1.0-rc2'
compile project(':knife-annotation')
}
sourceCompatibility = "1.8"
targetCompatibility = "1.8"
================================================
FILE: knife-compiler/src/main/java/me/shouheng/knife/compiler/BindViewProcessor.java
================================================
package me.shouheng.knife.compiler;
import com.google.auto.service.AutoService;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.Filer;
import javax.annotation.processing.Messager;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;
import javax.tools.Diagnostic;
import me.shouheng.knife.annotation.BindView;
import me.shouheng.knife.annotation.OnClick;
import me.shouheng.knife.compiler.model.AnnotatedClass;
import me.shouheng.knife.compiler.model.BindViewField;
import me.shouheng.knife.compiler.model.OnClickMethod;
/**
* @author shouh
* @version $Id: BindViewProcessor, v 0.1 2018/8/23 22:22 shouh Exp$
*/
@AutoService(Processor.class)
//@SupportedAnnotationTypes(value = {})
////@SupportedSourceVersion(value = SourceVersion.RELEASE_8)
public class BindViewProcessor extends AbstractProcessor {
private Filer filer;
private Elements elements;
private Messager messager;
private Map map = new HashMap<>();
@Override
public synchronized void init(ProcessingEnvironment processingEnvironment) {
super.init(processingEnvironment);
elements = processingEnvironment.getElementUtils();
messager = processingEnvironment.getMessager();
filer = processingEnvironment.getFiler();
}
@Override
public Set getSupportedAnnotationTypes() {
Set types = new LinkedHashSet<>();
types.add(BindView.class.getCanonicalName());
types.add(OnClick.class.getCanonicalName());
return types;
}
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}
@Override
public boolean process(Set extends TypeElement> set, RoundEnvironment roundEnvironment) {
map.clear();
try {
processBindView(roundEnvironment);
processOnClick(roundEnvironment);
} catch (IllegalArgumentException e) {
error(e.getMessage());
return true;
}
try {
for (AnnotatedClass annotatedClass : map.values()) {
info("generating file for %s", annotatedClass.getFullClassName());
annotatedClass.generateFinder().writeTo(filer);
}
} catch (Exception e) {
e.printStackTrace();
error("Generate file failed,reason:%s", e.getMessage());
}
return true;
}
private void processBindView(RoundEnvironment roundEnv) {
for (Element element : roundEnv.getElementsAnnotatedWith(BindView.class)) {
AnnotatedClass annotatedClass = getAnnotatedClass(element);
BindViewField field = new BindViewField(element);
annotatedClass.addField(field);
System.out.print("p_element=" + element.getSimpleName() + ",p_set=" + element.getModifiers());
}
}
private AnnotatedClass getAnnotatedClass(Element element) {
TypeElement encloseElement = (TypeElement) element.getEnclosingElement();
String fullClassName = encloseElement.getQualifiedName().toString();
AnnotatedClass annotatedClass = map.get(fullClassName);
if (annotatedClass == null) {
annotatedClass = new AnnotatedClass(encloseElement, elements);
map.put(fullClassName, annotatedClass);
}
return annotatedClass;
}
private void processOnClick(RoundEnvironment roundEnv) {
for (Element element : roundEnv.getElementsAnnotatedWith(OnClick.class)) {
AnnotatedClass annotatedClass = getAnnotatedClass(element);
OnClickMethod method = new OnClickMethod(element);
annotatedClass.addMethod(method);
}
}
private void error(String msg, Object... args) {
messager.printMessage(Diagnostic.Kind.ERROR, String.format(msg, args));
}
private void info(String msg, Object... args) {
messager.printMessage(Diagnostic.Kind.NOTE, String.format(msg, args));
}
}
================================================
FILE: knife-compiler/src/main/java/me/shouheng/knife/compiler/TypeUtils.java
================================================
package me.shouheng.knife.compiler;
import com.squareup.javapoet.ClassName;
/**
* @author shouh
* @version $Id: TypeUtils, v 0.1 2018/8/22 22:54 shouh Exp$
*/
public class TypeUtils {
public final static ClassName FINDER = ClassName.get("me.shouheng.knife.api.finder", "Finder");
public final static ClassName ONCLICK_LISTENER = ClassName.get("android.view", "View", "OnClickListener");
public final static ClassName ANDROID_VIEW = ClassName.get("android.view", "View");
public static final ClassName INJECTOR = ClassName.get("me.shouheng.knife.api", "Injector");
}
================================================
FILE: knife-compiler/src/main/java/me/shouheng/knife/compiler/model/AnnotatedClass.java
================================================
package me.shouheng.knife.compiler.model;
import com.squareup.javapoet.ClassName;
import com.squareup.javapoet.JavaFile;
import com.squareup.javapoet.MethodSpec;
import com.squareup.javapoet.ParameterizedTypeName;
import com.squareup.javapoet.TypeName;
import com.squareup.javapoet.TypeSpec;
import java.util.LinkedList;
import java.util.List;
import javax.lang.model.element.Modifier;
import javax.lang.model.element.TypeElement;
import javax.lang.model.util.Elements;
import me.shouheng.knife.compiler.TypeUtils;
/**
* @author shouh
* @version $Id: AnnotatedClass, v 0.1 2018/8/22 22:55 shouh Exp$
*/
public class AnnotatedClass {
private TypeElement typeElement;
private List bindViewFields;
private List onClickMethods;
private Elements elements;
public AnnotatedClass(TypeElement typeElement, Elements elements) {
this.typeElement = typeElement;
this.bindViewFields = new LinkedList<>();
this.onClickMethods = new LinkedList<>();
this.elements = elements;
}
public String getFullClassName() {
return typeElement.getQualifiedName().toString();
}
public void addField(BindViewField bindViewField) {
bindViewFields.add(bindViewField);
}
public void addMethod(OnClickMethod method) {
onClickMethods.add(method);
}
public JavaFile generateFinder() {
MethodSpec.Builder builder = MethodSpec.methodBuilder("inject")
.addModifiers(Modifier.PUBLIC)
.addAnnotation(Override.class)
.addParameter(TypeName.get(typeElement.asType()), "host", Modifier.FINAL)
.addParameter(TypeName.OBJECT, "source")
.addParameter(TypeUtils.FINDER, "finder");
for (BindViewField field : bindViewFields) {
builder.addStatement("host.$N=($T)finder.findView(source, $L)",
field.getFieldName(),
ClassName.get(field.getFieldType()),
field.getViewId());
}
if (onClickMethods.size() > 0) {
builder.addStatement("$T listener", TypeUtils.ONCLICK_LISTENER);
}
for (OnClickMethod method : onClickMethods) {
TypeSpec listener = TypeSpec.anonymousClassBuilder("")
.addSuperinterface(TypeUtils.ONCLICK_LISTENER)
.addMethod(MethodSpec.methodBuilder("onClick")
.addAnnotation(Override.class)
.addModifiers(Modifier.PUBLIC)
.returns(TypeName.VOID)
.addParameter(TypeUtils.ANDROID_VIEW, "view")
.addStatement("host.$N()", method.getMethodName())
.build())
.build();
builder.addStatement("listener = $L", listener);
for (int id : method.getIds()) {
builder.addStatement("finder.findView(source, $L).setOnClickListener(listener)", id);
}
}
String packageName = getPackageName(typeElement);
String className = getClassName(typeElement, packageName);
ClassName bindClassName = ClassName.get(packageName, className);
TypeSpec finderClass = TypeSpec.classBuilder(bindClassName.simpleName() + "$$Injector")
.addModifiers(Modifier.PUBLIC)
.addSuperinterface(ParameterizedTypeName.get(TypeUtils.INJECTOR, TypeName.get(typeElement.asType())))
.addMethod(builder.build())
.build();
return JavaFile.builder(packageName, finderClass).build();
}
private String getPackageName(TypeElement type) {
return elements.getPackageOf(type).getQualifiedName().toString();
}
private String getClassName(TypeElement type, String packageName) {
int packageLen = packageName.length() + 1;
return type.getQualifiedName().toString().substring(packageLen).replace('.', '$');
}
}
================================================
FILE: knife-compiler/src/main/java/me/shouheng/knife/compiler/model/BindViewField.java
================================================
package me.shouheng.knife.compiler.model;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.Name;
import javax.lang.model.element.VariableElement;
import javax.lang.model.type.TypeMirror;
import me.shouheng.knife.annotation.BindView;
/**
* @author shouh
* @version $Id: BindViewField, v 0.1 2018/8/22 22:56 shouh Exp$
*/
public class BindViewField {
private VariableElement variableElement;
private int viewId;
/**
* 使用 Element 初始化当前类
*
* @param element element
*/
public BindViewField(Element element) {
if (element.getKind() != ElementKind.FIELD) {
throw new IllegalArgumentException("Only field can be annotated with %s" + BindView.class.getSimpleName());
}
variableElement = (VariableElement) element;
BindView bindView = variableElement.getAnnotation(BindView.class);
viewId = bindView.id();
if (viewId < 0) {
throw new IllegalArgumentException("The id must > 0");
}
}
public Name getFieldName() {
return variableElement.getSimpleName();
}
public int getViewId() {
return viewId;
}
public TypeMirror getFieldType() {
return variableElement.asType();
}
}
================================================
FILE: knife-compiler/src/main/java/me/shouheng/knife/compiler/model/OnClickMethod.java
================================================
package me.shouheng.knife.compiler.model;
import java.util.List;
import javax.lang.model.element.Element;
import javax.lang.model.element.ElementKind;
import javax.lang.model.element.ExecutableElement;
import javax.lang.model.element.Name;
import javax.lang.model.element.VariableElement;
import me.shouheng.knife.annotation.OnClick;
/**
* @author shouh
* @version $Id: OnClickMethod, v 0.1 2018/8/22 22:56 shouh Exp$
*/
public class OnClickMethod {
private Name methodName;
private int[] ids;
public OnClickMethod(Element element) {
if (element.getKind() != ElementKind.METHOD) {
throw new IllegalArgumentException(String.format("Only method can be annotated with %s", OnClick.class.getSimpleName()));
}
ExecutableElement executableElement = (ExecutableElement) element;
methodName = executableElement.getSimpleName();
OnClick onClick = executableElement.getAnnotation(OnClick.class);
ids = onClick.ids();
for (int id : ids) {
if (id < 0) {
throw new IllegalArgumentException(String.format("Must set valid ids for @%s", OnClick.class.getSimpleName()));
}
}
List extends VariableElement> params = executableElement.getParameters();
if (params.size() > 0) {
throw new IllegalArgumentException(String.format("The method annotated with @%s must have no parameters", OnClick.class.getSimpleName()));
}
}
public Name getMethodName() {
return methodName;
}
public int[] getIds() {
return ids;
}
}
================================================
FILE: layout/.gitignore
================================================
/build
================================================
FILE: layout/build.gradle
================================================
println isLayoutModuleApp.toBoolean()
if (isLayoutModuleApp.toBoolean()) {
apply plugin: 'com.android.application'
} else {
apply plugin: 'com.android.library'
}
android {
compileSdkVersion rootProject.ext.compileSdkVersion
defaultConfig {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
versionName "1.0"
multiDexEnabled true
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
javaCompileOptions {
annotationProcessorOptions {
arguments = [moduleName: project.getName()]
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
// use data binding
dataBinding {
enabled = true
}
// use java 8 language
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
// use external libs folder
sourceSets {
main {
jniLibs.srcDirs = ['libs']
if (isLayoutModuleApp.toBoolean()) {
manifest.srcFile "src/main/debug/AndroidManifest.xml"
} else {
manifest.srcFile "src/main/AndroidManifest.xml"
}
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:runner:1.1.0'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0'
// swipe back layout
implementation 'me.imid.swipebacklayout.lib:library:1.1.0'
// router
annotationProcessor 'com.alibaba:arouter-compiler:1.1.4'
// projects
implementation project(':commons')
}
================================================
FILE: layout/proguard-rules.pro
================================================
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html
# 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 *;
#}
# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable
# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
================================================
FILE: layout/src/androidTest/java/me/shouheng/layout/ExampleInstrumentedTest.java
================================================
package me.shouheng.layout;
import android.content.Context;
import androidx.test.InstrumentationRegistry;
import androidx.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see Testing documentation
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getTargetContext();
assertEquals("me.shouheng.layout", appContext.getPackageName());
}
}
================================================
FILE: layout/src/main/AndroidManifest.xml
================================================
================================================
FILE: layout/src/main/debug/AndroidManifest.xml
================================================
================================================
FILE: layout/src/main/java/me/shouheng/layout/ModuleLayoutApp.java
================================================
package me.shouheng.layout;
import com.alibaba.android.arouter.launcher.ARouter;
import me.shouheng.commons.BaseApplication;
/**
* @author shouh
* @version $Id: ModuleGuokrApp, v 0.1 2018/6/6 22:30 shouh Exp$
*/
public class ModuleLayoutApp extends BaseApplication {
private static ModuleLayoutApp application;
public static ModuleLayoutApp getContext() {
return application;
}
@Override
public void onCreate() {
super.onCreate();
application = this;
ARouter.init(this);
}
}
================================================
FILE: layout/src/main/java/me/shouheng/layout/common/NormalTipsFragment.java
================================================
package me.shouheng.layout.common;
import android.app.Activity;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import android.view.View;
import com.alibaba.android.arouter.facade.annotation.Route;
import me.shouheng.commons.config.BaseConstants;
import me.shouheng.commons.view.fragment.CommonFragment;
import me.shouheng.layout.R;
import me.shouheng.layout.databinding.FragmentNormalTipsBinding;
/**
* Created by WngShhng on 2018/6/11.*/
@Route(path = BaseConstants.LAYOUT_NORMAL_FRAGMENT)
public class NormalTipsFragment extends CommonFragment {
private String title;
private String content;
private boolean showToolbar;
@Override
protected int getLayoutResId() {
return R.layout.fragment_normal_tips;
}
@Override
protected void doCreateView(Bundle savedInstanceState) {
handleArguments();
configToolbar();
configViews();
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setHasOptionsMenu(true);
}
private void handleArguments() {
Bundle args = getArguments();
assert args != null;
title = args.getString(BaseConstants.LAYOUT_NORMAL_FRAGMENT_EXTRA_TITLE);
content = args.getString(BaseConstants.LAYOUT_NORMAL_FRAGMENT_EXTRA_CONTENT);
showToolbar = args.getBoolean(BaseConstants.LAYOUT_NORMAL_FRAGMENT_EXTRA_SHOW_TOOLBAR);
}
private void configToolbar() {
Toolbar toolbar = getBinding().barLayout.toolbar;
if (!showToolbar) {
toolbar.setVisibility(View.GONE);
getBinding().shader.setVisibility(View.GONE);
return;
}
Activity activity = getActivity();
if (activity != null) {
((AppCompatActivity) activity).setSupportActionBar(toolbar);
ActionBar actionBar = ((AppCompatActivity) activity).getSupportActionBar();
if (actionBar != null) {
actionBar.setTitle(title);
}
}
}
private void configViews() {
getBinding().tvTitle.setText(title);
getBinding().tvContent.setText(content);
}
}
================================================
FILE: layout/src/main/java/me/shouheng/layout/view/ActivityEditLayout.java
================================================
package me.shouheng.layout.view;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout.LayoutParams;
import com.alibaba.android.arouter.facade.annotation.Route;
import me.shouheng.commons.config.BaseConstants;
import me.shouheng.commons.tools.ViewUtils;
import me.shouheng.commons.view.activity.CommonActivity;
import me.shouheng.layout.R;
import me.shouheng.layout.databinding.ActivityEditLayoutBinding;
/**
* Created on 2018/11/20.
*/
@Route(path = BaseConstants.LAYOUT_EDIT_LAYOUT)
public class ActivityEditLayout extends CommonActivity {
@Override
protected int getLayoutResId() {
return R.layout.activity_edit_layout;
}
@Override
protected void doCreateView(Bundle savedInstanceState) {
/* Get navigation bar height. */
int navHeight = ViewUtils.getNavigationBarHeight(this);
int statusBarHeight = ViewUtils.getStatusBarHeight(this);
/* RootView visible display frame. */
Rect visibleRect = new Rect();
getWindow().getDecorView().getWindowVisibleDisplayFrame(visibleRect);
/* LL visible display frame. */
Rect llVisibleRect = new Rect();
getBinding().ll.getWindowVisibleDisplayFrame(llVisibleRect);
/* Get window information. */
Point p = ViewUtils.getWindowSize(this);
/* Add a view with the same height of status bar. */
View view = new View(this);
view.setBackgroundColor(Color.BLUE);
LayoutParams lp = new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, statusBarHeight);
view.setLayoutParams(lp);
getBinding().container.addView(view, 0);
new Handler().postDelayed(() -> {
/* Get the ll hit rectangle. */
Rect llHitRect = new Rect();
getBinding().ll.getHitRect(llHitRect);
/* RootView visible display frame. */
Rect rootHitRect = new Rect();
getWindow().getDecorView().getHitRect(rootHitRect);
/* Display information. */
getBinding().tvInfo.setText("DecorView HitRect : " + rootHitRect + "\n"
+ "DecorView VisibleRect : " + visibleRect + "\n"
+ "Screen : " + p + "\n"
+ "LL HitRect : " + llHitRect + "\n"
+ "LL VisibleRect : " + llVisibleRect + "\n"
+ "StatusBar :" + statusBarHeight + "\n"
+ "NavBar :" + navHeight + "\n"
+ "LL(x:" + getBinding().ll.getX() + ", " + "y:" + getBinding().ll.getY() + "," + "w:" + getBinding().ll.getWidth() + "," + "h:" + getBinding().ll.getHeight() + ") \n"
+ "V(x:" + getBinding().v.getX() + ", " + "y:" + getBinding().v.getY() + "," + "w:" + getBinding().v.getWidth() + "," + "h:" + getBinding().v.getHeight() + ") \n");
}, 100);
}
}
================================================
FILE: layout/src/main/java/me/shouheng/layout/view/DrawerActivity.java
================================================
package me.shouheng.layout.view;
import android.os.Bundle;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.navigation.NavigationView;
import com.google.android.material.snackbar.Snackbar;
import androidx.core.view.GravityCompat;
import androidx.drawerlayout.widget.DrawerLayout;
import androidx.appcompat.app.ActionBarDrawerToggle;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import com.alibaba.android.arouter.facade.annotation.Route;
import me.shouheng.commons.config.BaseConstants;
import me.shouheng.layout.R;
@Route(path = BaseConstants.LAYOUT_DRAWER)
public class DrawerActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_drawer);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.addDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
}
@Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.drawer, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
@SuppressWarnings("StatementWithEmptyBody")
@Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
if (id == R.id.nav_camera) {
// Handle the camera action
} else if (id == R.id.nav_gallery) {
} else if (id == R.id.nav_slideshow) {
} else if (id == R.id.nav_manage) {
} else if (id == R.id.nav_share) {
} else if (id == R.id.nav_send) {
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
}
================================================
FILE: layout/src/main/java/me/shouheng/layout/view/LayoutMenuActivity.java
================================================
package me.shouheng.layout.view;
import android.os.Bundle;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.widget.Toolbar;
import android.view.MenuItem;
import com.alibaba.android.arouter.facade.annotation.Route;
import com.alibaba.android.arouter.launcher.ARouter;
import me.shouheng.commons.config.BaseConstants;
import me.shouheng.commons.view.activity.CommonActivity;
import me.shouheng.layout.R;
import me.shouheng.layout.databinding.ActivityLayoutMenuBinding;
@Route(path = BaseConstants.LAYOUT_MENU)
public class LayoutMenuActivity extends CommonActivity {
private boolean useAdapter = true;
@Override
protected int getLayoutResId() {
return R.layout.activity_layout_menu;
}
@Override
protected void doCreateView(Bundle savedInstanceState) {
configToolbar();
getBinding().bntNav.setOnClickListener(v ->
ARouter.getInstance()
.build(BaseConstants.LAYOUT_NAVIGATION)
.navigation());
getBinding().bntTabbed.setOnClickListener(v ->
ARouter.getInstance()
.build(BaseConstants.LAYOUT_TABBED)
.navigation());
getBinding().bntBottomSheet.setOnClickListener(v ->
ARouter.getInstance()
.build(BaseConstants.LAYOUT_BOTTOM_SHEET)
.navigation());
getBinding().bntCollapse.setOnClickListener(v ->
ARouter.getInstance()
.build(BaseConstants.LAYOUT_COLLAPSE_BAR)
.navigation());
getBinding().bntScrolling.setOnClickListener(v ->
ARouter.getInstance()
.build(BaseConstants.LAYOUT_SCROLLING)
.navigation());
getBinding().btnDrawer.setOnClickListener(v ->
ARouter.getInstance()
.build(BaseConstants.LAYOUT_DRAWER)
.navigation());
getBinding().btnViewSystem.setOnClickListener(v ->
ARouter.getInstance()
.build(BaseConstants.LAYOUT_VIEW_SYSTEM)
.navigation());
getBinding().btnViewAnimate.setOnClickListener(v ->
ARouter.getInstance()
.build(BaseConstants.LAYOUT_VIEW_ANIMATE)
.navigation());
getBinding().bntSupport28.setOnClickListener(v ->
ARouter.getInstance()
.build(BaseConstants.LAYOUT_SUPPORT_28)
.navigation());
getBinding().btnSwipe.setOnClickListener(v ->
ARouter.getInstance()
.build(BaseConstants.LAYOUT_SWIPE_BACK)
.navigation());
getBinding().btnAdapter.setOnClickListener(v ->
ARouter.getInstance()
.build(BaseConstants.LAYOUT_ADAPTER)
.withBoolean(BaseConstants.LAYOUT_ADAPTER_ARG_USE_ADAPTER, useAdapter = !useAdapter)
.navigation());
getBinding().btnEdit.setOnClickListener(v ->
ARouter.getInstance()
.build(BaseConstants.LAYOUT_EDIT_LAYOUT)
.navigation());
}
private void configToolbar() {
Toolbar toolbar = getBinding().barLayout.toolbar;
toolbar.setBackgroundResource(R.color.light_theme_background);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setTitle(R.string.menu_item_title_3);
actionBar.setSubtitle(R.string.menu_item_desc_3);
actionBar.setDisplayHomeAsUpEnabled(true);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
super.onBackPressed();
break;
}
return super.onOptionsItemSelected(item);
}
}
================================================
FILE: layout/src/main/java/me/shouheng/layout/view/adapter/AdapterUtils.java
================================================
package me.shouheng.layout.view.adapter;
import android.app.Activity;
import android.app.Application;
import android.content.ComponentCallbacks;
import android.content.res.Configuration;
import android.util.DisplayMetrics;
/**
* Created by WngShhng on 2018/10/29.
*/
public class AdapterUtils {
private static float noCompactDensity;
private static float noCompactScaledDensity;
public static void setCustomDensity(Activity activity, Application application) {
DisplayMetrics appDisplayMetrics = application.getResources().getDisplayMetrics();
if (noCompactDensity == 0) {
noCompactDensity = appDisplayMetrics.density;
noCompactScaledDensity = appDisplayMetrics.scaledDensity;
application.registerComponentCallbacks(new ComponentCallbacks() {
@Override
public void onConfigurationChanged(Configuration newConfig) {
if (newConfig != null && newConfig.fontScale > 0) {
noCompactScaledDensity = application.getResources().getDisplayMetrics().scaledDensity;
}
}
@Override
public void onLowMemory() { }
});
}
float targetDensity = appDisplayMetrics.widthPixels / 360;
float targetScaledDensity = targetDensity * (noCompactScaledDensity / noCompactDensity);
int targetDensityDpi = (int) (160 * targetDensity);
appDisplayMetrics.density = targetDensity;
appDisplayMetrics.scaledDensity = targetScaledDensity;
appDisplayMetrics.densityDpi = targetDensityDpi;
DisplayMetrics activityDisplayMetrics = activity.getResources().getDisplayMetrics();
activityDisplayMetrics.density = targetDensity;
activityDisplayMetrics.scaledDensity = targetScaledDensity;
activityDisplayMetrics.densityDpi = targetDensityDpi;
}
}
================================================
FILE: layout/src/main/java/me/shouheng/layout/view/adapter/BeforeAdapter.java
================================================
package me.shouheng.layout.view.adapter;
import android.os.Bundle;
import androidx.appcompat.app.AlertDialog;
import com.alibaba.android.arouter.facade.annotation.Route;
import me.shouheng.commons.config.BaseConstants;
import me.shouheng.commons.tools.LogUtils;
import me.shouheng.commons.view.activity.CommonActivity;
import me.shouheng.layout.R;
import me.shouheng.layout.databinding.ActivityAdapterBinding;
/**
* Created by WngShhng on 2018/10/29.
*/
@Route(path = BaseConstants.LAYOUT_ADAPTER)
public class BeforeAdapter extends CommonActivity {
@Override
protected int getLayoutResId() {
return R.layout.activity_adapter;
}
@Override
protected void doCreateView(Bundle savedInstanceState) {
boolean useAdapter = getIntent().getBooleanExtra(BaseConstants.LAYOUT_ADAPTER_ARG_USE_ADAPTER, false);
LogUtils.d("should use screen adapter " + useAdapter);
if (useAdapter) {
AdapterUtils.setCustomDensity(this, getApplication());
}
new AlertDialog.Builder(this)
.setTitle("测试对话框")
.setMessage("用来测试布局适配性的对话框")
.create().show();
}
}
================================================
FILE: layout/src/main/java/me/shouheng/layout/view/bottomsheet/BottomSheetActivity.java
================================================
package me.shouheng.layout.view.bottomsheet;
import android.graphics.Color;
import android.os.Bundle;
import com.alibaba.android.arouter.facade.annotation.Route;
import me.shouheng.commons.config.BaseConstants;
import me.shouheng.commons.view.activity.CommonActivity;
import me.shouheng.layout.R;
import me.shouheng.layout.databinding.ActivityBottomSheetBinding;
@Route(path = BaseConstants.LAYOUT_BOTTOM_SHEET)
public class BottomSheetActivity extends CommonActivity {
@Override
protected int getLayoutResId() {
return R.layout.activity_bottom_sheet;
}
@Override
protected void doCreateView(Bundle savedInstanceState) {
getBinding().toolbar.setTitle(R.string.menu_item_sub_title_3);
getBinding().toolbar.setTitleTextColor(Color.BLACK);
}
}
================================================
FILE: layout/src/main/java/me/shouheng/layout/view/collapse/CollapseBarStructure.java
================================================
package me.shouheng.layout.view.collapse;
import android.graphics.Color;
import android.os.Bundle;
import com.alibaba.android.arouter.facade.annotation.Route;
import me.shouheng.commons.config.BaseConstants;
import me.shouheng.commons.view.activity.CommonActivity;
import me.shouheng.layout.R;
import me.shouheng.layout.databinding.ActivityCollapseBarStructureBinding;
@Route(path = BaseConstants.LAYOUT_COLLAPSE_BAR)
public class CollapseBarStructure extends CommonActivity {
@Override
protected int getLayoutResId() {
return R.layout.activity_collapse_bar_structure;
}
@Override
protected void doCreateView(Bundle savedInstanceState) {
getBinding().toolbar.setTitle("");
getBinding().toolbar.setTitleTextColor(Color.BLACK);
}
}
================================================
FILE: layout/src/main/java/me/shouheng/layout/view/custom/CustomView.java
================================================
package me.shouheng.layout.view.custom;
import android.content.Context;
import android.graphics.Canvas;
import androidx.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
/**
* @author shouh
* @version $Id: CustomView, v 0.1 2018/10/13 11:31 shouh Exp$
*/
public class CustomView extends View {
public CustomView(Context context) {
super(context);
}
public CustomView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public CustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
================================================
FILE: layout/src/main/java/me/shouheng/layout/view/navigation/NavigationActivity.java
================================================
package me.shouheng.layout.view.navigation;
import android.os.Bundle;
import androidx.fragment.app.FragmentManager;
import com.alibaba.android.arouter.facade.annotation.Route;
import com.alibaba.android.arouter.launcher.ARouter;
import me.shouheng.commons.config.BaseConstants;
import me.shouheng.commons.tools.PalmUtils;
import me.shouheng.commons.view.activity.CommonActivity;
import me.shouheng.layout.R;
import me.shouheng.layout.common.NormalTipsFragment;
import me.shouheng.layout.databinding.ActivityNavigationBinding;
import me.shouheng.layout.view.navigation.fragment.PagerFragment;
@Route(path = BaseConstants.LAYOUT_NAVIGATION)
public class NavigationActivity extends CommonActivity {
private final String FRAGMENT_KEY_PAGER = "__key_fragment_pager";
private final String FRAGMENT_KEY_FAVORITE = "__key_fragment_favorite";
private final String FRAGMENT_KEY_INFO = "__key_fragment_info";
private PagerFragment pagerFragment;
private NormalTipsFragment favoriteFragment;
private NormalTipsFragment infoFragment;
@Override
protected int getLayoutResId() {
return R.layout.activity_navigation;
}
@Override
protected void doCreateView(Bundle savedInstanceState) {
initFragments(savedInstanceState);
getBinding().nav.setOnNavigationItemSelectedListener(menuItem -> {
if (menuItem.getItemId() == R.id.nav_main) {
showFragment(FRAGMENT_KEY_PAGER);
} else if (menuItem.getItemId() == R.id.nav_favorite) {
showFragment(FRAGMENT_KEY_FAVORITE);
} else if (menuItem.getItemId() == R.id.nav_info) {
showFragment(FRAGMENT_KEY_INFO);
}
return true;
});
showFragment(FRAGMENT_KEY_PAGER);
}
private void initFragments(Bundle savedInstanceState) {
FragmentManager fm = getSupportFragmentManager();
if (savedInstanceState == null) {
pagerFragment = (PagerFragment) ARouter.getInstance()
.build(BaseConstants.LAYOUT_PAGER_FRAGMENT)
.navigation();
favoriteFragment = (NormalTipsFragment) ARouter.getInstance()
.build(BaseConstants.LAYOUT_NORMAL_FRAGMENT)
.withString(BaseConstants.LAYOUT_NORMAL_FRAGMENT_EXTRA_TITLE, PalmUtils.getStringCompact(R.string.nav_bottom_item_2))
.withString(BaseConstants.LAYOUT_NORMAL_FRAGMENT_EXTRA_CONTENT, PalmUtils.getStringCompact(R.string.nav_bottom_desc_2))
.withBoolean(BaseConstants.LAYOUT_NORMAL_FRAGMENT_EXTRA_SHOW_TOOLBAR, true)
.navigation();
infoFragment = (NormalTipsFragment) ARouter.getInstance()
.build(BaseConstants.LAYOUT_NORMAL_FRAGMENT)
.withString(BaseConstants.LAYOUT_NORMAL_FRAGMENT_EXTRA_TITLE, PalmUtils.getStringCompact(R.string.nav_bottom_item_3))
.withString(BaseConstants.LAYOUT_NORMAL_FRAGMENT_EXTRA_CONTENT, PalmUtils.getStringCompact(R.string.nav_bottom_desc_3))
.withBoolean(BaseConstants.LAYOUT_NORMAL_FRAGMENT_EXTRA_SHOW_TOOLBAR, true)
.navigation();
} else {
pagerFragment = (PagerFragment) fm.getFragment(savedInstanceState, FRAGMENT_KEY_PAGER);
favoriteFragment = (NormalTipsFragment) fm.getFragment(savedInstanceState, FRAGMENT_KEY_FAVORITE);
infoFragment = (NormalTipsFragment) fm.getFragment(savedInstanceState, FRAGMENT_KEY_INFO);
}
if (!pagerFragment.isAdded()) {
fm.beginTransaction().add(R.id.fragment_container, pagerFragment, FRAGMENT_KEY_PAGER).commit();
}
if (!favoriteFragment.isAdded()) {
fm.beginTransaction().add(R.id.fragment_container, favoriteFragment, FRAGMENT_KEY_FAVORITE).commit();
}
if (!infoFragment.isAdded()) {
fm.beginTransaction().add(R.id.fragment_container, infoFragment, FRAGMENT_KEY_INFO).commit();
}
}
private void showFragment(String key) {
FragmentManager fm = getSupportFragmentManager();
switch (key) {
case FRAGMENT_KEY_PAGER:
fm.beginTransaction().show(pagerFragment).hide(favoriteFragment).hide(infoFragment).commit();
break;
case FRAGMENT_KEY_FAVORITE:
fm.beginTransaction().show(favoriteFragment).hide(pagerFragment).hide(infoFragment).commit();
break;
case FRAGMENT_KEY_INFO:
fm.beginTransaction().show(infoFragment).hide(favoriteFragment).hide(pagerFragment).commit();
break;
}
}
}
================================================
FILE: layout/src/main/java/me/shouheng/layout/view/navigation/fragment/PagerFragment.java
================================================
package me.shouheng.layout.view.navigation.fragment;
import android.graphics.Color;
import android.os.Bundle;
import androidx.annotation.Nullable;
import com.google.android.material.tabs.TabLayout.OnTabSelectedListener;
import com.google.android.material.tabs.TabLayout.Tab;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import com.alibaba.android.arouter.facade.annotation.Route;
import com.alibaba.android.arouter.launcher.ARouter;
import java.util.Arrays;
import java.util.List;
import me.shouheng.commons.config.BaseConstants;
import me.shouheng.commons.tools.ToastUtils;
import me.shouheng.commons.view.fragment.CommonFragment;
import me.shouheng.layout.R;
import me.shouheng.layout.common.NormalTipsFragment;
import me.shouheng.layout.databinding.FragmentPagerBinding;
/**
* Created by WngShhng on 2018/6/11.*/
@Route(path = BaseConstants.LAYOUT_PAGER_FRAGMENT)
public class PagerFragment extends CommonFragment {
@Override
protected int getLayoutResId() {
return R.layout.fragment_pager;
}
@Override
protected void doCreateView(Bundle savedInstanceState) {
getBinding().toolbar.setTitle(R.string.menu_item_sub_title_1);
getBinding().toolbar.setTitleTextColor(Color.BLACK);
Fragment tabFragment1 = (NormalTipsFragment) ARouter.getInstance()
.build(BaseConstants.LAYOUT_NORMAL_FRAGMENT)
.withString(BaseConstants.LAYOUT_NORMAL_FRAGMENT_EXTRA_TITLE, "Tab Fragment 1")
.withString(BaseConstants.LAYOUT_NORMAL_FRAGMENT_EXTRA_CONTENT, "This is the content for the tab fragment 1")
.withBoolean(BaseConstants.LAYOUT_NORMAL_FRAGMENT_EXTRA_SHOW_TOOLBAR, false)
.navigation();
Fragment tabFragment2 = (NormalTipsFragment) ARouter.getInstance()
.build(BaseConstants.LAYOUT_NORMAL_FRAGMENT)
.withString(BaseConstants.LAYOUT_NORMAL_FRAGMENT_EXTRA_TITLE, "Tab Fragment 2")
.withString(BaseConstants.LAYOUT_NORMAL_FRAGMENT_EXTRA_CONTENT, "This is the content for the tab fragment 2")
.withBoolean(BaseConstants.LAYOUT_NORMAL_FRAGMENT_EXTRA_SHOW_TOOLBAR, false)
.navigation();
Fragment tabFragment3 = (NormalTipsFragment) ARouter.getInstance()
.build(BaseConstants.LAYOUT_NORMAL_FRAGMENT)
.withString(BaseConstants.LAYOUT_NORMAL_FRAGMENT_EXTRA_TITLE, "Tab Fragment 3")
.withString(BaseConstants.LAYOUT_NORMAL_FRAGMENT_EXTRA_CONTENT, "This is the content for the tab fragment 3")
.withBoolean(BaseConstants.LAYOUT_NORMAL_FRAGMENT_EXTRA_SHOW_TOOLBAR, false)
.navigation();
getBinding().vp.setAdapter(new TabFragmentAdapter(getFragmentManager(),
Arrays.asList(tabFragment1, tabFragment2, tabFragment3),
Arrays.asList("Tab1", "Tab2", "Tab3")));
getBinding().vp.setOffscreenPageLimit(3);
getBinding().tabLayout.setupWithViewPager(getBinding().vp);
getBinding().tabLayout.addOnTabSelectedListener(new OnTabSelectedListener() {
@Override
public void onTabSelected(Tab tab) {
ToastUtils.makeToast("Tab" + (1 + tab.getPosition()) + "clicked!");
}
@Override
public void onTabUnselected(Tab tab) { }
@Override
public void onTabReselected(Tab tab) { }
});
getBinding().fab.setOnClickListener(v -> ToastUtils.makeToast("Fab clicked!"));
}
public static class TabFragmentAdapter extends FragmentPagerAdapter {
private List fragments;
private List titles;
TabFragmentAdapter(FragmentManager fm, List fragments, List titles) {
super(fm);
this.fragments = fragments;
this.titles = titles;
if (fragments.size() - titles.size() != 0) {
throw new IllegalArgumentException("The length for fragments and titles must be the same!");
}
}
@Override
public Fragment getItem(int position) {
return fragments.get(position);
}
@Override
public int getCount() {
return fragments.size();
}
@Nullable
@Override
public CharSequence getPageTitle(int position) {
return titles.get(position);
}
}
}
================================================
FILE: layout/src/main/java/me/shouheng/layout/view/scrolling/ScrollingActivity.java
================================================
package me.shouheng.layout.view.scrolling;
import android.graphics.Color;
import android.os.Bundle;
import com.google.android.material.snackbar.Snackbar;
import com.alibaba.android.arouter.facade.annotation.Route;
import me.shouheng.commons.config.BaseConstants;
import me.shouheng.commons.view.activity.CommonActivity;
import me.shouheng.layout.R;
import me.shouheng.layout.databinding.ActivityScrollingBinding;
@Route(path = BaseConstants.LAYOUT_SCROLLING)
public class ScrollingActivity extends CommonActivity {
@Override
protected int getLayoutResId() {
return R.layout.activity_scrolling;
}
@Override
protected void doCreateView(Bundle savedInstanceState) {
getBinding().toolbar.setTitle(R.string.menu_item_sub_title_4);
getBinding().toolbar.setTitleTextColor(Color.BLACK);
getBinding().fab.setOnClickListener(v ->
Snackbar.make(v, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show());
}
}
================================================
FILE: layout/src/main/java/me/shouheng/layout/view/support28/BottomAppBarActivity.java
================================================
package me.shouheng.layout.view.support28;
import android.os.Bundle;
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.LinearLayoutManager;
import com.alibaba.android.arouter.facade.annotation.Route;
import com.chad.library.adapter.base.BaseQuickAdapter;
import com.chad.library.adapter.base.BaseViewHolder;
import java.util.LinkedList;
import java.util.List;
import io.reactivex.Observable;
import io.reactivex.disposables.Disposable;
import me.shouheng.commons.config.BaseConstants;
import me.shouheng.commons.view.activity.CommonActivity;
import me.shouheng.layout.R;
import me.shouheng.layout.databinding.ActivityBottomAppBarBinding;
/**
* Created by WngShhng on 2018/9/11.
*/
@Route(path = BaseConstants.LAYOUT_BOTTOM_APP_BAR)
public class BottomAppBarActivity extends CommonActivity {
@Override
protected int getLayoutResId() {
return R.layout.activity_bottom_app_bar;
}
@Override
protected void doCreateView(Bundle savedInstanceState) {
// getBinding().bottomAppBar.replaceMenu(R.menu.bottom_navigation);
//
List items = new LinkedList<>();
Disposable disposable = Observable.range(40, 50).subscribe(integer -> items.add(String.valueOf(integer)));
Adapter adapter = new Adapter(items);
getBinding().rv.setLayoutManager(new LinearLayoutManager(getContext()));
getBinding().rv.setAdapter(adapter);
}
private static class Adapter extends BaseQuickAdapter {
Adapter(@Nullable List data) {
super(android.R.layout.simple_list_item_1, data);
}
@Override
protected void convert(BaseViewHolder helper, String item) {
helper.setText(android.R.id.text1, item);
}
}
}
================================================
FILE: layout/src/main/java/me/shouheng/layout/view/support28/Support28Activity.java
================================================
package me.shouheng.layout.view.support28;
import android.os.Bundle;
import com.alibaba.android.arouter.facade.annotation.Route;
import com.alibaba.android.arouter.launcher.ARouter;
import me.shouheng.commons.config.BaseConstants;
import me.shouheng.commons.view.activity.CommonActivity;
import me.shouheng.layout.R;
import me.shouheng.layout.databinding.ActivitySupport28Binding;
/**
* Created by WngShhng on 2018/9/11.
*/
@Route(path = BaseConstants.LAYOUT_SUPPORT_28)
public class Support28Activity extends CommonActivity {
@Override
protected int getLayoutResId() {
return R.layout.activity_support_28;
}
@Override
protected void doCreateView(Bundle savedInstanceState) {
getBinding().btnBottomBar.setOnClickListener(v ->
ARouter.getInstance()
.build(BaseConstants.LAYOUT_BOTTOM_APP_BAR)
.navigation());
}
}
================================================
FILE: layout/src/main/java/me/shouheng/layout/view/swipe/SwipeBackDemoActivity.java
================================================
package me.shouheng.layout.view.swipe;
import android.os.Bundle;
import com.alibaba.android.arouter.facade.annotation.Route;
import me.imid.swipebacklayout.lib.app.SwipeBackActivity;
import me.shouheng.commons.config.BaseConstants;
import me.shouheng.layout.R;
/**
* Created by WngShhng on 2018/10/19.
*/
@Route(path = BaseConstants.LAYOUT_SWIPE_BACK)
public class SwipeBackDemoActivity extends SwipeBackActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_swipe_back);
}
}
================================================
FILE: layout/src/main/java/me/shouheng/layout/view/tabbed/TabbedActivity.java
================================================
package me.shouheng.layout.view.tabbed;
import android.graphics.Color;
import android.os.Bundle;
import com.google.android.material.snackbar.Snackbar;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import com.alibaba.android.arouter.facade.annotation.Route;
import com.alibaba.android.arouter.launcher.ARouter;
import me.shouheng.commons.config.BaseConstants;
import me.shouheng.commons.view.activity.CommonActivity;
import me.shouheng.layout.R;
import me.shouheng.layout.databinding.ActivityTabbedBinding;
@Route(path = BaseConstants.LAYOUT_TABBED)
public class TabbedActivity extends CommonActivity {
@Override
protected int getLayoutResId() {
return R.layout.activity_tabbed;
}
@Override
protected void doCreateView(Bundle savedInstanceState) {
getBinding().toolbar.setTitle(R.string.menu_item_sub_title_2);
getBinding().toolbar.setTitleTextColor(Color.BLACK);
setSupportActionBar(getBinding().toolbar);
SectionsPagerAdapter adapter = new SectionsPagerAdapter(getSupportFragmentManager());
getBinding().vp.setAdapter(adapter);
getBinding().fab.setOnClickListener(view ->
Snackbar.make(view, "Fab is clicked!", Snackbar.LENGTH_LONG)
.setAction("Action", null).show()
);
}
public class SectionsPagerAdapter extends FragmentPagerAdapter {
SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
return (Fragment) ARouter.getInstance()
.build(BaseConstants.LAYOUT_NORMAL_FRAGMENT)
.withString(BaseConstants.LAYOUT_NORMAL_FRAGMENT_EXTRA_TITLE, "Fragment " + (position + 1))
.withString(BaseConstants.LAYOUT_NORMAL_FRAGMENT_EXTRA_CONTENT, "Content fragment of tabbed activity : " + (position + 1))
.withBoolean(BaseConstants.LAYOUT_NORMAL_FRAGMENT_EXTRA_SHOW_TOOLBAR, false)
.navigation();
}
@Override
public int getCount() {
return 3;
}
@Override
public CharSequence getPageTitle(int position) {
switch (position) {
case 0: return "Tab 1";
case 1: return "Tab 2";
case 2: return "Tab 3";
}
return null;
}
}
}
================================================
FILE: layout/src/main/java/me/shouheng/layout/view/views/CustomView.java
================================================
package me.shouheng.layout.view.views;
import android.content.Context;
import androidx.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.Scroller;
/**
* @author shouh
* @version $Id: CustomView, v 0.1 2018/10/5 16:34 shouh Exp$
*/
public class CustomView extends View {
private Scroller scroller = new Scroller(getContext());
public CustomView(Context context) {
super(context);
}
public CustomView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public CustomView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
public void computeScroll() {
super.computeScroll();
if (scroller.computeScrollOffset()) {
((View) getParent()).scrollTo(scroller.getCurrX(), scroller.getCurrY());
invalidate();
}
}
public void smoothScrollTo(int descX, int descY) {
scroller.startScroll(getScrollX(), getScrollY(), descX - getScrollX(), descY - getScrollY(), 2000);
invalidate();
}
}
================================================
FILE: layout/src/main/java/me/shouheng/layout/view/views/ViewAnimateActivity.java
================================================
package me.shouheng.layout.view.views;
import android.animation.TypeEvaluator;
import android.animation.ValueAnimator;
import android.graphics.drawable.AnimationDrawable;
import android.os.Build;
import android.os.Bundle;
import android.transition.Explode;
import android.view.animation.AnimationUtils;
import com.alibaba.android.arouter.facade.annotation.Route;
import java.util.Date;
import me.shouheng.commons.config.BaseConstants;
import me.shouheng.commons.tools.LogUtils;
import me.shouheng.commons.tools.ToastUtils;
import me.shouheng.commons.view.activity.CommonActivity;
import me.shouheng.layout.R;
import me.shouheng.layout.databinding.ActivityViewAnimateBinding;
/**
* @author shouh
* @version $Id: ViewAnimateActivity, v 0.1 2018/10/5 18:41 shouh Exp$
*/
@Route(path = BaseConstants.LAYOUT_VIEW_ANIMATE)
public class ViewAnimateActivity extends CommonActivity {
private AnimationDrawable animDraw;
@Override
protected int getLayoutResId() {
return R.layout.activity_view_animate;
}
@Override
protected void doCreateView(Bundle savedInstanceState) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().setEnterTransition(new Explode());
} else {
overridePendingTransition(R.anim.shake, R.anim.shake);
}
getBinding().v.setOnClickListener(v -> ToastUtils.makeToast("Clicked"));
getBinding().btnAniamte.setOnClickListener(v -> animate());
getBinding().btnShake.setOnClickListener(v -> shake());
// Drawable 动画
getBinding().ivRecord.setImageResource(R.drawable.record_anim);
animDraw = (AnimationDrawable) getBinding().ivRecord.getDrawable();
animDraw.start();
ValueAnimator animator = ValueAnimator.ofObject(new DateEvaluator(), new Date(0), new Date());
animator.setDuration(5000);
animator.addUpdateListener(animation -> {
Date date = (Date) animation.getAnimatedValue();
LogUtils.d(date);
});
animator.start();
}
private static class DateEvaluator implements TypeEvaluator {
@Override
public Date evaluate(float fraction, Date startValue, Date endValue) {
long startTime = startValue.getTime();
return new Date((long) (startTime + fraction * (endValue.getTime() - startTime)));
}
}
private void animate() {
getBinding().v.animate()
.scaleY(0.5f)
.scaleX(0.5f)
.translationX(100)
.translationX(100)
.rotation(5f)
.start();
}
private void shake() {
getBinding().v.startAnimation(AnimationUtils.loadAnimation(this, R.anim.shake));
}
@Override
protected void onPause() {
super.onPause();
animDraw.stop();
}
}
================================================
FILE: layout/src/main/java/me/shouheng/layout/view/views/ViewSystemActivity.java
================================================
package me.shouheng.layout.view.views;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.os.Handler;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.widget.FrameLayout;
import com.alibaba.android.arouter.facade.annotation.Route;
import me.shouheng.commons.config.BaseConstants;
import me.shouheng.commons.tools.LogUtils;
import me.shouheng.commons.tools.ToastUtils;
import me.shouheng.commons.view.activity.CommonActivity;
import me.shouheng.layout.R;
import me.shouheng.layout.databinding.ActivityViewSystemBinding;
/**
* @author shouh
* @version $Id: ViewSystemActivity, v 0.1 2018/10/5 13:24 shouh Exp$
*/
@Route(path = BaseConstants.LAYOUT_VIEW_SYSTEM)
public class ViewSystemActivity extends CommonActivity {
private int lastX, lastY;
private GestureDetector mGestureDetector;
private VelocityTracker velocityTracker;
private long duration, downTime;
@Override
protected int getLayoutResId() {
return R.layout.activity_view_system;
}
@SuppressLint("ClickableViewAccessibility")
@Override
protected void doCreateView(Bundle savedInstanceState) {
dispCoordinate(null);
getBinding().v.setOnTouchListener((v, event) -> {
dispCoordinate(event);
// layoutMove(event);
// offsetMove(event);
// lpMove(event);
// scrollByMove(event);
scrollToMove(event);
return true;
});
getBinding().btnTrans.setOnClickListener(v -> {
getBinding().v.animate().translationX(5f);
getBinding().v.animate().translationY(5f);
dispCoordinate(null);
});
getBinding().btnScroller.setOnClickListener(v -> scrollerMove());
new Handler().postDelayed(() -> dispCoordinate(null), 1000);
// GestureDetector
mGestureDetector = new GestureDetector(getContext(), new MyOnGestureListener());
velocityTracker = VelocityTracker.obtain();
getBinding().vg.setOnTouchListener((v, event) -> {
mGestureDetector.onTouchEvent(event);
velocityTracker.addMovement(event);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
downTime = System.currentTimeMillis();
break;
case MotionEvent.ACTION_UP:
duration = System.currentTimeMillis() - downTime;
break;
}
return true;
});
getBinding().btnVelocity.setOnClickListener(v -> {
velocityTracker.computeCurrentVelocity((int) duration);
getBinding().tvVelocity.setText("X:" + velocityTracker.getXVelocity() + "\n"
+ "Y:" + velocityTracker.getYVelocity());
});
}
private class MyOnGestureListener extends GestureDetector.SimpleOnGestureListener {
@Override
public boolean onSingleTapUp(MotionEvent e) {
ToastUtils.makeToast("Click detected");
return false;
}
@Override
public void onLongPress(MotionEvent e) {
LogUtils.d("Long press detected");
}
@Override
public boolean onDoubleTap(MotionEvent e) {
LogUtils.d("Double tab detected");
return true;
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
LogUtils.d("Fling detected");
return true;
}
}
private void dispCoordinate(MotionEvent event) {
String coordinate = "View.Top:" + getBinding().v.getTop() + "\n"
+ "View.Bottom:" + getBinding().v.getBottom() + "\n"
+ "View.Left:" + getBinding().v.getLeft() + "\n"
+ "View.Right:" + getBinding().v.getRight() + "\n"
+ "View.X:" + getBinding().v.getX() + "\n"
+ "View.Y:" + getBinding().v.getY() + "\n"
+ "View.Height:" + getBinding().v.getHeight() + "\n"
+ "View.Width:" + getBinding().v.getWidth() + "\n";
if (event != null) {
coordinate += "MotionEvent.RawX:" + event.getRawX() + "\n"
+ "MotionEvent.RawY:" + event.getRawY() + "\n"
+ "MotionEvent.X:" + event.getX() + "\n"
+ "MotionEvent.Y:" + event.getY() + "\n";
}
getBinding().tvCoordinate.setText(coordinate);
}
private void layoutMove(MotionEvent event) {
int x = (int) event.getX(), y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
lastX = x;
lastY = y;
break;
case MotionEvent.ACTION_MOVE:
int offsetX = x - lastX, offsetY = y - lastY;
getBinding().v.layout(getBinding().v.getLeft() + offsetX,
getBinding().v.getTop() + offsetY,
getBinding().v.getRight() + offsetX,
getBinding().v.getBottom() + offsetY);
break;
case MotionEvent.ACTION_UP:
break;
}
}
private void offsetMove(MotionEvent event) {
int x = (int) event.getX(), y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
lastX = x;
lastY = y;
break;
case MotionEvent.ACTION_MOVE:
int offsetX = x - lastX, offsetY = y - lastY;
getBinding().v.offsetLeftAndRight(offsetX);
getBinding().v.offsetTopAndBottom(offsetY);
break;
case MotionEvent.ACTION_UP:
break;
}
}
private void lpMove(MotionEvent event) {
int x = (int) event.getX(), y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
lastX = x;
lastY = y;
break;
case MotionEvent.ACTION_MOVE:
int offsetX = x - lastX, offsetY = y - lastY;
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) getBinding().v.getLayoutParams();
lp.leftMargin = getBinding().v.getLeft() + offsetX;
lp.topMargin = getBinding().v.getTop() + offsetY;
getBinding().v.setLayoutParams(lp);
break;
case MotionEvent.ACTION_UP:
break;
}
}
private void scrollByMove(MotionEvent event) {
int x = (int) event.getX(), y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
lastX = x;
lastY = y;
break;
case MotionEvent.ACTION_MOVE:
int offsetX = x - lastX, offsetY = y - lastY;
((View) getBinding().v.getParent()).scrollBy(-offsetX, -offsetY);
break;
case MotionEvent.ACTION_UP:
break;
}
}
private void scrollToMove(MotionEvent event) {
int x = (int) event.getX(), y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
lastX = x;
lastY = y;
break;
case MotionEvent.ACTION_MOVE:
int offsetX = x - lastX, offsetY = y - lastY;
View parent = ((View) getBinding().v.getParent());
parent.scrollTo(parent.getScrollX()-offsetX, parent.getScrollY()-offsetY);
break;
case MotionEvent.ACTION_UP:
break;
}
}
private void scrollerMove() {
getBinding().v.smoothScrollTo(-400, -100);
}
@Override
protected void onDestroy() {
super.onDestroy();
velocityTracker.clear();
velocityTracker.recycle();
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
return super.dispatchTouchEvent(ev);
}
}
================================================
FILE: layout/src/main/res/anim/cycle_7.xml
================================================
================================================
FILE: layout/src/main/res/anim/layout_anim.xml
================================================
================================================
FILE: layout/src/main/res/anim/shake.xml
================================================
================================================
FILE: layout/src/main/res/drawable/branded_background.xml
================================================
-
-
================================================
FILE: layout/src/main/res/drawable/ic_launcher_background.xml
================================================
================================================
FILE: layout/src/main/res/drawable/record_anim.xml
================================================
================================================
FILE: layout/src/main/res/drawable/side_nav_bar.xml
================================================
================================================
FILE: layout/src/main/res/drawable-v21/ic_menu_camera.xml
================================================
================================================
FILE: layout/src/main/res/drawable-v21/ic_menu_gallery.xml
================================================
================================================
FILE: layout/src/main/res/drawable-v21/ic_menu_manage.xml
================================================
================================================
FILE: layout/src/main/res/drawable-v21/ic_menu_send.xml
================================================
================================================
FILE: layout/src/main/res/drawable-v21/ic_menu_share.xml
================================================
================================================
FILE: layout/src/main/res/drawable-v21/ic_menu_slideshow.xml
================================================
================================================
FILE: layout/src/main/res/drawable-v24/ic_launcher_foreground.xml
================================================
================================================
FILE: layout/src/main/res/layout/activity_adapter.xml
================================================
================================================
FILE: layout/src/main/res/layout/activity_bottom_app_bar.xml
================================================
================================================
FILE: layout/src/main/res/layout/activity_bottom_sheet.xml
================================================
================================================
FILE: layout/src/main/res/layout/activity_collapse_bar_structure.xml
================================================
================================================
FILE: layout/src/main/res/layout/activity_drawer.xml
================================================
================================================
FILE: layout/src/main/res/layout/activity_edit_layout.xml
================================================
================================================
FILE: layout/src/main/res/layout/activity_layout_menu.xml
================================================
================================================
FILE: layout/src/main/res/layout/activity_navigation.xml
================================================
================================================
FILE: layout/src/main/res/layout/activity_scrolling.xml
================================================
================================================
FILE: layout/src/main/res/layout/activity_support_28.xml
================================================
================================================
FILE: layout/src/main/res/layout/activity_swipe_back.xml
================================================
================================================
FILE: layout/src/main/res/layout/activity_tabbed.xml
================================================
================================================
FILE: layout/src/main/res/layout/activity_view_animate.xml
================================================
================================================
FILE: layout/src/main/res/layout/activity_view_system.xml
================================================
================================================
FILE: layout/src/main/res/layout/app_bar_drawer.xml
================================================
================================================
FILE: layout/src/main/res/layout/bottom_sheet_dialog.xml
================================================
================================================
FILE: layout/src/main/res/layout/content_drawer.xml
================================================
================================================
FILE: layout/src/main/res/layout/fragment_normal_tips.xml
================================================
================================================
FILE: layout/src/main/res/layout/fragment_pager.xml
================================================
================================================
FILE: layout/src/main/res/layout/nav_header_drawer.xml
================================================
================================================
FILE: layout/src/main/res/menu/activity_drawer_drawer.xml
================================================
================================================
FILE: layout/src/main/res/menu/bottom_navigation.xml
================================================
================================================
FILE: layout/src/main/res/menu/drawer.xml
================================================
================================================
FILE: layout/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
================================================
================================================
FILE: layout/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
================================================
================================================
FILE: layout/src/main/res/values/colors.xml
================================================
#FAFAFA
#FAFAFA
#0078FF
================================================
FILE: layout/src/main/res/values/dimens.xml
================================================
16dp
16dp
8dp
176dp
16dp
================================================
FILE: layout/src/main/res/values/drawables.xml
================================================
- @android:drawable/ic_menu_camera
- @android:drawable/ic_menu_gallery
- @android:drawable/ic_menu_slideshow
- @android:drawable/ic_menu_manage
- @android:drawable/ic_menu_share
- @android:drawable/ic_menu_send
================================================
FILE: layout/src/main/res/values/strings.xml
================================================
layout
DrawerActivity
Open navigation drawer
Close navigation drawer
Android Studio
android.studio@android.com
Navigation header
Settings
================================================
FILE: layout/src/main/res/values/styles.xml
================================================
================================================
FILE: layout/src/main/res/values-v21/styles.xml
================================================
================================================
FILE: layout/src/test/java/me/shouheng/layout/ExampleUnitTest.java
================================================
package me.shouheng.layout;
import org.junit.Test;
import static org.junit.Assert.*;
/**
* Example local unit test, which will execute on the development machine (host).
*
* @see Testing documentation
*/
public class ExampleUnitTest {
@Test
public void dpTestCase1() {
int width = 720, height = 1280;
float inch = 4.7f;
float result = (float) (Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2)) / inch);
assertEquals(360, result, 0.1);
}
@Test
public void dpTestCase2() {
int width = 1920, height = 1080;
float inch = 5f;
float result = (float) (Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2)) / inch);
assertEquals(440, result, 0.1);
}
}
================================================
FILE: libraries/.gitignore
================================================
/build
================================================
FILE: libraries/build.gradle
================================================
println isLibraryModuleApp.toBoolean()
if (isLibraryModuleApp.toBoolean()) {
apply plugin: 'com.android.application'
} else {
apply plugin: 'com.android.library'
}
android {
compileSdkVersion rootProject.ext.compileSdkVersion
defaultConfig {
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 1
versionName "1.0"
multiDexEnabled true
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
javaCompileOptions {
annotationProcessorOptions {
arguments = [moduleName: project.getName()]
}
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
// use data binding
dataBinding {
enabled = true
}
// use java 8 language
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
// use external libs folder
sourceSets {
main {
jniLibs.srcDirs = ['libs']
if (isLibraryModuleApp.toBoolean()) {
manifest.srcFile "src/main/debug/AndroidManifest.xml"
} else {
manifest.srcFile "src/main/AndroidManifest.xml"
}
}
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
// router
annotationProcessor 'com.alibaba:arouter-compiler:1.1.4'
// knife
implementation project(':knife-api')
implementation project(':knife-annotation')
annotationProcessor project(':knife-compiler')
// event bus
implementation 'org.greenrobot:eventbus:3.1.1'
// fingerprint
// implementation 'com.wei.android.lib:fingerprintidentify:1.2.1'
// work manager
implementation "android.arch.work:work-runtime:1.0.0-alpha10"
// projects
implementation project(':commons')
}
================================================
FILE: libraries/proguard-rules.pro
================================================
# EventBus
-keepattributes *Annotation*
-keepclassmembers class * {
@org.greenrobot.eventbus.Subscribe ;
}
-keep enum org.greenrobot.eventbus.ThreadMode { *; }
# Only required if you use AsyncExecutor
-keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
(java.lang.Throwable);
}
================================================
FILE: libraries/src/main/AndroidManifest.xml
================================================
================================================
FILE: libraries/src/main/debug/AndroidManifest.xml
================================================
================================================
FILE: libraries/src/main/java/me/shouheng/libraries/FingerprintIdentifyActivity.java
================================================
package me.shouheng.libraries;
import android.os.Bundle;
import com.alibaba.android.arouter.facade.annotation.Route;
//import com.wei.android.lib.fingerprintidentify.FingerprintIdentify;
//import com.wei.android.lib.fingerprintidentify.base.BaseFingerprint;
import me.shouheng.commons.config.BaseConstants;
import me.shouheng.commons.view.activity.CommonActivity;
import me.shouheng.libraries.databinding.ActivityFingerprintIdentifyBinding;
/**
* TODO need to handle this problem by downloading the library and automatically migrate to AndroidX
*
* @author shouh
* @version $Id: FingerprintIdentifyActivity, v 0.1 2018/8/25 14:45 shouh Exp$
*/
@Route(path = BaseConstants.LIBRARY_FINGERPRIINT_IDENTIFY)
public class FingerprintIdentifyActivity extends CommonActivity {
// private FingerprintIdentify mFingerprintIdentify;
private static final int MAX_AVAILABLE_TIMES = 5;
@Override
protected int getLayoutResId() {
return R.layout.activity_fingerprint_identify;
}
@Override
protected void doCreateView(Bundle savedInstanceState) {
// long time = System.currentTimeMillis();
// mFingerprintIdentify = new FingerprintIdentify(getApplicationContext(), exception ->
// append("\nException:" + exception.getLocalizedMessage()));
// append("\ninitialize cost " + (System.currentTimeMillis() - time) + " ms");
// append("\nisHardwareEnable() " + mFingerprintIdentify.isHardwareEnable());
// append("\nisRegisteredFingerprint() " + mFingerprintIdentify.isRegisteredFingerprint());
// append("\nisFingerprintEnable() " + mFingerprintIdentify.isFingerprintEnable());
//
// if (!mFingerprintIdentify.isFingerprintEnable()) {
// append("\nfingerprint not support");
// return;
// }
// append("\nCLICK IDENTIFY BUTTON TO START!");
//
// getBinding().btnIdentify.setOnClickListener(v -> startIdentify());
}
// private void startIdentify() {
// append("\nIDENTIFY START!");
// mFingerprintIdentify.startIdentify(MAX_AVAILABLE_TIMES, new BaseFingerprint.FingerprintIdentifyListener() {
// @Override
// public void onSucceed() {
// append("\nonSucceed");
// }
//
// @Override
// public void onNotMatch(int availableTimes) {
// append("\nonNotMatch : availableTimes = " + availableTimes);
// }
//
// @Override
// public void onFailed(boolean isDeviceLocked) {
// append("\nonFailed : isDeviceLocked = " + isDeviceLocked);
// }
//
// @Override
// public void onStartFailedByDeviceLocked() {
// append("\nonStartFailedByDeviceLocked");
// }
// });
// }
// private void append(String msg) {
// getBinding().tvResult.append(msg);
// }
}
================================================
FILE: libraries/src/main/java/me/shouheng/libraries/MenuActivity.java
================================================
package me.shouheng.libraries;
import android.os.Bundle;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.widget.Toolbar;
import android.view.MenuItem;
import android.view.View;
import com.alibaba.android.arouter.facade.annotation.Route;
import com.alibaba.android.arouter.launcher.ARouter;
import java.util.Calendar;
import java.util.Date;
import me.shouheng.commons.config.BaseConstants;
import me.shouheng.commons.tools.ToastUtils;
import me.shouheng.commons.view.activity.CommonActivity;
import me.shouheng.libraries.databinding.ActivityMenuBinding;
import me.shouheng.libraries.serial.SerializeActivity;
@Route(path = BaseConstants.LIBRARY_MENU)
public class MenuActivity extends CommonActivity {
@Override
protected int getLayoutResId() {
return R.layout.activity_menu;
}
@Override
protected void doCreateView(Bundle savedInstanceState) {
configToolbar();
getBinding().bntEventBus.setOnClickListener(v ->
ARouter.getInstance()
.build(BaseConstants.LIBRARY_EVENT_BUS_ACTIVITY1)
.navigation());
getBinding().btnRxjava.setOnClickListener(v ->
ARouter.getInstance()
.build(BaseConstants.LIBRARY_RX_JAVA)
.navigation());
getBinding().btnClip.setOnClickListener(v ->
ARouter.getInstance()
.build(BaseConstants.LIBRARY_CLIP_PIC)
.navigation());
getBinding().btnTimber.setOnClickListener(v ->
ARouter.getInstance()
.build(BaseConstants.LIBRARY_TIMBER)
.navigation());
getBinding().btnMyKnife.setOnClickListener(v ->
ARouter.getInstance()
.build(BaseConstants.LIBRARY_MY_KNIFE)
.navigation());
getBinding().btnFingerprint.setOnClickListener(v ->
ARouter.getInstance()
.build(BaseConstants.LIBRARY_FINGERPRIINT_IDENTIFY)
.navigation());
getBinding().btnWorkManager.setOnClickListener(v ->
ARouter.getInstance()
.build(BaseConstants.LIBRARY_WORK_MANAGER)
.navigation());
SerializeActivity.Monster monster = new SerializeActivity.Monster("Monster01", 1,
new SerializeActivity.Weapon("Weapon01"), new Date(), new SerializeActivity.Grade(1));
getBinding().btnSerial.setOnClickListener(v ->
ARouter.getInstance()
.build(BaseConstants.LIBRARY_SERIAL)
.withParcelable(BaseConstants.LIBRARY_SERIAL_ARG_MONSTER, monster)
.navigation());
getBinding().btnHandler.setOnClickListener(v ->
ARouter.getInstance()
.build(BaseConstants.LIBRARY_HANDLER)
.navigation());
getBinding().btnTimeZone.setOnClickListener(v -> {
Calendar cal = Calendar.getInstance();
int offset = cal.get(Calendar.ZONE_OFFSET);
ToastUtils.makeToast(String.valueOf(offset / 3600000));
});
}
public void imageCompress(View view) {
ARouter.getInstance()
.build(BaseConstants.LIBRARY_COMPRESS)
.navigation();
}
private void configToolbar() {
Toolbar toolbar = getBinding().barLayout.toolbar;
toolbar.setBackgroundResource(R.color.light_theme_background);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setTitle(R.string.menu_item_title_4);
actionBar.setSubtitle(R.string.menu_item_desc_4);
actionBar.setDisplayHomeAsUpEnabled(true);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
super.onBackPressed();
break;
}
return super.onOptionsItemSelected(item);
}
}
================================================
FILE: libraries/src/main/java/me/shouheng/libraries/ModuleLibraryApp.java
================================================
package me.shouheng.libraries;
import com.alibaba.android.arouter.launcher.ARouter;
import me.shouheng.commons.BaseApplication;
/**
* @author shouh
* @version $Id: ModuleGuokrApp, v 0.1 2018/6/6 22:30 shouh Exp$
*/
public class ModuleLibraryApp extends BaseApplication {
private static ModuleLibraryApp application;
public static ModuleLibraryApp getContext() {
return application;
}
@Override
public void onCreate() {
super.onCreate();
application = this;
ARouter.init(this);
}
}
================================================
FILE: libraries/src/main/java/me/shouheng/libraries/MyKnifeActivity.java
================================================
package me.shouheng.libraries;
import android.os.Bundle;
import android.widget.TextView;
import com.alibaba.android.arouter.facade.annotation.Route;
import me.shouheng.commons.config.BaseConstants;
import me.shouheng.commons.tools.ToastUtils;
import me.shouheng.commons.view.activity.CommonActivity;
import me.shouheng.knife.api.MyKnife;
import me.shouheng.libraries.databinding.ActivityMyKnifeBinding;
/**
* @Warn Test my knife activity, delete the annotations if you set this module as lib instead of application. */
@Route(path = BaseConstants.LIBRARY_MY_KNIFE)
public class MyKnifeActivity extends CommonActivity {
// @BindView(id = R.id.tv)
public TextView textView;
// @OnClick(ids = {R.id.btn})
public void OnClick() {
ToastUtils.makeToast("OnClick");
}
@Override
protected int getLayoutResId() {
return R.layout.activity_my_knife;
}
@Override
protected void doCreateView(Bundle savedInstanceState) {
MyKnife.bind(this);
textView.setText("This is MyKnife demo!");
}
}
================================================
FILE: libraries/src/main/java/me/shouheng/libraries/TimberActivity.java
================================================
package me.shouheng.libraries;
import android.os.Bundle;
import com.alibaba.android.arouter.facade.annotation.Route;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
import me.shouheng.commons.config.BaseConstants;
import me.shouheng.commons.view.activity.CommonActivity;
import me.shouheng.libraries.databinding.ActivityTimberBinding;
import timber.log.Timber;
@Route(path = BaseConstants.LIBRARY_TIMBER)
public class TimberActivity extends CommonActivity {
@Override
protected int getLayoutResId() {
return R.layout.activity_timber;
}
@Override
protected void doCreateView(Bundle savedInstanceState) {
getBinding().btnLogV.setOnClickListener(v -> Timber.v(getBinding().et.getText().toString()));
getBinding().btnLogD.setOnClickListener(v -> Timber.d(getBinding().et.getText().toString()));
getBinding().btnLogE.setOnClickListener(v -> Timber.e(getBinding().et.getText().toString()));
getBinding().btnLogW.setOnClickListener(v -> Timber.w(getBinding().et.getText().toString()));
getBinding().btnLogDate.setOnClickListener(v ->
Timber.d("当前时间: %s", new SimpleDateFormat("YYYY-MM-dd", Locale.getDefault()).format(new Date())));
}
}
================================================
FILE: libraries/src/main/java/me/shouheng/libraries/eventbus/EventBusActivity1.java
================================================
package me.shouheng.libraries.eventbus;
import android.os.Bundle;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.widget.Toolbar;
import android.view.MenuItem;
import com.alibaba.android.arouter.facade.annotation.Route;
import com.alibaba.android.arouter.launcher.ARouter;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import me.shouheng.commons.config.BaseConstants;
import me.shouheng.commons.view.activity.CommonActivity;
import me.shouheng.libraries.R;
import me.shouheng.libraries.databinding.ActivityEventBus1Binding;
@Route(path = BaseConstants.LIBRARY_EVENT_BUS_ACTIVITY1)
public class EventBusActivity1 extends CommonActivity {
private boolean stopDelivery = false;
@Override
protected int getLayoutResId() {
return R.layout.activity_event_bus1;
}
@Override
protected void doCreateView(Bundle savedInstanceState) {
configToolbar();
getBinding().btnReg.setOnClickListener(v ->
EventBus.getDefault().register(this));
getBinding().btnNav2.setOnClickListener( v ->
ARouter.getInstance()
.build(BaseConstants.LIBRARY_EVENT_BUS_ACTIVITY2)
.navigation());
getBinding().btnStop.setOnClickListener(v -> stopDelivery = true);
}
private void configToolbar() {
Toolbar toolbar = getBinding().barLayout.toolbar;
toolbar.setBackgroundResource(R.color.light_theme_background);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setTitle("EventBus");
actionBar.setSubtitle("Demo activity 1");
actionBar.setDisplayHomeAsUpEnabled(true);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
super.onBackPressed();
break;
}
return super.onOptionsItemSelected(item);
}
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
@Subscribe(threadMode = ThreadMode.POSTING, priority = 0)
public void onGetMessage(MessageWrap message) {
getBinding().tvMessage.setText(message.message);
}
@Subscribe(threadMode = ThreadMode.POSTING, sticky = true, priority = 1)
public void onGetStickyEvent(MessageWrap message) {
String txt = "Sticky event: " + message.message;
getBinding().tvStickyMessage.setText(txt);
if (stopDelivery) {
EventBus.getDefault().cancelEventDelivery(message);
}
}
}
================================================
FILE: libraries/src/main/java/me/shouheng/libraries/eventbus/EventBusActivity2.java
================================================
package me.shouheng.libraries.eventbus;
import android.os.Bundle;
import androidx.appcompat.app.ActionBar;
import androidx.appcompat.widget.Toolbar;
import android.view.MenuItem;
import com.alibaba.android.arouter.facade.annotation.Route;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import me.shouheng.commons.config.BaseConstants;
import me.shouheng.commons.tools.ToastUtils;
import me.shouheng.commons.view.activity.CommonActivity;
import me.shouheng.libraries.R;
import me.shouheng.libraries.databinding.ActivityEventBus2Binding;
@Route(path = BaseConstants.LIBRARY_EVENT_BUS_ACTIVITY2)
public class EventBusActivity2 extends CommonActivity {
@Override
protected int getLayoutResId() {
return R.layout.activity_event_bus2;
}
@Override
protected void doCreateView(Bundle savedInstanceState) {
configToolbar();
EventBus.getDefault().register(this);
getBinding().btnPublish.setOnClickListener(v -> publishContent());
getBinding().btnPublishAndFinish.setOnClickListener(v -> {
publishContent();
finish();
});
getBinding().btnPublishSticky.setOnClickListener(v -> publishStickyontent());
}
private void publishContent() {
String msg = getBinding().etMessage.getText().toString();
EventBus.getDefault().post(MessageWrap.getInstance(msg));
ToastUtils.makeToast("Published : " + msg);
}
private void publishStickyontent() {
String msg = getBinding().etMessage.getText().toString();
EventBus.getDefault().postSticky(MessageWrap.getInstance(msg));
ToastUtils.makeToast("Published : " + msg);
}
private void configToolbar() {
Toolbar toolbar = getBinding().barLayout.toolbar;
toolbar.setBackgroundResource(R.color.light_theme_background);
setSupportActionBar(toolbar);
ActionBar actionBar = getSupportActionBar();
if (actionBar != null) {
actionBar.setTitle("EventBus");
actionBar.setSubtitle("Demo activity 2");
actionBar.setDisplayHomeAsUpEnabled(true);
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
super.onBackPressed();
break;
}
return super.onOptionsItemSelected(item);
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onGetMessage(MessageWrap message) {
getBinding().tvMessage.setText(message.message);
}
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
}
================================================
FILE: libraries/src/main/java/me/shouheng/libraries/eventbus/MessageWrap.java
================================================
package me.shouheng.libraries.eventbus;
/**
* @author shouh
* @version $Id: MessageWrap, v 0.1 2018/8/5 15:18 shouh Exp$
*/
public class MessageWrap {
public final String message;
public static MessageWrap getInstance(String message) {
return new MessageWrap(message);
}
private MessageWrap(String message) {
this.message = message;
}
}
================================================
FILE: libraries/src/main/java/me/shouheng/libraries/handler/FileRecognizeTask.java
================================================
package me.shouheng.libraries.handler;
import android.app.IntentService;
import android.content.Context;
import android.content.Intent;
import me.shouheng.commons.tools.LogUtils;
/**
* @author shouh
* @version $Id: FileRecognizeTask, v 0.1 2018/11/4 23:40 shouh Exp$
*/
public class FileRecognizeTask extends IntentService {
public static void start(Context context) {
Intent intent = new Intent(context, FileRecognizeTask.class);
context.startService(intent);
}
public FileRecognizeTask() {
super("FileRecognizeTask");
}
@Override
protected void onHandleIntent(@androidx.annotation.Nullable Intent intent) {
// do something
LogUtils.d("=========================================");
}
}
================================================
FILE: libraries/src/main/java/me/shouheng/libraries/handler/HandlerActivity.java
================================================
package me.shouheng.libraries.handler;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import com.alibaba.android.arouter.facade.annotation.Route;
import me.shouheng.commons.config.BaseConstants;
import me.shouheng.commons.tools.LogUtils;
import me.shouheng.commons.view.activity.CommonActivity;
import me.shouheng.libraries.R;
import me.shouheng.libraries.databinding.ActivityHandlerBinding;
/**
* Created by WngShhng on 2018/11/1.
*/
@Route(path = BaseConstants.LIBRARY_HANDLER)
public class HandlerActivity extends CommonActivity {
private final static int SAY_HELLO = 1;
private static Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case SAY_HELLO:
LogUtils.d("Hello!");
break;
}
}
};
@Override
protected int getLayoutResId() {
return R.layout.activity_handler;
}
@Override
protected void doCreateView(Bundle savedInstanceState) {
LogUtils.d("========开始一个任务,将在2秒之后执行========");
new Handler().postDelayed(() -> LogUtils.d("========任务开始执行========"), 2000);
LogUtils.d("=========开始一个线程========");
new Thread(() -> {
try {
// new Handler(); // 会因为该线程中没有对应的 Looper 而发生异常
Thread.sleep(2000);
new Handler(Looper.getMainLooper())
.post(() -> getBinding().tv.setText("任务执行完毕,主线程更新UI"));
// handler.post(() -> getBinding().tv.setText("任务执行完毕,主线程更新UI"));
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
new Thread(() -> {
LogUtils.d("+++++++++" + Thread.currentThread());
Looper.prepare();
new Handler().post(() -> LogUtils.d("+++++++++" + Thread.currentThread()));
Looper.loop();
}).start();
Message message = Message.obtain(handler);
message.what = SAY_HELLO;
message.sendToTarget();
// or below
// Message message = Message.obtain();
// message.what = SAY_HELLO;
// handler.sendMessage(message);
// HandlerThread demo
HandlerThread handlerThread = new HandlerThread("MyHandlerThread");
handlerThread.start();
// IntentService demo
FileRecognizeTask.start(this);
}
}
================================================
FILE: libraries/src/main/java/me/shouheng/libraries/image/ClipPictureActivity.java
================================================
package me.shouheng.libraries.image;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import com.alibaba.android.arouter.facade.annotation.Route;
import me.shouheng.commons.config.BaseConstants;
import me.shouheng.commons.tools.ToastUtils;
import me.shouheng.commons.view.activity.CommonActivity;
import me.shouheng.libraries.R;
import me.shouheng.libraries.databinding.ActivityClipPictureBinding;
/**
* Created by WngShhng on 2018/8/21.*/
@Route(path = BaseConstants.LIBRARY_CLIP_PIC)
public class ClipPictureActivity extends CommonActivity {
@Override
protected int getLayoutResId() {
return R.layout.activity_clip_picture;
}
@Override
protected void doCreateView(Bundle savedInstanceState) {
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 1;
options.inScaled = false;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.raw.test_pic, options);
ToastUtils.makeToast("w:" + bitmap.getWidth() + " h:" + bitmap.getHeight());
Bitmap cliped = Bitmap.createBitmap(bitmap, 54, 217, 125, 28);
getBinding().ivPic.setImageBitmap(cliped);
}
}
================================================
FILE: libraries/src/main/java/me/shouheng/libraries/image/ImageCompressActivity.java
================================================
package me.shouheng.libraries.image;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.graphics.Matrix;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.util.TypedValue;
import android.view.View;
import com.alibaba.android.arouter.facade.annotation.Route;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import me.shouheng.commons.config.BaseConstants;
import me.shouheng.commons.tools.PalmUtils;
import me.shouheng.commons.tools.ToastUtils;
import me.shouheng.commons.view.activity.CommonActivity;
import me.shouheng.libraries.R;
import me.shouheng.libraries.databinding.ActivityImageCompressBinding;
@Route(path = BaseConstants.LIBRARY_COMPRESS)
public class ImageCompressActivity extends CommonActivity {
private static final String TAG = "ImageCompressActivity";
private static final String COMPRESS_FILE_NAME = "compress.jpg";
private static final String SCALE_COMPRESS_FILE_NAME = "scale_compress.jpg";
@Override
protected int getLayoutResId() {
return R.layout.activity_image_compress;
}
@Override
protected void doCreateView(Bundle savedInstanceState) {
// empty
}
/**
* 临近采样图片压缩
*
* @param view v
* @throws IOException exception
*/
public void compressAlgorithm(View view) throws IOException {
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM), COMPRESS_FILE_NAME);
StringBuilder sb = new StringBuilder(PalmUtils.getStringCompact(R.string.libraries_compress_compress));
sb.append(":\n");
BitmapFactory.Options options = getOriginalOptions(R.raw.ice_land);
sb.append(String.format(PalmUtils.getStringCompact(R.string.libraries_compress_compress_original), options.outWidth, options.outHeight));
sb.append("\n");
// 执行图片压缩:采样率 2,压缩的质量 75
ByteArrayOutputStream stream = new ByteArrayOutputStream();
options.inSampleSize = 2;
options.inJustDecodeBounds = false;
options.inScaled = false; // 需要设置这个参数,那么要根据资源的类型进行判断吗?
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.raw.ice_land, options);
Log.d(TAG, options.outWidth + " " + options.outHeight); // 从这里看的结果确实是加载了一半
Log.d(TAG, bitmap.getWidth() + " " + bitmap.getHeight()); // TODO Error!
bitmap.compress(Bitmap.CompressFormat.JPEG, 75, stream);
Log.d(TAG, bitmap.getWidth() + " " + bitmap.getHeight());
bitmap.recycle();
saveToFileSystem(file, stream); // 最终写出的数据有问题
ToastUtils.makeToast("Success saved to " + file.getPath());
BitmapFactory.Options retOptions = getOriginalOptions(file.getPath());
sb.append(String.format(PalmUtils.getStringCompact(R.string.libraries_compress_compress_result), retOptions.outWidth, retOptions.outHeight));
getBinding().tvDisplay.setText(sb.toString());
}
/**
* 双线性采样
*
* @param view view
* @throws IOException IOException
*/
public void scaleCompressAlgorithm(View view) throws IOException {
File file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM), SCALE_COMPRESS_FILE_NAME);
StringBuilder sb = new StringBuilder(PalmUtils.getStringCompact(R.string.libraries_compress_scale));
sb.append(":\n");
BitmapFactory.Options options = getOriginalOptions(R.raw.ice_land);
int originalWidth = options.outWidth, originalHeight = options.outHeight;
sb.append(String.format(PalmUtils.getStringCompact(R.string.libraries_compress_compress_original), options.outWidth, options.outHeight));
sb.append("\n");
options.inJustDecodeBounds = false;
options.inSampleSize = 2;
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.raw.ice_land, options);
Log.d(TAG, options.outWidth + " " + options.outHeight);
Matrix matrix = new Matrix();
float scale = 1200f / originalWidth;
matrix.setScale(scale, scale);
Bitmap scaledBitmap = Bitmap.createBitmap(bitmap, 0, 0, originalWidth, originalHeight, matrix, true);
saveToFileSystem(file, scaledBitmap);
ToastUtils.makeToast("Success saved to " + file.getPath());
BitmapFactory.Options retOptions = getOriginalOptions(file.getPath());
sb.append(String.format(PalmUtils.getStringCompact(R.string.libraries_compress_compress_result), retOptions.outWidth, retOptions.outHeight));
getBinding().tvDisplay.setText(sb.toString());
}
// region private methods
private BitmapFactory.Options getOriginalOptions(int resId) {
BitmapFactory.Options options = new Options();
options.inJustDecodeBounds = true;
options.inSampleSize = 1;
BitmapFactory.decodeResource(getResources(), resId, options);
return options;
}
private BitmapFactory.Options getOriginalOptions(String saveFilePath) {
BitmapFactory.Options retOptions = new Options();
retOptions.inJustDecodeBounds = true;
retOptions.inSampleSize = 1;
BitmapFactory.decodeFile(saveFilePath, retOptions);
return retOptions;
}
private void saveToFileSystem(File file, ByteArrayOutputStream stream) throws IOException {
OutputStream fos = new FileOutputStream(file);
fos.write(stream.toByteArray());
fos.flush();
fos.close();
stream.close();
}
private void saveToFileSystem(File file, Bitmap bitmap) throws IOException {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream);
saveToFileSystem(file, stream);
}
private Bitmap rotatingImage(Bitmap bitmap, int angle) {
Matrix matrix = new Matrix();
matrix.postRotate(angle);
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
}
// endregion
}
================================================
FILE: libraries/src/main/java/me/shouheng/libraries/rxjava/DemoFragment.java
================================================
package me.shouheng.libraries.rxjava;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import com.alibaba.android.arouter.facade.annotation.Route;
import com.alibaba.android.arouter.launcher.ARouter;
import me.shouheng.commons.config.BaseConstants;
import me.shouheng.commons.tools.LogUtils;
import me.shouheng.commons.view.fragment.CommonFragment;
import me.shouheng.libraries.R;
import me.shouheng.libraries.databinding.FragmentDemoBinding;
/**
* Created by WngShhng on 2018/10/19.
*/
@Route(path = BaseConstants.LIBRARY_FRAGMENT_DEMO)
public class DemoFragment extends CommonFragment {
@Override
protected int getLayoutResId() {
return R.layout.fragment_demo;
}
@Override
protected void doCreateView(Bundle savedInstanceState) {
boolean hasChild = getArguments().getBoolean(BaseConstants.LIBRARY_FRAGMENT_DEMO_HAS_CHILD);
if (hasChild) {
getChildFragmentManager()
.beginTransaction()
.replace(R.id.fragment_container, (Fragment) ARouter.getInstance()
.build(BaseConstants.LIBRARY_FRAGMENT_DEMO)
.withBoolean(BaseConstants.LIBRARY_FRAGMENT_DEMO_HAS_CHILD, false)
.navigation())
.commit();
}
addSubscription(RxMessage.class, rxMessage ->
LogUtils.d("++++++++++++++++++++++ DemoFragment(hasChild:" + hasChild + "): 接受到消息 " + rxMessage.message + "!"));
}
}
================================================
FILE: libraries/src/main/java/me/shouheng/libraries/rxjava/RxBusActivity.java
================================================
package me.shouheng.libraries.rxjava;
import android.os.Bundle;
import com.alibaba.android.arouter.facade.annotation.Route;
import me.shouheng.commons.config.BaseConstants;
import me.shouheng.commons.view.activity.CommonActivity;
import me.shouheng.libraries.R;
import me.shouheng.libraries.databinding.ActivityRxBusBinding;
/**
* Created by WngShhng on 2018/8/17.
*/
@Route(path = BaseConstants.LIBRARY_RX_JAVA_BUS)
public class RxBusActivity extends CommonActivity {
@Override
protected int getLayoutResId() {
return R.layout.activity_rx_bus;
}
@Override
protected void doCreateView(Bundle savedInstanceState) {
getBinding().btnSendEvent.setOnClickListener(v -> {
postEvent(new RxMessage("Hello world!"));
});
}
}
================================================
FILE: libraries/src/main/java/me/shouheng/libraries/rxjava/RxJavaActivity.java
================================================
package me.shouheng.libraries.rxjava;
import android.os.Bundle;
import androidx.fragment.app.Fragment;
import com.alibaba.android.arouter.facade.annotation.Route;
import com.alibaba.android.arouter.launcher.ARouter;
import io.reactivex.Observable;
import io.reactivex.ObservableOnSubscribe;
import me.shouheng.commons.config.BaseConstants;
import me.shouheng.commons.tools.FragmentHelper;
import me.shouheng.commons.tools.LogUtils;
import me.shouheng.commons.tools.ToastUtils;
import me.shouheng.commons.view.activity.CommonActivity;
import me.shouheng.libraries.R;
import me.shouheng.libraries.databinding.ActivityRxjavaBinding;
/**
* @author shouh
* @version $Id: RxJavaActivity, v 0.1 2018/8/7 8:22 shouh Exp$
*/
@Route(path = BaseConstants.LIBRARY_RX_JAVA)
public class RxJavaActivity extends CommonActivity {
@Override
protected int getLayoutResId() {
return R.layout.activity_rxjava;
}
@Override
protected void doCreateView(Bundle savedInstanceState) {
getBinding().btn1.setOnClickListener(v ->
Observable.create((ObservableOnSubscribe) emitter -> {
String str = getBinding().et.getText().toString();
emitter.onNext(str);
// emitter.onError(new Exception("Exception"));
// emitter.onComplete();
}).subscribe(ToastUtils::makeToast));
getBinding().btn2.setOnClickListener(v -> Observable.just(1,2,3,4).subscribe(LogUtils::d));
getBinding().btnRxBus.setOnClickListener(v ->
ARouter.getInstance()
.build(BaseConstants.LIBRARY_RX_JAVA_BUS)
.navigation());
addSubscription(RxMessage.class, rxMessage -> {
ToastUtils.makeToast(rxMessage.message);
LogUtils.d("++++++++++++++++++++++ RxJavaActivity: 接受到消息 " + rxMessage.message + "!");
});
FragmentHelper.replace(this,
(Fragment) ARouter.getInstance()
.build(BaseConstants.LIBRARY_FRAGMENT_DEMO)
.withBoolean(BaseConstants.LIBRARY_FRAGMENT_DEMO_HAS_CHILD, true)
.navigation(),
R.id.fragment_container);
}
}
================================================
FILE: libraries/src/main/java/me/shouheng/libraries/rxjava/RxMessage.java
================================================
package me.shouheng.libraries.rxjava;
/**
* Created by WngShhng on 2018/8/17.*/
public class RxMessage {
public final String message;
RxMessage(String message) {
this.message = message;
}
}
================================================
FILE: libraries/src/main/java/me/shouheng/libraries/serial/SerializeActivity.java
================================================
package me.shouheng.libraries.serial;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import com.alibaba.android.arouter.facade.annotation.Route;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import me.shouheng.commons.config.BaseConstants;
import me.shouheng.commons.view.activity.CommonActivity;
import me.shouheng.libraries.R;
import me.shouheng.libraries.databinding.ActivitySerializeBinding;
import timber.log.Timber;
/**
* @author shouh
* @version $Id: SerializeActivity, v 0.1 2018/10/21 17:58 shouh Exp$
*/
@Route(path = BaseConstants.LIBRARY_SERIAL)
public class SerializeActivity extends CommonActivity {
@Override
protected int getLayoutResId() {
return R.layout.activity_serialize;
}
@Override
protected void doCreateView(Bundle savedInstanceState) {
/*----------------------------------Serializable-------------------------------------*/
SerializeUtils.setStudent(new Student("Student.01",
12,
new Role("Role01"),
() -> "do whatever"));
Student student = SerializeUtils.getStudent();
assert student != null;
String strStu = student.toString() + "\n\n" + student.i.doSomething();
getBinding().tvStudent.setText(strStu);
/*----------------------------------------Parcelable--------------------------------------------*/
Monster monster = getIntent().getParcelableExtra(BaseConstants.LIBRARY_SERIAL_ARG_MONSTER);
getBinding().tvMonster.setText(monster.toString());
}
public static class Student implements Serializable {
final String name;
final int age;
/**
* 内部的字段也应该实现序列化接口,才能进行正确序列化
*/
final Role role;
/**
* 接口也必须实现 Serializable 接口
*/
final IInterface i;
public Student(String name, int age, Role role, IInterface i) {
this.name = name;
this.age = age;
this.role = role;
this.i = i;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", role=" + role +
'}';
}
}
public static class Role implements Serializable {
final String name;
public Role(String name) {
this.name = name;
}
@Override
public String toString() {
return "Role{" +
"name='" + name + '\'' +
'}';
}
}
public interface IInterface extends Serializable {
String doSomething();
}
// region 直接使用接口的实现方式
/*
public static class Monster implements Parcelable {
final String name;
final int age;
final Weapon weapon;
final Date birthday;
public Monster(String name, int age, Weapon weapon, Date birthday) {
this.name = name;
this.age = age;
this.weapon = weapon;
this.birthday = birthday;
}
Monster(Parcel in) {
name = in.readString();
age = in.readInt();
weapon = in.readParcelable(Weapon.class.getClassLoader());
birthday = (Date) in.readSerializable();
}
public static final Creator CREATOR = new Creator() {
@Override
public Monster createFromParcel(Parcel in) {
return new Monster(in);
}
@Override
public Monster[] newArray(int size) {
return new Monster[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
dest.writeInt(age);
dest.writeParcelable(weapon, 0);
dest.writeSerializable(birthday);
}
@Override
public String toString() {
return "Monster{" +
"name='" + name + '\'' +
", age=" + age +
", weapon=" + weapon +
", birthday=" + birthday +
'}';
}
}
public static class Weapon implements Parcelable {
final String name;
public Weapon(String name) {
this.name = name;
}
Weapon(Parcel in) {
name = in.readString();
}
public static final Creator CREATOR = new Creator() {
@Override
public Weapon createFromParcel(Parcel in) {
return new Weapon(in);
}
@Override
public Weapon[] newArray(int size) {
return new Weapon[size];
}
};
@Override
public String toString() {
return "Weapon{" +
"name='" + name + '\'' +
'}';
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeString(name);
}
}
*/
// endregion
public static class Monster extends BaseParcelable {
public static final Creator CREATOR = CreatorFactory.getCreator(Monster.class);
String name;
int age;
Weapon weapon;
Date birthday;
Grade grade;
public Monster(String name, int age, Weapon weapon, Date birthday, Grade grade) {
this.name = name;
this.age = age;
this.weapon = weapon;
this.birthday = birthday;
this.grade = grade;
}
public Monster(Parcel in) {
super(in);
}
@Override
public String toString() {
return "Monster{" +
"name='" + name + '\'' +
", age=" + age +
", weapon=" + weapon +
", birthday=" + birthday +
", grade=" + grade +
"}";
}
}
public static class Weapon extends BaseParcelable {
public static final Creator CREATOR = CreatorFactory.getCreator(Weapon.class);
String name;
public Weapon(String name) {
this.name = name;
}
/**
* 需要时 public 的,并且字段不能是 final 的
*
* @param in
*/
public Weapon(Parcel in) {
super(in);
}
@Override
public String toString() {
return "Weapon{" +
"name='" + name + '\'' +
'}';
}
}
public static class Grade {
int grade;
public Grade(int grade) {
this.grade = grade;
}
@Override
public String toString() {
return "Grade{" +
"grade=" + grade +
'}';
}
}
// TODO There are many available methods for simplifying the usage of Parcelable, most are implemented by auto-generating codes
public static abstract class BaseParcelable implements Parcelable {
protected BaseParcelable() { }
protected BaseParcelable(Parcel in) {
// TODO 父类中的字段
Field[] fields = getClass().getDeclaredFields();
Class> fieldType;
CreatorFactory.TypeHandler> typeHandler;
try {
for (Field field : fields) {
fieldType = field.getType();
/*------------------------------使用类型处理器---------------------------------*/
if ((typeHandler = CreatorFactory.handlerMap.get(fieldType)) != null) {
field.set(this, typeHandler.read(in));
continue;
}
/*------------------------------默认数据类型--------------------------------*/
if (fieldType == String.class) {
field.set(this, in.readString());
} else if (fieldType == byte.class || fieldType == Byte.class) {
field.set(this, in.readByte());
} else if (fieldType == short.class || fieldType == Short.class) {
field.set(this, in.readInt());
} else if (fieldType == int.class || fieldType == Integer.class) {
field.set(this, in.readInt());
} else if (fieldType == long.class || fieldType == Long.class) {
field.set(this, in.readLong());
} else if (fieldType == float.class || fieldType == Float.class) {
field.set(this, in.readFloat());
} else if (fieldType == double.class || fieldType == Double.class) {
field.set(this, in.readDouble());
} else if (fieldType == boolean.class || fieldType == Boolean.class) {
field.set(this, in.readInt() == 1);
} else if (Serializable.class.isAssignableFrom(fieldType)) {
field.set(this, in.readSerializable());
} else if (Parcelable.class.isAssignableFrom(fieldType)) {
field.set(this, in.readParcelable(fieldType.getClassLoader()));
}
}
} catch (IllegalAccessException e) {
Timber.e(e);
}
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
Field[] fields = getClass().getDeclaredFields();
Class> fieldType;
CreatorFactory.TypeHandler