Days 19 Handler

Handler机制详解
本文详细介绍了Android中的Handler机制,包括Handler的基本概念、工作原理及其应用场景。此外,还提供了多个实例演示如何利用Handler在子线程与主线程间进行消息传递,以实现对UI的操作。

1、什么是Handler?
Handler通俗来讲就是用来在各个线程之间发送数据的处理对象。在B线程中,只要获得A线程的Handler,就可以通过handler.sendMessage(messge)方法向A线程发送数据。而当B线程处理完一些耗时操作后,A线程可以通过handler的handlerMessage()方法获得数据
2、主线程
运行所有UI组件。如果任何一个消息用时超过5秒,Android将抛出Application Not Responding,所以一个任务用时超过5秒,应该在一个独立线程中完成它,或者延迟处理它。
子线程没有办法对UI界面的内容进行操作,如果操作,将抛出CalledFromWrongThreadException。为了实现子线程中操作UI界面,Android中引入了Handler消息传递机制。至此,我们学过的子线程操作UI界面的方法有:1、异步任务;2、Loader;3、Handler
3、常用类
a、Handler :处理者,负责Message的发送及处理。主要作用:1、在工作线程中发送消息;2、在主线程中获取并处理消息。
b、Message:消息,其中包含了消息标识,消息处理对象以及处理的数据。由MessageQueue统一列队,最终由Handler处理
c、MessageQueue:消息队列,将Message串联起来,等到Looper的抽取,按照FIFO规则(先进先出)
d、Looper:消息泵,不断的从MessageQueue中抽取Message执行。一个MessageQueue需要对应一个Looper
4、常用类的方法及属性
a、Handler类
1、handleMessage()用在主线程中(可以根据获得的消息更新UI),构造Handler对象时,重写handleMessage()方法,根据工作线程返回的消息标识,获得消息并执行相应操作
2、sendEmptyMessage()用在工作线程中,发送空消息
3、sendMessage()用在工作线程中,将消息(Message对象)发送(给主线程)
b、Message类
1、arg1,arg2 用来存放整型数据,可节省系统资源arg1 and arg2 are lower-cost alternatives to using
2、obj 用来存放Object数据
3、what 就是一个消息的标记,用来区分消息,为int类型
b、Message类
1、message虽然可以通过new Message()方法获得,但是通常使用Message.obtain()方法或handler.obtainMessage()方法从消息池中获得空消息对象,节省系统资源
2、arg1、arg2 若传递的数据为int型,用此属性,节省内存
3、what 就是用于识别消息的标记
4、如果需要从工作线程返回很多消息信息,可以借助Bundle对象将这些数据集中在一起,放在obj属性中
5、备注:
a、通过getResource().getAssets().open(“文件名”);返回值为InputStream,以流的形式打开assets目录下的文件
b、Looper对象用来为一个线程开启一个消息循环,从而操作MessageQueue;
默认情况下,Android创建的线程没有开启消息循环Looper,但是主线程例外。
系统自动为主线程创建Looper对象,开启消息循环;
所以主线程中使用new来创建Handler对象。而子线程中不能直接new来创建Handler对象就会异常。
子线程中创建Handler对象,步骤如下:
Looper.prepare();
Handler handler = new Handler() {
//handlemessage(){}
}
Looper.loop();
Demo1:
构造Handler对象

private Handler handler = new Handler() {
        // 现在在主线程中,故可以更新UI(是主线程的接收处理方法)
        public void handleMessage(Message msg) {
            switch (msg.what) {
            case 1:
                txtShow.setText(msg.arg1 + "  " + msg.arg2 + "  " + msg.obj);
                break;

            default:
                break;
            }
        };
    };

子线程:

new Thread() {
            public void run() {
                int count = 0;
                while (count < 100) {
                    Message message = new Message();

                    // message.what值为int类型,就是一个消息的标识,用来区分消息
                    message.what = 1;
                    // arg1,arg2可以传递整数类型,节省系统资源
                    // arg1 and arg2 are lower-cost alternatives to using
                    message.arg1 = count;
                    message.arg2 = count * 10;
                    // 用来存放非整形数据
                    message.obj = "count = " + count;

                    // (子线程中)通过handler对象的sendMessage()方法将消息(Message对象)发送(给主线程)
                    handler.sendMessage(message);

                    count++;
                    SystemClock.sleep(1000);
                }
            };
        }.start();

Demo2:
子线程下载图片数据,传给主线程更新UI
构建Handler对象

private Handler handler = new Handler() {
        //主线程handler对象根据message的不同标识采取相应操作
        @Override
        public void handleMessage(Message msg) {
            /**
             * 所犯错误:
             * pdShow若在外面创建,因为要走三遍handleMessage()方法,所以会创建三个pdShow
             * 而case 2的dismiss()只关闭了第三个Show()
             */
//          pdShow = new ProgressDialog(MainActivity.this);
            switch (msg.what) {
            //工作线程发送what为0,代表工作线程开启;主线程相应显示对话框
            case 0:
                pdShow = new ProgressDialog(MainActivity.this);
                pdShow.setTitle("title");
                pdShow.setIcon(R.drawable.ic_launcher);
                pdShow.setMessage("洪荒之力已开启");

                pdShow.show();
                break;

            //工作线程发送what为1,将代表需要的数据加载完毕,通过Message对象获得数据
            case 1:
                ivShow.setImageBitmap((Bitmap) msg.obj);
                break;
            //工作线程发送what为2,代表工作线程执行完毕,关闭对话框
            case 2:
                pdShow.dismiss();
                break;
            default:
                break;
            }

        }
    };

子线程:

public void start(View v) {
        new Thread() {
            public void run() {

                //当工作线程刚开始时,希望显示进度对话框,此时让handler发送一个空消息即可
                handler.sendEmptyMessage(0);

                byte[] data = OkHttpUtils.getByteArrayByUrl(url);

                Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0,
                        data.length);

                //Message虽然可以通过new来获取,
                //但是通常使用Message.obtain()方法或handler.obtainMessage()方法
                //来从消息池中获得空消息对象,以节省资源
                Message msg = Message.obtain();
                msg.what = 1;
                msg.obj = bitmap;

                handler.sendMessage(msg);

//              SystemClock.sleep(6000);
                //当工作线程执行完毕,希望关闭进度对话框,此时让handler发送一个空消息即可
                handler.sendEmptyMessage(2);
            };
        }.start();
    }

Demo3:
子线程不断发送图片的偏移量,主线程中(根据图片位置)设置使图片偏移

public class MainActivity extends Activity {

    private ImageView ivShow = null;
    private float x, y;
    //错误:这样声明falgX为false,flagY为true
//  private boolean flagX , flagY = true;
    private boolean flagX = true;//标志图片是否往上走
    private boolean flagY = true;

    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
            case 1:
                if (x > 400) {
                    flagX = false;
                } else if (x < 10) {
                    flagX = true;
                }

                if (flagX) {
                    x += msg.arg1;
                } else {
                    x -= msg.arg1;
                }

                if (flagY) {
                    flagY = false;
                    y += msg.arg2;
                } else {
                    flagY = true;
                    y -= msg.arg2;
                }
                ivShow.setX(x);
                //在这里,y方向的正方向为向下,所以y += msg.arg2后,setY(y)向下移动
                ivShow.setY(y);
                break;

            default:
                break;
            }
        }
    };

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

        initView();
    }

    private void initView() {
        ivShow = (ImageView) findViewById(R.id.ivShow);

        //在onAttachedToWindow()方法之前,ImageView都没有显示在屏幕上,所以getX()为0
        /**
         * onAttachedToWindow()方法,将控件显示在界面上
         */
//      x = ivShow.getX();
//      y = ivShow.getY();
    }

    public void play(View v) {
        //获得ivShow离父容器左边缘距离
        x = ivShow.getX();
        y = ivShow.getY();
        new Thread() {
            public void run() {
                while (!Thread.interrupted()) {
//                  Message msg = handler.obtainMessage();
                    Message msg = Message.obtain();

                    msg.arg1 = 10;
                    msg.arg2 = 50;
                    msg.what = 1;

                    handler.sendMessage(msg);
                    //生成100到600之间的随机数
                    SystemClock.sleep(new Random().nextInt(500)+100);
                }
            };
        }.start();
    }

}

Demo4:
设置一个页面,每一秒切换一张图片同时中间有秒倒计时

public class MainActivity extends Activity {

    private TextView txtShow = null;
    private ImageView ivShow = null;
    private List<Drawable> list = null;

    private boolean flag = true;
    private int index = 0;
    private int remain = 60;

    private Handler clockHandler = new Handler();

    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
            case 0:
                ivShow.setImageDrawable(list.get(index++));

                if (index == list.size()) {
                    index = 0;
                }
                break;

            default:
                break;
            }
        }
    };

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

        initView();

        setData();

        switchImage();

        setTime();
    }

    private void setTime() {
        new Thread() {
            public void run() {
                /** 
                 * 通过handler的post方法将Runnable对象发送到消息队列中
                 * 该Runnable将附加在当前handler定义的线程中即主线程中执行
                 * 此处如果使用的handler为设置图片的handler,则设置图片与设置时间会有先后(添加在一个队列中)
                 */
                clockHandler.post(new Runnable() {

                    @Override
                    public void run() {
                        remain--;

                        if (remain < 0) {
                            flag = false;
                            txtShow.setText("还看");
                        } else {
                            txtShow.setText("remain:" + remain);
                        }
                        /**
                         * handler的postDelayed(Runnable,delay)方法,
                         * 将此Runnable对象发送到消息队列中,延时delay时间后run
                         */
                        clockHandler.postDelayed(this, 1000);
                    }
                });
            };
        }.start();
    }

    private void switchImage() {
        new Thread() {
            public void run() {
                while (flag) {
                    Message msg = Message.obtain();

                    handler.sendEmptyMessage(0);

                    SystemClock.sleep(1000);
                }
            };
        }.start();
    }

    private void setData() {
        // getResources().obtainTypedArray()根据普通数组资源名称获取实际普通数组
        // 获得资源文件中TypeArray对象
        TypedArray typedArray = getResources().obtainTypedArray(
                R.array.arraysImgs);

        list = new ArrayList<Drawable>();
        for (int i = 0; i < typedArray.length(); i++) {
            list.add(typedArray.getDrawable(i));
        }
    }

    private void initView() {
        txtShow = (TextView) findViewById(R.id.txtShow);
        ivShow = (ImageView) findViewById(R.id.ivShow);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

}
2025-09-19 13:11:07.204 [lettuce-nioEventLoop-4-1] DEBUG io.lettuce.core.protocol.CommandHandler - [channel=0x69b8c689, /127.0.0.1:22669 -> localhost/127.0.0.1:6379, epid=0x1, chid=0x1] write(ctx, AsyncCommand [type=DEL, output=IntegerOutput [output=null, error='null'], commandType=io.lettuce.core.protocol.Command], promise) 2025-09-19 13:11:07.205 [lettuce-nioEventLoop-4-1] DEBUG io.lettuce.core.protocol.CommandEncoder - [channel=0x69b8c689, /127.0.0.1:22669 -> localhost/127.0.0.1:6379] writing command AsyncCommand [type=DEL, output=IntegerOutput [output=null, error='null'], commandType=io.lettuce.core.protocol.Command] 2025-09-19 13:11:07.205 [lettuce-nioEventLoop-4-1] DEBUG io.lettuce.core.protocol.CommandHandler - [channel=0x69b8c689, /127.0.0.1:22669 -> localhost/127.0.0.1:6379, epid=0x1, chid=0x1] Received: 4 bytes, 1 commands in the stack 2025-09-19 13:11:07.205 [lettuce-nioEventLoop-4-1] DEBUG io.lettuce.core.protocol.CommandHandler - [channel=0x69b8c689, /127.0.0.1:22669 -> localhost/127.0.0.1:6379, epid=0x1, chid=0x1] Stack contains: 1 commands 2025-09-19 13:11:07.206 [lettuce-nioEventLoop-4-1] DEBUG io.lettuce.core.protocol.RedisStateMachine - Decode done, empty stack: true 2025-09-19 13:11:07.209 [lettuce-nioEventLoop-4-1] DEBUG io.lettuce.core.protocol.CommandHandler - [channel=0x69b8c689, /127.0.0.1:22669 -> localhost/127.0.0.1:6379, epid=0x1, chid=0x1] Completing command LatencyMeteredCommand [type=DEL, output=IntegerOutput [output=1, error='null'], commandType=io.lettuce.core.protocol.AsyncCommand] 2025-09-19 13:11:07.209 [scheduling-1] DEBUG o.s.data.redis.core.RedisConnectionUtils - Closing Redis Connection. 2025-09-19 13:11:07.210 [scheduling-1] INFO c.hvlink.service.impl.SyncPlanProtocolServiceImpl - ======================结束了===========================计划协议同步任务锁已释放 2025-09-19 13:11:07.212 [scheduling-1] DEBUG o.s.jdbc.datasource.DataSourceTransactionManager - Initiating transaction rollback 2025-09-19 13:11:07.212 [scheduling-1] DEBUG o.s.jdbc.datasource.DataSourceTransactionManager - Rolling back JDBC transaction on Connection [ConnectionID:1 ClientConnectionId: 99d645c0-e5d6-4b9d-a421-952766829756] 2025-09-19 13:11:07.224 [scheduling-1] DEBUG o.s.jdbc.datasource.DataSourceTransactionManager - Releasing JDBC Connection [ConnectionID:1 ClientConnectionId: 99d645c0-e5d6-4b9d-a421-952766829756] after transaction 2025-09-19 13:11:07.226 [scheduling-1] ERROR o.s.s.support.TaskUtils$LoggingErrorHandler - Unexpected error occurred in scheduled task java.lang.RuntimeException: java.lang.IllegalArgumentException: Result Maps collection does not contain value for com.hvlink.entity.dto.order.PurchaseOrderMainDTO at com.hvlink.service.impl.SyncPlanProtocolServiceImpl.syncPurchaseOrderData(SyncPlanProtocolServiceImpl.java:189) at com.hvlink.service.impl.SyncPlanProtocolServiceImpl$$FastClassBySpringCGLIB$$fba6dd9d.invoke(<generated>) at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:218) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:792) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:762) at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:123) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:388) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:762) at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:707) at com.hvlink.service.impl.SyncPlanProtocolServiceImpl$$EnhancerBySpringCGLIB$$38999a59.syncPurchaseOrderData(<generated>) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:84) at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:750) Caused by: java.lang.IllegalArgumentException: Result Maps collection does not contain value for com.hvlink.entity.dto.order.PurchaseOrderMainDTO at com.baomidou.mybatisplus.core.MybatisConfiguration$StrictMap.get(MybatisConfiguration.java:454) at com.baomidou.mybatisplus.core.MybatisConfiguration.getResultMap(MybatisConfiguration.java:293) at org.apache.ibatis.builder.MapperBuilderAssistant.getStatementResultMaps(MapperBuilderAssistant.java:394) at org.apache.ibatis.builder.MapperBuilderAssistant.addMappedStatement(MapperBuilderAssistant.java:285) at org.apache.ibatis.builder.xml.XMLStatementBuilder.parseStatementNode(XMLStatementBuilder.java:113) at org.apache.ibatis.session.Configuration.lambda$buildAllStatements$2(Configuration.java:914) at java.util.Collection.removeIf(Collection.java:414) at org.apache.ibatis.session.Configuration.buildAllStatements(Configuration.java:913) at com.baomidou.mybatisplus.core.MybatisConfiguration.hasStatement(MybatisConfiguration.java:359) at org.apache.ibatis.session.Configuration.hasStatement(Configuration.java:885) at org.apache.ibatis.binding.MapperMethod$SqlCommand.resolveMappedStatement(MapperMethod.java:257) at org.apache.ibatis.binding.MapperMethod$SqlCommand.<init>(MapperMethod.java:227) at com.baomidou.mybatisplus.core.override.MybatisMapperMethod.<init>(MybatisMapperMethod.java:50) at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.lambda$cachedInvoker$0(MybatisMapperProxy.java:111) at java.util.concurrent.ConcurrentHashMap.computeIfAbsent(ConcurrentHashMap.java:1660) at com.baomidou.mybatisplus.core.toolkit.CollectionUtils.computeIfAbsent(CollectionUtils.java:115) at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.cachedInvoker(MybatisMapperProxy.java:98) at com.baomidou.mybatisplus.core.override.MybatisMapperProxy.invoke(MybatisMapperProxy.java:89) at com.sun.proxy.$Proxy116.queryExistingApprovalCodes(Unknown Source) at com.hvlink.service.impl.SyncPlanProtocolServiceImpl.getLatestOrderDetailsList(SyncPlanProtocolServiceImpl.java:541) at com.hvlink.service.impl.SyncPlanProtocolServiceImpl.syncPurchaseOrderData(SyncPlanProtocolServiceImpl.java:139) ... 25 common frames omitted 2025-09-19 13:11:07.251 [RMI TCP Connection(1)-2.0.0.1] DEBUG o.springframework.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource 2025-09-19 13:11:07.261 [RMI TCP Connection(1)-2.0.0.1] DEBUG o.springframework.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource 2025-09-19 13:11:07.546 [RMI TCP Connection(1)-2.0.0.1] INFO com.alibaba.druid.pool.DruidDataSource - {dataSource-2} inited 2025-09-19 13:11:07.680 [RMI TCP Connection(1)-2.0.0.1] DEBUG o.springframework.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource 2025-09-19 13:11:07.705 [RMI TCP Connection(1)-2.0.0.1] DEBUG o.springframework.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource 2025-09-19 13:11:07.706 [RMI TCP Connection(1)-2.0.0.1] DEBUG o.springframework.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource 2025-09-19 13:11:07.741 [RMI TCP Connection(1)-2.0.0.1] DEBUG o.springframework.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource 2025-09-19 13:11:07.741 [RMI TCP Connection(1)-2.0.0.1] DEBUG o.springframework.jdbc.datasource.DataSourceUtils - Fetching JDBC Connection from DataSource 2025-09-19 13:11:07.892 [boundedElastic-1] DEBUG io.lettuce.core.RedisClient - Trying to get a Redis connection for: redis://localhost 2025-09-19 13:11:07.893 [boundedElastic-1] DEBUG io.lettuce.core.RedisClient - Resolved SocketAddress localhost:6379 using redis://localhost 2025-09-19 13:11:07.893 [boundedElastic-1] DEBUG io.lettuce.core.AbstractRedisClient - Connecting to Redis at localhost:6379 2025-09-19 13:11:07.895 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.CommandHandler - [channel=0x3f3b2d91, [id: 0x2d015132] (inactive), epid=0x2, chid=0x2] channelRegistered() 2025-09-19 13:11:07.897 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.CommandHandler - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379, epid=0x2, chid=0x2] write(ctx, AsyncCommand [type=HELLO, output=GenericMapOutput [output=null, error='null'], commandType=io.lettuce.core.protocol.Command], promise) 2025-09-19 13:11:07.897 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.CommandEncoder - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379] writing command AsyncCommand [type=HELLO, output=GenericMapOutput [output=null, error='null'], commandType=io.lettuce.core.protocol.Command] 2025-09-19 13:11:07.897 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.CommandHandler - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379, epid=0x2, chid=0x2] Received: 30 bytes, 1 commands in the stack 2025-09-19 13:11:07.897 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.CommandHandler - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379, epid=0x2, chid=0x2] Stack contains: 1 commands 2025-09-19 13:11:07.897 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.RedisStateMachine - Decode done, empty stack: true 2025-09-19 13:11:07.900 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.CommandHandler - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379, epid=0x2, chid=0x2] Completing command LatencyMeteredCommand [type=HELLO, output=GenericMapOutput [output=null, error='ERR unknown command 'HELLO''], commandType=io.lettuce.core.protocol.AsyncCommand] 2025-09-19 13:11:07.900 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.CommandHandler - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379, epid=0x2, chid=0x2] write(ctx, AsyncCommand [type=PING, output=StatusOutput [output=null, error='null'], commandType=io.lettuce.core.protocol.Command], promise) 2025-09-19 13:11:07.900 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.CommandEncoder - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379] writing command AsyncCommand [type=PING, output=StatusOutput [output=null, error='null'], commandType=io.lettuce.core.protocol.Command] 2025-09-19 13:11:07.901 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.CommandHandler - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379, epid=0x2, chid=0x2] Received: 7 bytes, 1 commands in the stack 2025-09-19 13:11:07.901 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.CommandHandler - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379, epid=0x2, chid=0x2] Stack contains: 1 commands 2025-09-19 13:11:07.927 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.RedisStateMachine - Decode done, empty stack: true 2025-09-19 13:11:07.927 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.CommandHandler - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379, epid=0x2, chid=0x2] Completing command LatencyMeteredCommand [type=PING, output=StatusOutput [output=PONG, error='null'], commandType=io.lettuce.core.protocol.AsyncCommand] 2025-09-19 13:11:07.927 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.CommandHandler - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379, epid=0x2, chid=0x2] channelActive() 2025-09-19 13:11:07.927 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.DefaultEndpoint - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379, epid=0x2] activateEndpointAndExecuteBufferedCommands 0 command(s) buffered 2025-09-19 13:11:07.927 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.DefaultEndpoint - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379, epid=0x2] activating endpoint 2025-09-19 13:11:07.927 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.DefaultEndpoint - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379, epid=0x2] flushCommands() 2025-09-19 13:11:07.927 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.DefaultEndpoint - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379, epid=0x2] flushCommands() Flushing 0 commands 2025-09-19 13:11:07.927 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.ConnectionWatchdog - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379, last known addr=localhost/127.0.0.1:6379] channelActive() 2025-09-19 13:11:07.927 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.CommandHandler - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379, epid=0x2, chid=0x2] channelActive() done 2025-09-19 13:11:07.927 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.AbstractRedisClient - Connecting to Redis at localhost:6379: Success 2025-09-19 13:11:07.988 [boundedElastic-1] DEBUG io.lettuce.core.RedisChannelHandler - dispatching command SubscriptionCommand [type=INFO, output=StatusOutput [output=null, error='null'], commandType=io.lettuce.core.protocol.Command] 2025-09-19 13:11:07.988 [boundedElastic-1] DEBUG io.lettuce.core.protocol.DefaultEndpoint - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379, epid=0x2] write() writeAndFlush command SubscriptionCommand [type=INFO, output=StatusOutput [output=null, error='null'], commandType=io.lettuce.core.protocol.Command] 2025-09-19 13:11:07.997 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.CommandHandler - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379, epid=0x2, chid=0x2] write(ctx, SubscriptionCommand [type=INFO, output=StatusOutput [output=null, error='null'], commandType=io.lettuce.core.protocol.Command], promise) 2025-09-19 13:11:07.997 [boundedElastic-1] DEBUG io.lettuce.core.protocol.DefaultEndpoint - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379, epid=0x2] write() done 2025-09-19 13:11:07.998 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.CommandEncoder - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379] writing command SubscriptionCommand [type=INFO, output=StatusOutput [output=null, error='null'], commandType=io.lettuce.core.protocol.Command] 2025-09-19 13:11:07.999 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.CommandHandler - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379, epid=0x2, chid=0x2] Received: 365 bytes, 1 commands in the stack 2025-09-19 13:11:07.999 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.CommandHandler - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379, epid=0x2, chid=0x2] Stack contains: 1 commands 2025-09-19 13:11:07.999 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.RedisStateMachine - Decode done, empty stack: true 2025-09-19 13:11:08.005 [lettuce-nioEventLoop-4-2] DEBUG io.lettuce.core.protocol.CommandHandler - [channel=0x3f3b2d91, /127.0.0.1:22683 -> localhost/127.0.0.1:6379, epid=0x2, chid=0x2] Completing command LatencyMeteredCommand [type=INFO, output=StatusOutput [output=# Server redis_version:3.0.504 redis_git_sha1:00000000 redis_git_dirty:0 redis_build_id:a4f7a6e86f2d60b3 redis_mode:standalone os:Windows arch_bits:64 multiplexing_api:WinSock_IOCP process_id:904 run_id:a7d2e2bdc458123d1f1f741d8bf2bf35dcd84801 tcp_port:6379 uptime_in_seconds:187271 uptime_in_days:2 hz:10 lru_clock:13428203 config_file: , error='null'], commandType=io.lettuce.core.RedisPublisher$SubscriptionCommand]
09-20
AI 代码审查Review工具 是一个旨在自动化代码审查流程的工具。它通过集成版本控制系统(如 GitHub 和 GitLab)的 Webhook,利用大型语言模型(LLM)对代码变更进行分析,并将审查意见反馈到相应的 Pull Request 或 Merge Request 中。此外,它还支持将审查结果通知到企业微信等通讯工具。 一个基于 LLM 的自动化代码审查助手。通过 GitHub/GitLab Webhook 监听 PR/MR 变更,调用 AI 分析代码,并将审查意见自动评论到 PR/MR,同时支持多种通知渠道。 主要功能 多平台支持: 集成 GitHub 和 GitLab Webhook,监听 Pull Request / Merge Request 事件。 智能审查模式: 详细审查 (/github_webhook, /gitlab_webhook): AI 对每个变更文件进行分析,旨在找出具体问题。审查意见会以结构化的形式(例如,定位到特定代码行、问题分类、严重程度、分析和建议)逐条评论到 PR/MR。AI 模型会输出 JSON 格式的分析结果,系统再将其转换为多条独立的评论。 通用审查 (/github_webhook_general, /gitlab_webhook_general): AI 对每个变更文件进行整体性分析,并为每个文件生成一个 Markdown 格式的总结性评论。 自动化流程: 自动将 AI 审查意见(详细模式下为多条,通用模式下为每个文件一条)发布到 PR/MR。 在所有文件审查完毕后,自动在 PR/MR 中发布一条总结性评论。 即便 AI 未发现任何值得报告的问题,也会发布相应的友好提示和总结评论。 异步处理审查任务,快速响应 Webhook。 通过 Redis 防止对同一 Commit 的重复审查。 灵活配置: 通过环境变量设置基
【直流微电网】径向直流微电网的状态空间建模与线性化:一种耦合DC-DC变换器状态空间平均模型的方法 (Matlab代码实现)内容概要:本文介绍了径向直流微电网的状态空间建模与线性化方法,重点提出了一种基于耦合DC-DC变换器的状态空间平均模型的建模策略。该方法通过数学建模手段对直流微电网系统进行精确的状态空间描述,并对其进行线性化处理,以便于系统稳定性分析与控制器设计。文中结合Matlab代码实现,展示了建模与仿真过程,有助于研究人员理解和复现相关技术,推动直流微电网系统的动态性能研究与工程应用。; 适合人群:具备电力电子、电力系统或自动化等相关背景,熟悉Matlab/Simulink仿真工具,从事新能源、微电网或智能电网研究的研究生、科研人员及工程技术人员。; 使用场景及目标:①掌握直流微电网的动态建模方法;②学习DC-DC变换器在耦合条件下的状态空间平均建模技巧;③实现系统的线性化分析并支持后续控制器设计(如电压稳定控制、功率分配等);④为科研论文撰写、项目仿真验证提供技术支持与代码参考。; 阅读建议:建议读者结合Matlab代码逐步实践建模流程,重点关注状态变量选取、平均化处理和线性化推导过程,同时可扩展应用于更复杂的直流微电网拓扑结构中,提升系统分析与设计能力。
内容概要:本文介绍了基于物PINN驱动的三维声波波动方程求解(Matlab代码实现)理信息神经网络(PINN)求解三维声波波动方程的Matlab代码实现方法,展示了如何利用PINN技术在无需大量标注数据的情况下,结合物理定律约束进行偏微分方程的数值求解。该方法将神经网络与物理方程深度融合,适用于复杂波动问题的建模与仿真,并提供了完整的Matlab实现方案,便于科研人员理解和复现。此外,文档还列举了多个相关科研方向和技术服务内容,涵盖智能优化算法、机器学习、信号处理、电力系统等多个领域,突出其在科研仿真中的广泛应用价值。; 适合人群:具备一定数学建模基础和Matlab编程能力的研究生、科研人员及工程技术人员,尤其适合从事计算物理、声学仿真、偏微分方程数值解等相关领域的研究人员; 使用场景及目标:①学习并掌握PINN在求解三维声波波动方程中的应用原理与实现方式;②拓展至其他物理系统的建模与仿真,如电磁场、热传导、流体力学等问题;③为科研项目提供可复用的代码框架和技术支持参考; 阅读建议:建议读者结合文中提供的网盘资源下载完整代码,按照目录顺序逐步学习,重点关注PINN网络结构设计、损失函数构建及物理边界条件的嵌入方法,同时可借鉴其他案例提升综合仿真能力。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值