Android Studio App开发中多线程的讲解与实现新闻轮播滚动实战(附源码 超详细必看)

简介: Android Studio App开发中多线程的讲解与实现新闻轮播滚动实战(附源码 超详细必看)

运行有问题或需要源码请点赞关注收藏后评论区留言 ~~~

一、分线程通过Handler操作界面

为了使App运行的更加流畅,多线程技术被广泛应用于App开发,由于Android规定只有主线程才能直接操作界面,因此分线程若想修改界面就要另想办法,这要求有一种在线程之间相互通信的机制,如果是主线程向分线程传递消息,可以在分线程的构造方法中传递参数,然而分线程向主线程传递消息并无捷径,为此Android设计了一个Message消息工具,通过结合Handler与Message能够实现线程间通信

由分线程向主线程传递消息的过程主要有四个步骤

1:在主线程中构造一个处理器对象 并启动分线程

2:在分线程中构造一个Message类型的消息包

3:在分线程中通过处理器对象将Message消息发出去

4:主线程的Handler对象处理接收到的消息

综合上面的四个线程通信步骤,接下来通过一个实验观察线程间通信的效果,下面便是利用多线程技术实现新闻滚动的例子

点击开始播放新闻后便会自动播放,每隔两秒钟弹出一条新闻

点击停止播放新闻则停止播放

根据以上的新闻播放效果,可以知道分线程的播放开始和播放结束指令都成功送到了主线程

代码如下

Java类

package com.example.chapter11;
import android.annotation.SuppressLint;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.Gravity;
import android.view.View;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import com.example.chapter11.util.DateUtil;
import java.util.Random;
@SuppressLint("HandlerLeak")
public class HandlerMessageActivity extends AppCompatActivity implements View.OnClickListener {
    private TextView tv_message; // 声明一个文本视图对象
    private boolean isPlaying = false; // 是否正在播放新闻
    private int BEGIN = 0, SCROLL = 1, END = 2; // 0为开始,1为滚动,2为结束
    private String[] mNewsArray = { "北斗导航系统正式开通,定位精度媲美GPS",
            "黑人之死引发美国各地反种族主义运动", "印度运营商禁止华为中兴反遭诺基亚催债",
            "贝鲁特发生大爆炸全球紧急救援黎巴嫩", "日本货轮触礁毛里求斯造成严重漏油污染"
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_handler_message);
        tv_message = findViewById(R.id.tv_message);
        findViewById(R.id.btn_start).setOnClickListener(this);
        findViewById(R.id.btn_stop).setOnClickListener(this);
    }
    @Override
    public void onClick(View v) {
        if (v.getId() == R.id.btn_start) { // 点击了开始播放新闻的按钮
            if (!isPlaying) { // 如果不在播放就开始播放
                isPlaying = true;
                new PlayThread().start(); // 创建并启动新闻播放线程
            }
        } else if (v.getId() == R.id.btn_stop) { // 点击了结束播放新闻的按钮
            isPlaying = false;
        }
    }
    // 定义一个新闻播放线程
    private class PlayThread extends Thread {
        @Override
        public void run() {
            mHandler.sendEmptyMessage(BEGIN); // 向处理器发送播放开始的空消息
            while (isPlaying) { // 正在播放新闻
                try {
                    sleep(2000); // 睡眠两秒(2000毫秒)
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                Message message = Message.obtain(); // 获得默认的消息对象
                //Message message = mHandler.obtainMessage(); // 获得处理器的消息对象
                message.what = SCROLL; // 消息类型
                message.obj = mNewsArray[new Random().nextInt(5)]; // 消息描述
                mHandler.sendMessage(message); // 向处理器发送消息
            }
            mHandler.sendEmptyMessage(END); // 向处理器发送播放结束的空消息
            // 如果只要简单处理,也可绕过Handler,直接调用runOnUiThread方法操作界面
//            runOnUiThread(new Runnable() {
//                @Override
//                public void run() {
//                    String desc = String.format("%s\n%s %s", tv_message.getText().toString(), DateUtil.getNowTime(), "新闻播放结束,谢谢观看");
//                    tv_message.setText(desc);
//                }
//            });
            isPlaying = false;
        }
    }
    // 创建一个处理器对象
    private Handler mHandler = new Handler() {
        // 在收到消息时触发
        public void handleMessage(Message msg) {
            String desc = tv_message.getText().toString();
            if (msg.what == BEGIN) { // 开始播放
                desc = String.format("%s\n%s %s", desc, DateUtil.getNowTime(), "开始播放新闻");
            } else if (msg.what == SCROLL) { // 滚动播放
                desc = String.format("%s\n%s %s", desc, DateUtil.getNowTime(), msg.obj);
            } else if (msg.what == END) { // 结束播放
                desc = String.format("%s\n%s %s", desc, DateUtil.getNowTime(), "新闻播放结束");
            }
            tv_message.setText(desc);
        }
    };
}

时间类

package com.example.chapter11.util;
import android.annotation.SuppressLint;
import android.text.TextUtils;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
@SuppressLint("SimpleDateFormat")
public class DateUtil {
    // 获取当前的日期时间
    public static String getNowDateTime(String formatStr) {
        String format = formatStr;
        if (TextUtils.isEmpty(format)) {
            format = "yyyyMMddHHmmss";
        }
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        return sdf.format(new Date());
    }
    // 获取当前的时间
    public static String getNowTime() {
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
        return sdf.format(new Date());
    }
    // 获取当前的时间(精确到毫秒)
    public static String getNowTimeDetail() {
        SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss.SSS");
        return sdf.format(new Date());
    }
    public static String getNowDate() {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
        return sdf.format(new Date());
    }
    public static String getDate(Calendar calendar) {
        Date date = calendar.getTime();
        // 创建一个日期格式化的工具
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        // 将当前日期时间按照指定格式输出格式化后的日期时间字符串
        return sdf.format(date);
    }
    public static String getMonth(Calendar calendar) {
        Date date = calendar.getTime();
        // 创建一个日期格式化的工具
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM");
        // 将当前日期时间按照指定格式输出格式化后的日期时间字符串
        return sdf.format(date);
    }
    public static Date formatString(String strTime) {
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        try {
            date = sdf.parse(strTime);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return date;
    }
}

XML文件

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="horizontal" >
        <Button
            android:id="@+id/btn_start"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="开始播放新闻"
            android:textColor="@color/black"
            android:textSize="17sp" />
        <Button
            android:id="@+id/btn_stop"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_weight="1"
            android:text="停止播放新闻"
            android:textColor="@color/black"
            android:textSize="17sp" />
    </LinearLayout>
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="180dp"
        android:orientation="vertical" >
        <TextView
            android:id="@+id/tv_message"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:paddingLeft="5dp"
            android:scrollbars="vertical"
            android:gravity="left|bottom"
            android:maxLines="9"
            android:textColor="@color/black"
            android:textSize="15sp" />
    </LinearLayout>
</LinearLayout>

创作不易 觉得有帮助请点赞关注收藏~~~

相关文章
|
Android开发 数据安全/隐私保护 开发者
Android自定义view之模仿登录界面文本输入框(华为云APP)
本文介绍了一款自定义输入框的实现,包含静态效果、hint值浮动动画及功能扩展。通过组合多个控件完成界面布局,使用TranslateAnimation与AlphaAnimation实现hint文字上下浮动效果,支持密码加密解密显示、去除键盘回车空格输入、光标定位等功能。代码基于Android平台,提供完整源码与attrs配置,方便复用与定制。希望对开发者有所帮助。
373 0
|
存储 Android开发 数据安全/隐私保护
Thanox安卓系统增加工具下载,管理、阻止、限制后台每个APP运行情况
Thanox是一款Android系统管理工具,专注于权限、后台启动及运行管理。支持应用冻结、系统优化、UI自定义和模块管理,基于Xposed框架开发,安全可靠且开源免费,兼容Android 6.0及以上版本。
1869 4
|
数据采集 JSON 网络安全
移动端数据抓取:Android App的TLS流量解密方案
本文介绍了一种通过TLS流量解密技术抓取知乎App热榜数据的方法。利用Charles Proxy解密HTTPS流量,分析App与服务器通信内容;结合Python Requests库模拟请求,配置特定请求头以绕过反爬机制。同时使用代理IP隐藏真实IP地址,确保抓取稳定。最终成功提取热榜标题、内容简介、链接等信息,为分析热点话题和用户趋势提供数据支持。此方法也可应用于其他Android App的数据采集,但需注意选择可靠的代理服务。
804 11
移动端数据抓取:Android App的TLS流量解密方案
|
Java 中间件 调度
【源码】【Java并发】从InheritableThreadLocal和TTL源码的角度来看父子线程传递
本文涉及InheritableThreadLocal和TTL,从源码的角度,分别分析它们是怎么实现父子线程传递的。建议先了解ThreadLocal。
662 4
【源码】【Java并发】从InheritableThreadLocal和TTL源码的角度来看父子线程传递
|
安全 Java 调度
Netty源码—3.Reactor线程模型二
本文主要介绍了NioEventLoop的执行总体框架、Reactor线程执行一次事件轮询、Reactor线程处理产生IO事件的Channel、Reactor线程处理任务队列之添加任务、Reactor线程处理任务队列之执行任务、NioEventLoop总结。
|
安全 Java
Netty源码—2.Reactor线程模型一
本文主要介绍了关于NioEventLoop的问题整理、理解Reactor线程模型主要分三部分、NioEventLoop的创建和NioEventLoop的启动。
|
Java 调度
【源码】【Java并发】【线程池】邀请您从0-1阅读ThreadPoolExecutor源码
当我们创建一个`ThreadPoolExecutor`的时候,你是否会好奇🤔,它到底发生了什么?比如:我传的拒绝策略、线程工厂是啥时候被使用的? 核心线程数是个啥?最大线程数和它又有什么关系?线程池,它是怎么调度,我们传入的线程?...不要着急,小手手点上关注、点赞、收藏。主播马上从源码的角度带你们探索神秘线程池的世界...
708 0
【源码】【Java并发】【线程池】邀请您从0-1阅读ThreadPoolExecutor源码
|
缓存 移动开发 JavaScript
如何优化UniApp开发的App的启动速度?
如何优化UniApp开发的App的启动速度?
1867 139
|
移动开发 JavaScript weex
UniApp开发的App在启动速度方面有哪些优势和劣势?
UniApp开发的App在启动速度方面有哪些优势和劣势?
843 137

热门文章

最新文章