Git Product home page Git Product logo

loadsir's Introduction

中文 | English

LoadSir

👉👈

LoadSir是一个高效易用,低碳环保,扩展性良好的加载反馈页管理框架,在加载网络或其他数据时候,根据需求切换状态页面, 可添加自定义状态页面,如加载中,加载失败,无数据,网络超时,如占位图,登录失效等常用页面。可配合网络加载框架,结合返回 状态码,错误码,数据进行状态页自动切换,封装使用效果更佳。

使用场景

in Activity in View in Fragment
Placeholder Muitl-Fragment ViewPage+Fragment

下载 Demo

(密码:9517)

流程图

LoadSir的功能及特点

  • ⭐支持Activity,Fragment,Fragment(v4),View状态回调
  • ⭐适配多个Fragment切换,及Fragment+ViewPager切换,不会布局叠加或者布局错乱
  • ⭐利用泛型转换输入信号和输出状态,可根据网络返回体的状态码或者数据返回自动适配状态页,实现全局自动状态切换
  • ⭐无需修改布局文件
  • ⭐只加载唯一一个状态视图,不会预加载全部视图
  • ⭐不需要设置枚举或者常量状态值,直接用状态页类类型(xxx.class)作为状态码
  • ⭐可对单个状态页单独设置点击事件,根据返回boolean值覆盖或者结合OnReloadListener使用,如网络错误可跳转设置页
  • ⭐无预设页面,低耦合,开发者随心配置
  • ⭐可保留标题栏(Toolbar,titile view等)
  • 可设置重新加载点击事件(OnReloadListener)
  • 可自定义状态页(继承Callback类)
  • 可在子线程直接切换状态
  • 可设置初始状态页(常用进度页作为初始状态)
  • 可扩展状态页面,在配置中添加自定义状态页
  • 可全局单例配置,也可以单独配置

开始使用LoadSir

LoadSir的使用,只需要简单的三步

添加依赖

compile 'com.kingja.loadsir:loadsir:1.3.8'

第一步:配置

全局配置方式

全局配置方式,使用的是单例模式,即获取的配置都是一样的。可在Application中配置,添加状态页,设置默认状态页

public class App extends Application {
    @Override
    public void onCreate() {
        super.onCreate();
        LoadSir.beginBuilder()
                .addCallback(new ErrorCallback())//添加各种状态页
                .addCallback(new EmptyCallback())
                .addCallback(new LoadingCallback())
                .addCallback(new TimeoutCallback())
                .addCallback(new CustomCallback())
                .setDefaultCallback(LoadingCallback.class)//设置默认状态页
                .commit();
    }
}
单独配置方式

如果你即想保留全局配置,又想在某个特殊页面加点不同的配置,可采用该方式。

LoadSir loadSir = new LoadSir.Builder()
                .addCallback(new LoadingCallback())
                .addCallback(new EmptyCallback())
                .addCallback(new ErrorCallback())
                .build();
        loadService = loadSir.register(this, new Callback.OnReloadListener() {
            @Override
            public void onReload(View v) {
                // 重新加载逻辑
            }
        });

第二步:注册

在Activity中使用
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_content);
    // Your can change the callback on sub thread directly.
    LoadService loadService = LoadSir.getDefault().register(this, new Callback.OnReloadListener() {
        @Override
        public void onReload(View v) {
            // 重新加载逻辑
        }
    });
}}
在View 中使用
ImageView imageView = (ImageView) findViewById(R.id.iv_img);
LoadSir loadSir = new LoadSir.Builder()
        .addCallback(new TimeoutCallback())
        .setDefaultCallback(LoadingCallback.class)
        .build();
loadService = loadSir.register(imageView, new Callback.OnReloadListener() {
    @Override
    public void onReload(View v) {
        loadService.showCallback(LoadingCallback.class);
        // 重新加载逻辑
    }
});
Ps:
[1]要注册RelativeLayoutConstraintLayout的子View,如果该子View被其它子View约束,建议在子View外层再包层布局,参考
acitivy_view.xmactivity_constraintlayout.xml
在Fragment 中使用

由于Fragment添加到Activitiy方式多样,比较特别,所以在Fragment注册方式不同于上面两种,大家先看模板代码:

@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle
        savedInstanceState) {
    //第一步:获取布局View
    rootView = View.inflate(getActivity(), R.layout.fragment_a_content, null);
    //第二步:注册布局View
    LoadService loadService = LoadSir.getDefault().register(rootView, new Callback.OnReloadListener() {
        @Override
        public void onReload(View v) {
            // 重新加载逻辑
        }
    });
    //第三步:返回LoadSir生成的LoadLayout
    return loadService.getLoadLayout();
}

第三步: 回调

直接回调
protected void loadNet() {
        // 进行网络访问...
        // 进行回调
        loadService.showSuccess();//成功回调
        loadService.showCallback(EmptyCallback.class);//其他回调
    }
转换器回调 (推荐使用)

如果你不想再每次回调都要手动进行的话,可以选择注册的时候加入转换器,可根据返回的数据,适配对应的状态页。

LoadService loadService = LoadSir.getDefault().register(this, new Callback.OnReloadListener() {
    @Override
    public void onReload(View v) {
            // 重新加载逻辑
    }}, new Convertor<HttpResult>() {
    @Override
    public Class<? extends Callback> map(HttpResult httpResult) {
        Class<? extends Callback> resultCode = SuccessCallback.class;
        switch (httpResult.getResultCode()) {
            case SUCCESS_CODE://成功回调
                if (httpResult.getData().size() == 0) {
                    resultCode = EmptyCallback.class;
                }else{
                    resultCode = SuccessCallback.class;
                }
                break;
            case ERROR_CODE:
                resultCode = ErrorCallback.class;
                break;
        }
        return resultCode;
    }
});

回调的时候直接传入转换器指定的数据类型。

loadService.showWithConvertor(httpResult);

自定义回调页

LoadSir为了完全解耦,没有预设任何状态页,需要自己实现,开发者自定义自己的回调页面,比如加载中,没数据,错误,超时等常用页面, 设置布局及自定义点击逻辑

public class CustomCallback extends Callback {

    //填充布局
    @Override
    protected int onCreateView() {
        return R.layout.layout_custom;
    }
    //当前Callback的点击事件,如果返回true则覆盖注册时的onReloa(),如果返回false则两者都执行,先执行onReloadEvent()。
    @Override
    protected boolean onReloadEvent(final Context context, View view) {
        Toast.makeText(context.getApplicationContext(), "Hello buddy! :p", Toast.LENGTH_SHORT).show();
        (view.findViewById(R.id.iv_gift)).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(context.getApplicationContext(), "It's your gift! :p", Toast.LENGTH_SHORT).show();
            }
        });
        return true;
    }

    //是否在显示Callback视图的时候显示原始图(SuccessView),返回true显示,false隐藏
    @Override
    public boolean getSuccessVisible() {
        return super.getSuccessVisible();
    }

    //将Callback添加到当前视图时的回调,View为当前Callback的布局View
    @Override
    public void onAttach(Context context, View view) {
        super.onAttach(context, view);
    }

    //将Callback从当前视图删除时的回调,View为当前Callback的布局View
    @Override
    public void onDetach() {
        super.onDetach(context, view);
    }

}

动态修改Callback

loadService = LoadSir.getDefault().register(...);
loadService.setCallBack(EmptyCallback.class, new Transport() {
   @Override
   public void order(Context context, View view) {
       TextView mTvEmpty = (TextView) view.findViewById(R.id.tv_empty);
       mTvEmpty.setText("fine, no data. You must fill it!");
   }
});

LoadSir自带便携式Callback

ProgressCallback loadingCallback = new ProgressCallback.Builder()
        .setTitle("Loading", R.style.Hint_Title)
        .build();

HintCallback hintCallback = new HintCallback.Builder()
        .setTitle("Error", R.style.Hint_Title)
        .setSubTitle("Sorry, buddy, I will try it again.")
        .setHintImg(R.drawable.error)
        .build();

LoadSir loadSir = new LoadSir.Builder()
        .addCallback(loadingCallback)
        .addCallback(hintCallback)
        .setDefaultCallback(ProgressCallback.class)
        .build();

在使用过程中,遇到问题可以先去FAQ和Issues看看有没解决方案,如果没有的话,请给我提Issue吧。

💡 About placeholder effect

placeholder效果状态页类似ShimmerRecyclerView的效果. LoadSir只用了一个 自定义状态页PlaceHolderCallback就完成类似的效果,是不是很棒 👻

Docs

代码混淆

-dontwarn com.kingja.loadsir.**
-keep class com.kingja.loadsir.** {*;}

Contact Me

Any questions,Welcome to contact me.

License

Copyright 2017 KingJA

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

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

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

loadsir's People

Contributors

jalajaj avatar kingja avatar rainer-lang avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

loadsir's Issues

在使用的过程中会报错:An instance of OnFlingListener already set“”

loadService = LoadSir.getDefault().register(this, new Callback.OnReloadListener() {
@OverRide
public void onReload(View v) {
// Your can change the status out of Main thread.
new Thread(new Runnable() {
@OverRide
public void run() {
loadService.showCallback(LoadingCallback.class);
//do retry logic...
SystemClock.sleep(500);

                    //增加这一段即可
                    if(recyclerView.getOnFlingListener() != null){
                        recyclerView.setOnFlingListener(null);
                    }

                    //callback
                    loadService.showSuccess();
                }
            }).start();
        }
    });
    PostUtil.postCallbackDelayed(loadService,EmptyCallback.class);

当在Application里面不用默认的Loading状态时,用ViewPager加载多个fragment,每切换一个Fragment显示Loading状态,此时加载Loading那个圈很卡。

在Application里面注释掉
LoadSir.beginBuilder()
.addCallback(new ErrorCallback())
.addCallback(new EmptyCallback())
.addCallback(new LoadingCallback())
.addCallback(new TimeoutCallback())
.addCallback(new CustomCallback())
// .setDefaultCallback(LoadingCallback.class)
.commit();
FragmentA
@OverRide
public void loadNet() {
PostUtil.postCallbackDelayed(mBaseLoadService, LoadingCallback.class);
}
FragmentB
@OverRide
public void loadNet() {
PostUtil.postCallbackDelayed(mBaseLoadService, LoadingCallback.class);
}

请问activity可以像fragment那样把title放出来么

您当时说抽出来放在基类,是可以实现,但是我的基类里面已经有这些方法了,有的时候,动态添加View,太容易报错了,出现异常,有没有别的办法实现呢,简单点的,
有些地方我的最外层布局是一些特殊的布局,
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
FrameLayout.LayoutParams.MATCH_PARENT);

您这个方法又强制的改了我的最外层布局,我不想改布局呢

有一些问题,removeAllViews(); 导致 IllegalStateException

image

代码结构:
在Activity:
顺序

LoadSir loadSir = new LoadSir.Builder();
loadService = loadSir.register();

initRefreshLayout();
initRectclerView();
initAdapter();
loadData();//加载数据

其中

mRefreshLayout.setOnRefreshListener() 调用 loadData();

loadData()方法里,有 onSuccess - >在其中做了下列方法

if(responesList.siez()==0) {

 PostUtil.postCallbackDelayed(loadService, ErrorCallback.class);

} else {

mlist.clear();
mlist.addAll(responesList);

mAdapter.notifyDataSetChanged();

mRefreshLayout.setRefreshing(false);

mRecyclerView.loadMoreFinish(false, true);

loadService.showSuccess();
}

在Activity顺序执行: loadData()==成功
在下拉刷新 第一次: loadData()==成功
在下拉刷新 第二次: loadData()==失败报错

LoadSirHintCallback报错

hi,你好。LoadSirHintCallback这块好像有些变量啥的没有序列化,然后报错了。在demo,default LoadSir Callback这块

导入依赖出错

Error:Execution failed for task ':app:processDebugManifest'.

Manifest merger failed : Attribute application@label value=(@string/app_name) from AndroidManifest.xml:28:9-41
is also present at [com.kingja.loadsir:loadsir:1.2.2] AndroidManifest.xml:13:9-32 value=(LoadSir).
Suggestion: add 'tools:replace="android:label"' to element at AndroidManifest.xml:24:5-61:19 to override.

add 'tools:replace="android:label"'在清单文件

@Chinese people: Could you please write in English

I really would like to understand what's going on.... I'm very interested in this lib and I want to learn what I could do with it - and maybe I also could learn from your questions and ideas - or answer them in future.

If possible it would be really kind of you to write in English.
Thanks.

Suggestions for "Best Practice"

state: 27.09.2017 - PM 2:39 CEST

Only a collection of libs which could maybe used with LoadSir. I think it could be good to have examples for each of this use-cases.

For each use case I would suggest to make a separate activity in the sample app.

I will continue this list...

@KingJA Is this ok for you?

能把leakcanary集成去掉吗?

我也导入了leakcanary,然后我把自己导入的删掉后可以运行了,但是发现想用leakcanary还是用不了....
还要重新导入,陷入了死循环。

文档写的太简略了

正在使用,许多问题并没有讲的很清楚。需要打开代码自己寻找。比如如何做到只遮挡一部分,留出toolbar。文档中没有详讲,会让学习成本增加。

add layout files/items for different states

I think this lib will be used quite for the states loading and showing some error with retry or empty.

Therefore it would be good to add generic layout items for

  • loading (ProgressBar/image, title, text)
  • error (image, title, text, button for retry)
  • empty (image, title, text, button for retry)
    ...of course with Builder pattern. :-)

This would be very convenient.

...and including default Callbacks for these use cases.

关于最新版1.3.0的问题

LoadSir作用在View上时,如果View设置了margin等属性,在LoadSir.showSuccess()后,这些属性会丢失, 1.2.0版本则正常。

提一个建议

在activity中 请求数据为空数据状态 加载回调布局页面会整个铺满屏幕 这样就会导致导航栏的部分被遮住了,最好修改为在导航栏下面

动画怎么添加,

Loading添加动画

loadService = loadSir.register(contentView, new Callback.OnReloadListener() {
@OverRide
public void onReload(View v) {
loadService.showCallback(LoadingCallback.class);
// 重新加载逻辑
}
});

contentView
只能在这里自定义添加动画,假如我每个界面都用loading,每个界面都要从新写一遍吗

是用双层Fragment嵌套时 无法显示布局

如题所示 在使用viewpager作为 主界面容器时 fragment中的子fragment 布局无法显示 , 使用的是全局 LoadSir, 是在子Fragment中实例的 LoadService, 希望作者能解惑。

请教你个问题

你的框架没有看的太明白,如何实现先呈现加载动画,然后判断是否数据为空,为空显示Empty,重现加载数据

To all using LoadSir

If you're using LoadSir in your project/app or with another lib - please feel free to make an issue here.

We would be grateful to add your project in a special section here, or if you would like to make a sample how LoadSir could be used with another lib - please make a PR.

:octocat: 大家好,如果你有在项目中或者其它库中使用LoadSir,欢迎使用issue分享心得。

如果你有关于Loadsir结合其它用库使用或者封装使用的案例并想分享的话,请联系我们或者发起PR。

非常感谢。:ghost:

希望出个MAVEN的release

如果可以出个maven的release,或者出个转换的话,我想我可以把这个jar用到我们的web页面中

线程安全问题?

PostUtil中的几个方法,都采用的new Handler() post方式,是为了线程安全吗?那应该new Handler(Looper.getMainLooper()).不然在子线程调用PostUtil中的方法会出错

addView、removeView

@LoadSirUtil#getTargetContext

if (contentParent != null) {
            contentParent.removeView(oldContent);
        }
        return new TargetContext(context, contentParent, oldContent, childIndex);

rt
用add以及remove 真正的View真的好吗,这两个操作涉及比较多东西(比如测量)
尝试visible?
but
这种方式(尝试visible)的话,childView的index就相对于开发者本身是不可知的操作了(因为变化了),应该权衡一下

有空白页

在使用在LoadingCallback的时候,会先显示空白页,大约迟疑一秒,在显示progressBar,这样正好请求服务器成功,就没有显示progressBar,数据拉去成功,LoadingCallback这个就跟没起作用一样

提一个建议,reload的click事件

现在的reload的点击事件是设置在了整个的View上了(父布局的事件一直会被触发),建议在ids.xml中 添加 一个预先定义的id,用于设置reload的点击事件,可否这样:
View reloadView = rootView.findViewById(R.id.reload_view);
if (reloadView != null) {
reloadView .setOnClickListener(new View.OnClickListener() {
@OverRide
public void onClick(View v) {
if (onReloadEvent(context, rootView)) {
return;
}
if (onReloadListener != null) {
onReloadListener.onReload(v);
}
}
});
}

一个小问题

想实现在loading时 不光能看到加载页面同时能看到content页面(即在loading和content同时能看到),但是这可能和这个库的设计理念有点违背了,看您的库是单页面的加载,我是想在加载时显示2种页面状态,但是目前没有想到很优雅的解决方式。如果有好的思路请告知,谢谢。

register 的View 如果是recyclerview 的问题

register 的View 如果是recyclerview 的话,loadlayout在切换到success的时候,recyclerview虽然有高度,但是loadlayout的高度和宽度都没有。感觉和 view绘制有关

不知作者是如何跟网络框架封装的

  • 一般网络框架的回调onStart onSuccess onError的基类不知道能不能结合本库封装。

  • 如果你有这方面的实践,是否方便提供下思路(或者多添加下这场景的demo)跟代码截图。

  • mBaseLoadService已经封装在BaseActivity跟BaseFragment

关于ScrollView的滑动监听的问题

作者您好,一直想找一个这样的库,目前来说,您的库是使用最方便的库,效果也不错。
我目前遇见了一个问题:
我的一个页面是做了一个类似于淘宝的Toolbar随ScrollView渐变颜色,目前出现了bug。

@OverRide
public void onScrollChanged(GradationScrollView scrollView, int x, int y,
int oldx, int oldy) {
// TODO Auto-generated method stub
if (y <= 0) { //设置标题的背景颜色
goodsDetailToolbar.setBackgroundColor(Color.argb((int) 0, 255, 255, 255));
goodsDetailTitle.setTextColor(Color.argb((int) 0, 255, 255, 255));
goodsDetailFab.setVisibility(View.GONE);
} else if (y > 0 && y <= height) { //滑动距离小于banner图的高度时,设置背景和字体颜色颜色透明度渐变
float scale = (float) y / height;
float alpha = (255 * scale);
goodsDetailTitle.setTextColor(Color.argb((int) alpha, 1, 24, 28));
goodsDetailToolbar.setBackgroundColor(Color.argb((int) alpha, 255, 255, 255));
goodsDetailFab.setVisibility(View.GONE);
} else { //滑动到banner下面设置普通颜色
goodsDetailToolbar.setBackgroundColor(Color.argb((int) 255, 255, 255, 255));
goodsDetailToolbar.setAlpha(1);
goodsDetailFab.setVisibility(View.VISIBLE);
goodsDetailFab.setAlpha(0.75f);

    }
}

height为Banner的高度。
当使用了您的控件,布局加载出来后,我滑动直接走了else这一块逻辑。请问该如何解决呢。
提前感谢!!!!!!!

Fragment中如果用到了ButterKnife, 会产生异常

@OverRide
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
rootView = inflater.inflate(getLayoutId(), container, false);
unbinder = ButterKnife.bind(this, rootView);
loadService = LoadSir.getDefault().register(rootView, new Callback.OnReloadListener() {
@OverRide
public void onReload(View v) {
// retry logic
}
});
return loadService.getLoadLayout();
}

试下这段代码,然后在业务Fragment中通过@BindView(R.id.xxxx) View view1, 在调用view1的地方会产生空指针。

在fragment中有一些布局结构使用目前版本无法做到状态页面的切换

作者好:我也通读了该项目源码 ,并且使用在项目中了,但是今天发现在fragment中 有一种布局结构无法达到各种状态页的替换 ,可能我脑子不好使 想半天 不知道怎么处理 希望作者您能看到 帮忙想想。 布局结构如下:

<FrameLayout>
            <LinearLayout vertical>
                      <EditText/>
                      <LinearLayout>...</LinearLayout>
                      <RecyclerView/>(这个是要 替换的View)
            </LinearLayout>
            <Button/>(最大的问题就是这个Button 是浮在最上面的)
</FrameLayout>

导入依赖 报错

Error:Execution failed for task ':app:processDebugManifest'.

Manifest merger failed with multiple errors, see logs

a question about layout

CN
@KingJA 你好, 我想问下为什么替换布局之后, 原来的View为什么不会报空指针, 也能设置数据, 加载成功后UI上的数据还能显示更改后的数据.

En
@KingJA Hi, I would like to know the old View why not throw a NullPointerException after replace layout, but also set the data, the UI after call showSuccess() can also display the changed data. (Why English is so awkward...)

EmptyCallback中textview不能传递值

比如我现在加载的页面要显示列表不能为空,另外一个界面显示消息不能为空,但是这个页面就一个文字不一样,我不能传递字符串过去,这个问题怎么解决?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.