动手写一个Android数据加载时界面状态切换的开源库

Android Killer入门指南:安卓逆向工程图形化工具实战解析 安卓逆向工程是分析移动应用内部机制、理解其工作原理的关键技术,广泛应用于安全评估、漏洞挖掘与学习研究。其核心原理在于通过反编译、静态分析与动态调试等技术,将已编译的APK文件还原为可读的代码与资源,从而洞察应用逻辑。掌握这项技术不仅能深化对安卓系统运行机制的理解,更能提升开发者的代码安全与防御能力。在众多工具中,Android Killer以其图形化集成环境脱颖而出,它无缝整合了Apktool、dex2jar、jd-gui等经典命令行工具,将复杂的反编译、代码查看、打包签名流程可视化,极大降低了逆向工程的学 阅读详情

文章伊始,让我们先静心回忆三秒:在我们写过的Android应用当中,是不是有很多地方都离不开数据加载的需求呢?如果是,那么我们首先来看下图:

这里写图片描述

好的,从这里开始我们暂时忘记自己是一个安卓开发者,而是以一个不懂技术的APP使用者的身份来继续接下来的交流。

如果是作为一个使用者,那么现在我们的内心应该是懵逼的。因为自打我们打开这个应用进入到第一个界面后,就发现没有任何内容。
这个时我们可能会开始推测:什么鬼?手机断网啦?再一看,网络正常啊!继续推测…推测…,最后得出结论:这应用傻x吧,删掉删掉…..

好的,现在切换回开发者的身份,来推测分析下答案:那么原因可能为事实上该界面存放有一个ListView用来显示从服务器获取的一些信息。
但是,的确很可能因为网络不顺畅,服务器内部异常等一些原因造成请求失败,没有数据返回。于是造成了页面没有内容显示的窘境。
显然,作为一个优秀的应用,用户的体验肯定是头等大事。所以很必须的,针对于这种类似的情况,我们应该给用户一些友好的提示。

那么,现在我们可以初步的改进一下代码,比如改进为下面这样的效果:

这里写图片描述

可以看到,现在当我们发现本次请求没有成功返回数据的时候及时对用户做了交代,起码用户明白这次没有获取到“数据”。这就比之前友好一些了。
不得不说这其实是很一种很常见,但是也很有必要的做法。而且要实现这种需求也相当简单,为listview进行setEmptyView就可以了。

<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

   <ListView
       android:id="@+id/lv_animals"
       android:layout_width="match_parent"
       android:layout_height="match_parent">
   </ListView>

   <RelativeLayout
       android:id="@+id/empty"
       android:layout_width="match_parent"
       android:layout_height="match_parent">

      <ImageView
          android:id="@+id/empty_icon"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:background="@drawable/ic_empty"
          android:layout_centerInParent="true"/>

      <TextView android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_below="@id/empty_icon"
          android:layout_centerHorizontal="true"
          android:text="还没有数据哦,亲!"/>
   </RelativeLayout>
</RelativeLayout>

这种东西已经不是新鲜事了。以上布局文件中,id为empty的部分就是我们想要在没有获取到的数据的时候提供给用户看的view。
随后的做法也很简单,在Java代码中调用setEmptyView把指定的view设置给ListView就可以了。

        listView = (ListView) findViewById(R.id.listview);
        View empty = findViewById(R.id.empty);
        listView.setEmptyView(empty);

现在就搞定了,确实非常简单。但简单其实是因为Android的设计者已经考虑到了ListView的数据为空的情况,我们调用现有的方法,当然就容易了。

现在我们是不是就可以满足了呢?当然不是。就像我们在图2中可以看到,虽然现在针对于获取数据为空的情况对用户做了交代。但是!我们知道:
比如通过网络去加载数据,肯定是需要一点时间的。那么就像图2演示的,在本次请求结果返回之前,有一段时间我们的界面是一直没有内容的。
那么该怎么改进呢?其实就像绝大多数应用所做的一样,当界面在等待数据加载的过程里,是有一个loading提示的,通常是一个漂亮的动画。
这样做的好处显而易见:一是告诉用户,让它知道现在正处于数据读取的过程中。二来loading动画越有趣,也就不那么让用户因为等待而烦躁了。

好的,现在我们考虑的问题自然就是如何来实现这种需求了。有了setEmptyView的经验,难免就想看看ListView还有没有叫做setLoadingView的方法?
很遗憾,答案是没有。那么问题来了:为什么listview的设计者已经考虑到了empty view的情况,却没有考虑到loading呢?我们试着从源码中寻找答案。

很显然,为了得到我们想要的答案。我们自然是去瞧一瞧setEmptyView的内部实现原理是怎么样的?打开该方法的代码如下:

    public void setEmptyView(View emptyView) {
        mEmptyView = emptyView;

        // If not explicitly specified this view is important for accessibility.
        if (emptyView != null
                && emptyView.getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
            emptyView.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
        }

        final T adapter = getAdapter();
        final boolean empty = ((adapter == null) || adapter.isEmpty());
        updateEmptyStatus(empty);
    }

我们发现其实这个方法的实现还是很简单的,就是把我们传入的view赋值给AdapterView内部的实例变量mEmptyView 。
之后会判断adapter == null || adapter.isEmpty(),实际意义其实就是判断AdapterView现在是否有数据,没有的话就updateEmptyStatus。

updateEmptyStatus的方法我们也不用全看,通过截取后的如下代码就能把其逻辑的核心思想体现的淋漓尽致:

     private void updateEmptyStatus(boolean empty) {
        // ...

        if (empty) {
            if (mEmptyView != null) {
                mEmptyView.setVisibility(View.VISIBLE);
                setVisibility(View.GONE);
            } 
        // ...
        } else {
            if (mEmptyView != null) 
            mEmptyView.setVisibility(View.GONE);
            setVisibility(View.VISIBLE);
        }
    }

通过代码我们可以发现:其实内部是通过传入的布尔变量empty来确定显示的view的。本质则是通过设置View的Visibility属性,来控制是显示AdapterView本身还是EmptyView。是的,原理就是如此简单。但我们接着分析:当ListView的数据发生改变,显然就需要再次判断需要显示何种内容。
那么,这个判断又是如何进行的的呢?实际上是借助“观察者”设计模式来完成的。打开BaseAdapter的源码,首先就会看到如下的代码:

public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter {
    private final DataSetObservable mDataSetObservable = new DataSetObservable();

    public boolean hasStableIds() {
        return false;
    }

    public void registerDataSetObserver(DataSetObserver observer) {
        mDataSetObservable.registerObserver(observer);
    }

也就是说BaseAdapter内部有一个“观察”mDataSetObservable,顾名思义它就是用来确定adapter的数据是否发生变化的。
通过registerDataSetObserver可以注册“观察者”给观察对象,而这个调用发生在为AdapterView设置adapter的时候,即发生在setAdapter方法当中:

    public void setAdapter(ListAdapter adapter) {
        if (mAdapter != null && mDataSetObserver != null) {
            mAdapter.unregisterDataSetObserver(mDataSetObserver);
        }
        //.......省略代码
       mDataSetObserver = new AdapterDataSetObserver();           
       mAdapter.registerDataSetObserver(mDataSetObserver);

也就是说,当我们调用setAdapter后,“观察者”和“观察对象”就都齐了。那么,我们接下来的工作就是查看“观察”的行为究竟是如何进行的。
回想一下,当ListView的数据发生更改的时候,通常我们会调用什么方法?没错,就是notifyDataSetChanged方法。OK,打开该方法的源码:

    public void notifyDataSetChanged() {
        mDataSetObservable.notifyChanged();
    }

上述代码是在Adapter顶层基类BaseAdapter中该方法的实现,由此我们可以发现当数据更新后,mDataSetObservable就会调用notifyChanged方法:

    public void notifyChanged() {
        synchronized(mObservers) {
            for (int i = mObservers.size() - 1; i >= 0; i--) {
                mObservers.get(i).onChanged();
            }
        }
    }

由此可以发现,当我们调用notifyDataSetChanged,最终其实是通过Adapter内部的“Observer”们来完成执行对应的操作的。

我们之前说到BaseAdapter的观察者类型是DataSetObserver,这个抽象类其实结构很简单,只有两个方法定义:

public abstract class DataSetObserver {

    public void onChanged() {
        // Do nothing
    }

    public void onInvalidated() {
        // Do nothing
    }
}

顾名思义,也就是观察到数据发生改变时的回调,和数据无效时的回调。之前我们说到当调用notifyDataSetChanged方法时,观察者的onChanged方法最终被回调了。而对应的,onInvalidated则是发生在对adapter调用notifyDataSetInvalidated的时候。

好了,事实上现在就已经万事俱备了。只剩最后一步,就能彻底弄明白ListView究竟是怎么在EmptyView和自身内容之间切换显示的。
回忆一下之前说的,当我们对ListView调用setAdapter的时候,就会将观察者注册给Adapter,而以ListView来说:
这个观察者的实际类型是:定义在AdapterView的中的一个内部类,它继承自DataSetObserver,名叫AdapterDataSetObserver:

class AdapterDataSetObserver extends DataSetObserver {

        private Parcelable mInstanceState = null;

        @Override
        public void onChanged() {
            mDataChanged = true;
            mOldItemCount = mItemCount;
            mItemCount = getAdapter().getCount();
            //省略若干代码...
            checkFocus();
            requestLayout();
        }

        @Override
        public void onInvalidated() {
            mDataChanged = true;

            //省略若干代码...
            mItemCount = 0;
            //省略若干代码...

            checkFocus();
            requestLayout();
        }
    //...
}

我们这里省略了部分不关心的代码,从剩下的代码中可以清晰的看到onChanged和onInvalidated都有几乎相同的几个操作:

  • 为mItemCount赋值,不同的是onChanged是通过adapter.getCount()获取的值;onInvalidated则直接设置为0.
  • 最终都会调用checkFocus()和requestLayout方法。

显然,requestLayout是View当中的方法,也就是通知控件重绘。那么关键就在checkFocus身上了,打开其源码:

    void checkFocus() {
        final T adapter = getAdapter();
        final boolean empty = adapter == null || adapter.getCount() == 0;
        //省略若干代码...
        if (mEmptyView != null) {
            updateEmptyStatus((adapter == null) || adapter.isEmpty());
        }
    }

可以看到这里又出现了熟悉的代码,通过判断adapter是否为null或者adapter.getCount是否为0,来确定empty的值,最后就回到了我们熟悉的updateEmptyStatus。好的, 相信我们已经大概弄清了对ListView设置emptyView的实现原理。我们简单的来总结一下:

  • 当我们对ListView调用setAdapter()方法后,就会注册一个类型为AdapterDataSetObserver 的观察者对象给Adapter自身。
  • 随后,当ListView出现数据更新,则会调用到notifyDataSetChanged或者说notifyDataSetInvalidated方法。
  • 于是Adapter内部的观察者对象的onChanged和onInvalidated方法就会被回调。而这两个方法最后都会触发checkFocus方法。
  • checkFocus方法会通过判断adapter是否null和adapter.getCount()是否为0来判断当前ListView是否有数据,从而决定显示ListView还是EmptyView。

好了,现在还是回到我们之前的问题:为什么ListView已经提供了setEmptyView这样的方法,却没有提供setLoadingView这样的东西呢?
其实了解了setEmptyView的原理后,已经很清楚了。我们已经知道AdapterView内部是通过“观察者”来监听adpter的数据变化。
那么很显然,“数据发生变化”这种东西是设计者是很容易为我们进行观察的,但是否处于loading状态这种东西,就没那么好“观察”了。
因为其实我们都说不好开发时会因为各种各样的需求在某个时候会出现处于Loading状态。

但是,没关系,从以上的源码分析中,我们可以从中学习一个关键,那就是所谓不同状态的界面切换显示,实际上本质就是:
为数据加载可能出现的状态分别提供对应的View,然后根据不同的状态来让需要显示的View-VISIBLE,其余的View-Gone。

了解了这个原理我们就很容易实现类似的需求了。但是!我们也说到了数据加载这种东西在应用里是很常见的。
如果我们每次遇到类似的需求都要去写一遍同样逻辑的代码,实际上也是很蛋疼的。有没有可能造一个轮子让我们重复使用呢?肯定是可以的额。

有了想法就付诸行动吧,让我们自己来写一个完成数据加载时不同状态的视图切换的开源库。
首先,让我们来总结分析一下:其实以“数据加载”而言,结合我们平时的经验,通常会需要四种切换状态:

  • 内容视图:即成功获取到数据后显示这些数据的视图
  • Loading视图:即当数据开始加载到还未加载返回的这段时间显示的视图
  • 空视图:即没有查询到我们想要获取的数据时显示的视图
  • 异常视图:比如我们通过网络请求数据时,因为网络中断而发生异常,就可以通过对应视图告诉用户,网络出错了。

举个例子来说,就像下面这样:

这里写图片描述

以上的效果都是通过最近没事写的一个很简单的小开源库SmartLoadingLayout实现的。今天把它整理了下上传到了bintary和github。
用起来还是比较简单的。(github项目地址:https://github.com/RawnHwang/SmartLoadingLayout)有兴趣的一起接着看:

首先肯定是配置依赖,在项目下的build.gradle添加maven仓库,然后在module的build.gradle中导入。

    repositories {
        jcenter()
        maven {
            url  "http://dl.bintray.com/rawnhwang/RawnHwangAndroid"
        }
    }
    //============================================
    compile 'me.rawnhwang.library:smart-loading-layout:1.2.2@aar'

现在,我们就来一起看看:如何通过这个小工具库,来方便的完成如上所示的效果图。首先我们先新建一个初始的界面布局:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <TextView
        android:id="@+id/tv_content"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:text="Hello Android!" />
</LinearLayout>

这种布局简单且具有代表性,与我们平常写的没有任何不同。然后来看下怎么通过SmartLoadingLayout来为这个界面加上不同的切换状态。

public class MainActivity extends AppCompatActivity {

    private TextView tvContent;
    private DefaultLoadingLayout mLayout; //SmartLoadingLayout对象

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        tvContent = (TextView) findViewById(R.id.tv_content);
        mLayout = SmartLoadingLayout.createDefaultLayout(this, tvContent);
    }
}

以上所有的代码相信我们都很熟悉,唯一的额外工作是需要一个DefaultLoadingLayout对象。
DefaultLoadingLayout通过调用SmartLoadingLayout的静态方法createDefaultLayout就可以成功获取。
该方法需要两个参数,一个是界面的宿主Activity,另一个就是传入我们选择作为内容的view(比如这里就是TextView)。

OK,到了这里,我们的一切准备工作就已经完成了,就是这么的简单。那么,通过以下的代码逻辑我们就可以模拟出等待数据加载并显示的效果:

    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            // 数据下载完成,转换状态,显示内容视图
            mLayout.onDone();
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        //......

        //进入loading状态
        mLayout.onLoading();
        new Thread(new Runnable() {
            @Override
            public void run() {
                // 这里是模拟下载数据的耗时过程
                downloadData(); 
                // 数据下载完毕后,通知handler
                mHandler.sendEmptyMessage(1);
            }
        }).start();
    }

然后让我们运行程序看一下效果:

这里写图片描述

看上去是不是还不错呢?可以看到我们需要做的就是在开始加载数据的时候调用onLoading方法,然后在成功获取数据后调用onDone方法就搞定了。

那么,现在假设这次我们进入时没有获取到数据,也就是我们之前说的空视图。那么,也很简单,将之前代码的onDone改为onEmpty就可以了。

    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            mLayout.onEmpty();
        }
    };

让我们再次运行程序看看效果:

这里写图片描述

现在我们就轻车熟路了。同理,如果是读取数据的过程中发生了网络异常呢?我们再把onEmpty改为onError。然后再看看效果:

这里写图片描述

再接着看,可以看到就像上一张图中演示的一样,error状态下通常会有一个按钮,来执行某种操作,通常来说是用于再次发送请求刷新界面的。
那么,我们应该怎么样为这个按钮添加这个操作呢?别急。大家可能还会有其它问题,比如:
我觉得这个错误界面的图形太丑了,我不喜欢;或者我想自己定义错误的描述信息;或者按钮什么鬼?同样也不是我想要的等等等等..

没关系,结合以上问题一起,我们用如下的代码能够一次体现所有的解决方式:

        mLayout.setErrorButtonListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mLayout.replaceErrorIcon(R.mipmap.ic_launcher);
                mLayout.setErrorDescription("This my error information.");
                mLayout.setErrorDescriptionColor(Color.BLUE);
                mLayout.setErrorDescriptionTextSize(20);
                mLayout.setErrorButtonText("oh!no!");
                mLayout.setErrorButtonTextColor(Color.RED);
                mLayout.setErrorButtonBackground(R.drawable.bg_error);
            }
        });

同样的,我们再次运行程序来看看效果:

这里写图片描述

同理的,如果你不喜欢Loading的效果,不喜欢Empty界面的效果,都可以通过对应的方法来定制为自己喜欢的风格。
但问题又来了,你说了:到目前为止所有的一切我都不太喜欢怎么办。那么我就很尴尬了.
不过也没关系。还有另一个类型叫做CustomLoadingLayout,通过它所有的界面都可以完全由你自己定制。

比如说,现在我们在自己的项目里分别定义好了数据加载时各种不同状态的布局文件。那么,接下来就把它include进来就行了:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">
    <ListView
        android:id="@+id/lv_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_centerInParent="true" />
    <!-- this is your custom part -->
    <include
        android:id="@+id/my_empty_page"
        layout="@layout/my_empty_page" />

    <include
        android:id="@+id/my_error_page"
        layout="@layout/my_error_page" />

    <include
        android:id="@+id/my_loading_page"
        layout="@layout/my_loading_page" />
</LinearLayout>

接着是代码控制:

    private CustomLoadingLayout mLayout; //SmartLoadingLayout对象
    //...............

    mLayout = SmartLoadingLayout.createCustomLayout(this);
    mLayout.setLoadingView(R.id.my_loading_page);
    mLayout.setContentView(R.id.lv_content);
    mLayout.setEmptyView(R.id.my_empty_page);
    mLayout.setErrorView(R.id.my_error_page);

这样就完成了准备工作,接下来的工作就仍然是在需要的时候调用onLoading此类的方法了。好啦,就写到这里吧!

安卓期末项目实战:从零构建一个MVVM架构的社区应用 在移动应用开发领域,客户端架构设计与性能优化是构建高质量应用的核心基础。MVVM(Model-View-ViewModel)作为一种主流架构模式,通过数据绑定实现了视图与业务逻辑的清晰分离,有效提升了代码的可维护性和可测试性。其技术价值在于能够优雅地管理界面状态,并响应数据变化。在实际工程实践中,结合Jetpack组件库,开发者可以高效处理网络通信、数据持久化等常见场景。例如,在开发一个包含用户交互与内容展示的社区类应用时,合理运用RecyclerView进行列表渲染与分页加载,并借助Glide等库优化图片 阅读详情

相关推荐

LSPatch免Root模块注入:内存加载技术与Android逆向工程实践

动态代码注入是Android应用修改与功能增强领域的核心技术之一,它允许开发者在运行时改变应用行为而无需修改原始APK。其原理主要基于ART运行时环境,通过类加载器机制和反射技术实现方法拦截与代码执行。这项技术的核心价值在于为应用热修复、功能扩展和安全研究提供了底层支持,广泛应用于插件化开发、性能监控和逆向分析等场景。其中,内存加载技术通过将Dex文件直接读入内存并创建InMemoryDexClassLoader,实现了免Root环境下的代码注入,这正是LSPatch项目的核心实现方式。通过APK重打包与C

weixin_33980459的博客 384

android 界面等待,Android 开发使用PopupWindow实现加载等待界面功能示例

本文实例讲述了Android 开发使用PopupWindow实现加载等待界面功能。分享给大家供大家参考,具体如下:实现加载等待界面我用了两种方式,一种是用PopupWindow实现,另一种便是用Activity实现。用Activity实现方法请见我的另一篇博客:Android 使用Activity实现加载等待界面首先看效果:用PopupWindow实现此功能还是比较简单的,首先我们写一个布局,只有...

weixin_36357900的博客 649

LazyUIAutomatorViewer:安卓UI自动化测试元素定位效率利器

UI自动化测试是移动应用质量保障的核心环节,其关键在于精准、高效地定位界面元素。传统工具在元素探查与定位代码生成上存在效率瓶颈,影响测试脚本的开发与维护。LazyUIAutomatorViewer作为一款增强工具,针对原生uiautomatorviewer的痛点进行了深度优化。它通过整合信息面板、提供一键生成主流框架(如Appium、Espresso)定位代码等特性,将元素探查与脚本编写无缝衔接,显著提升了安卓UI自动化测试的前期开发效率。该工具尤其适用于需要频繁编写和维护UI测试用例的工程师,能有效应对复

weixin_30457551的博客 379

安卓开发显示加载中

【代码】安卓开发显示加载中。

qq_21810059的博客 335

Android横竖屏切换的“数据保卫战”:如何优雅地保存和恢复表单数据

Dao有些控件(比如自定义View或第三方库)可能不支持onSaveInstanceState(),这时候你需要自己动手。自定义View的保存和恢复状态是个技术活,但能让你掌控一切。

大模型大数据攻城狮的专栏 764

Android-StatusView简单的Android页面多状态布局切换控件

StatusView:简单的 Android 页面多状态布局切换控件

Android 用Activity实现加载等待界面

实现加载等待界面我用了两种方式,一种是用PopupWindow实现,另一种便是用Activity实现。用PopupWindow实现方法请见我的另一篇博客:用PopupWindow实现加载等待界面 好了,下面开始。先上效果:基本原理就是在主界面点击按钮(以登录按钮为例)之后,打开一个新的Activity,此Activity以对话框形式展示。首先,主界面(一个登录按钮以及它的监听事件):activity

LIFER 8345

基于YOLO11深度学习的糖尿病视网膜病变智能诊断系统【Python源码+Pyqt5界面+数据集+训练代码】

本文详细介绍如何利用YOLO11深度学习技术构建糖尿病视网膜病变智能诊断系统。项目提供完整的Python源码、PyQt5图形界面、标注数据集及训练代码,实现从图片、视频到摄像头的多模态病变检测,旨在辅助医疗筛查,提升诊断效率。

weixin_29089057的博客 277

Android开发学习:[24]Android加载网页

首先我们打开下载安装好的Android Studio然后新建一个项目,这里为了方便我就在我的Demo里面新建一个Activity了2然后我们在界面布局代码里面增加一个Webview控件&lt;RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"    xmlns:tools="http://schemas...

lyfxh1314的博客 615

AD17入门简单教程(一)

AD17入门简单教程 我写这篇文章主要是因为最近刚学习完了AD17,想做一下总结,也希望通过自己心得的帮助一些刚入门AD17的小白。 总结一共分为两大部分,包括AD17的下载安装与汉化(文末有详细链接)、工程的创建、元器件库、PCB、走线中的常用命令介绍,文末还附有完整的PCB工程以及讲解视频。 第一部分工程的创建及元器件库常用命令 1.首先在桌面上创建一个文件夹,然后在AD17点击左上角的文件中...

qq_45433195的博客 2万+

嵌入式开发语言-C语言编程

C语言编程概述环境在Windows上构建C语言的环境安装在Mac上构建C语言的环境安装 概述 “C语言”被称为适合嵌入式系统开发的编程语言之一。 C语言在一般的编程中也是熟悉的开发语言,但实际上,如果试着使用C语言制作微型计算机的控制程序等,就必须使用与“普通的C程序”不同的使用方法。 作为一般的C语言的学习方法,使用“printf”“scanf”等标准函数的程序开发是固定的,但这些都是以UNIX和Windows等环境上的应用程序开发为前提的。 对此,没有显示器和键盘的嵌入式系统的微型计算机控制程序,该如何

编程老王 7976

Android显示内容页、加载中和出错页的一种方法

Android显示内容页、加载中、数据错误和布局的一种方法,缺点是在整个内容页外面套一个根布局,所以如果内容页是有标题栏或者底部有tabbar的话,空页面、加载中和错误页面会阻挡整个内容页

Liangingword的博客 871

告别手动翻页!用幻影联动+DLL调用,5分钟搞定通达信分时指标自动选股

本文详细介绍了如何利用幻影联动软件结合DLL调用技术,实现通达信分时指标的自动化选股。通过改造指标代码和配置幻影联动任务,用户可以在5分钟内完成从信号检测到自动报警的全流程,大幅提升短周期交易的效率和准确性。

weixin_42561040的博客 764

Android 开发者迁移 Flutter 全指南:从 View、Intent 到插件与本地存储的逐项对照实战

本文以 Flutter-learning 仓库收录的 [《Android开发者参考》](https://link.gitcode.com/i/488abee0e4f92863d3af901dc8d92406) 官方文档译文为骨架,面向已有 Android 开发经验、希望快速上手 Flutter 的开发者,系统梳理 Android 与 Flutter 在 **View/Widget、Intent/R

gitblog_00211的博客 431

Qwen3.6-27B本地部署实战:LM Studio配置、硬件门槛与避坑指南

大语言模型本地部署是当前AI工程落地的核心能力之一,其本质是将高参数量模型(如27B级)在受限硬件环境下实现低延迟、高稳定推理。关键技术原理涵盖量化压缩(如GGUF格式与q4_k_m精度权衡)、GPU显存分配策略(KV Cache管理与Offloading机制)、以及运行时环境兼容性(CUDA驱动、llama.cpp后端版本)。该能力直接决定私有化AI应用的技术可行性与成本边界,广泛应用于企业知识库构建、代码辅助、长文档分析等对数据主权和响应确定性要求高的场景。本文聚焦Qwen3.6-27B这一典型27B模

weixin_33272631的博客 467

算法面试八股文『 基础知识篇 』

个人整理的算法面试基础知识八股文,内容较详细。

SG_teresa's blog 4336

灵活定制 LoadingAndRetryManager:为单个页面打造专属加载、重试与空数据布局的 3 种方式

LoadingAndRetryManager 是一个轻量级的 Android 开源库,能够无缝地为 Activity、Fragment 以及任意 View 设置加载(loading)、重试(retry)和无数据(empty)页面。默认情况下,你可以在 Application 里配置一套全局通用的加载、重试与空数据布局,让所有页面风格统一;而当某个页面需要与众不同的表现时,也无需大动干戈——只需重写

gitblog_00639的博客 896

Windows 10下Gpg4win 4.3.1安装与配置全攻略:从下载到邮件加密实战

本文详细介绍了在Windows 10系统下安装和配置Gpg4win 4.3.1的全过程,包括下载、验证、自定义安装以及密钥管理。特别重点讲解了如何通过Kleopatra证书管理器进行密钥创建和管理,以及在Outlook中实现邮件加密的实战操作,帮助用户全面提升数据安全防护能力。

weixin_29271263的博客 301

【亲测免费】 动态替换Android应用字符串:Restring开源库解析与应用

动态替换Android应用字符串:Restring开源库解析与应用 在开发Android应用时,我们经常会遇到需要动态更新或添加多语言翻译的需求。传统的资源文件方式虽然稳定,但在灵活性上却有所欠缺。为此,我们推荐一款名为Restring的开源库,它允许你在运行时动态替换应用中的字符串,甚至提供新的翻译版本。现在,让我们深入了解这个强大的工具。 项目介绍 Restring是一个轻量级的Android...

gitblog_00033的博客 564

LSTM+Transformer混合模型时间序列预测实战教学

LSTM+Transformer混合模型时间序列预测实战教学 毕业设计

8218

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

告别Android复杂滚动交互难题:Scrollable开源库完全指南

还在为Android应用中复杂的滚动交互而头疼吗?🤔 想要实现流畅的标签切换、智能的过度滚动效果,却总是被各种技术细节困扰?今天,我要为你介绍一款能够彻底解决这些难题的终极神器——Scrollable开源库!🚀 Scrollable是一个专为Android开发者设计的强大滚动交互解决方案,它能够轻松处理ViewPager、RecyclerView、ScrollView等各种视图容器的滚动事件

gitblog_00033的博客 489

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

Android App框架设计 基类BaseActivity

Android App框架设计 基类BaseActivity

jiushiwo12340的博客 2055

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

新手福音:用快马AI生成安卓棋牌应用界面入门代码

总之,从一句“我想要一个棋牌游戏大厅界面”的描述,到一个结构清晰、注释详细、可运行可部署的安卓项目,这个过程极大地降低了安卓UI的入门门槛。的AI生成功能就像一位经验丰富的向导,帮你搭好了基础框架,让你可以跳过最令人困惑的起步阶段,直接进入“填充血肉”和“理解骨骼”的环节。控件,将其约束在屏幕顶部,并设置一个醒目的背景色和居中的应用标题,比如“棋牌乐园”。通过这样一个从描述到生成代码的过程,我不仅得到了一个可运行的棋牌应用界面原型,更重要的是,我清晰地看到了一个标准安卓应用界面是如何层层组装起来的。

SilverfoxOwl19的博客 186

Android使用Fragment来实现ViewPager的功能(解决切换Fragment状态不保存)以及各个Fragment之间的通信

转载:http://www.cnblogs.com/tiantianbyconan/p/3364728.html 我前两天写过一篇博客《Android使用Fragment来实现TabHost的功能(解决切换Fragment状态不保存)以及各个Fragment之间的通信》(http://www.cnblogs.com/tiantianbyconan/p/3360938.html),实现了Tab

程序,有自己的灵魂. 649

Unity场景异步切换:从原理到企业级加载管理器实现

在游戏开发中,资源加载是影响用户体验的关键环节。同步加载会阻塞主线程,导致游戏卡顿甚至无响应,而异步加载技术通过将耗时操作分摊到多帧执行,在后台加载资源的同时保持当前场景的响应性。其核心原理基于任务分帧处理与进度监控,技术价值在于提升应用流畅度与健壮性。在Unity引擎中,可通过SceneManager.LoadSceneAsync结合协程或async/await模式实现,并常配合加载界面提供进度反馈。这一方案广泛应用于需要平滑过渡的各类游戏场景,如大型开放世界地图切换、关卡加载以及资源热更新等场景,是构建

weixin_34357436的博客 316

Folia 国内下载安装教程:3 条路线 10 分钟跑起全屏歌词动画播放器

Folia 是一款以全屏歌词动画为核心的音乐播放器,支持本地音乐库与 Navidrome、网易云、QQ 音乐、酷狗等在线音源。本文给出 Folia 国内下载安装的 3 条路线,照做即可在 Windows、macOS 或 Linux 上完成安装并验证播放。 ## 开装前确认 先对照下表确认你的系统、对应官方渠道和所需工具: | 系统 | 官方获取渠道 | 所需工具 | 版本核对方式 | | -

gitblog_00330的博客 992
上一篇: 带着疑惑走进Dagger2
下一篇: 用Canvas和属性动画造一只萌蠢的“小鬼”
LaterEqualsNever
博客等级 码龄12年 297粉丝 61原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值