appA拉起appB 如果appB已经在后台运行 获取不到参数的解决

本文主要探讨了在Android中,当appA尝试拉起已经处于后台运行状态的appB时,如何解决获取不到参数的问题。通过调整AndroidManifest.xml配置,特别是考虑singleInstance模式下可能出现的动画不一致和黑屏现象,提供了相应的解决方案,包括自定义启动和关闭动画以及设置界面主题样式。

appA 应用

/**
     * 通过包名拉起app
     * @param packagename  要拉起app的包名
     */
    public static void doStartApplicationWithPackageName(String packagename) {
        // 通过包名获取要跳转的app,创建intent对象
        Intent intent = PageManager.getCurrentActivity().getPackageManager().getLaunchIntentForPackage(packagename);
        //测试参数随机数
        Random rd = new Random();
        // 这里如果intent为空,就说名没有安装要跳转的应用嘛
        if (intent != null) {
            // 这里跟Activity传递参数一样的嘛,不要担心怎么传递参数,还有接收参数也是跟Activity和Activity传参数一样
            intent.putExtra("name", "name"+":"+rd.nextInt(100));
            intent.putExtra("birthday", "birthday"+":"+rd.nextInt(100));
            PageManager.getCurrentActivity().startActivity(intent);
        } else {
            // 没有安装要跳转的app应用,提醒一下
            Toast.makeText(PageManager.getCurrentActivity().getApplicationContext(), "哟,赶紧下载安装这个APP吧", Toast.LENGTH_LONG).show();
        }
    }

appB应用

AndroidManifest.xml

<activity android:name=".WellcomeActivity"
            android:launchMode="singleInstance"><!--必须设置成这个模式-->
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.DEFAULT"/>
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

启动页面可以获取到参数 根据参数跳转不同页面  有可能singleInstance加载动画和我们应用内部加载动画不一致 我们也可以自定activity启动关闭动画

public class WellcomeActivity extends AppCompatActivity {
    private final static int MSG_200 = 200;
    Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
                case MSG_200:
                    Intent intent = new Intent(WellcomeActivity.this, MainActivity.class);
                    startActivity(intent);
                    overridePendingTransition(R.anim.right_in,R.anim.right_out);//为了使动画统一
                    finish();
                    break;
                default:
                    break;
            }
        }
    };
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_wellcome);
        Intent intent = getIntent();
        Bundle bundle = intent.getExtras();
        if (bundle != null) {
            String name = bundle.getString("name");
            String birthday = bundle.getString("birthday");
            if (name != null && birthday != null) {
                Toast.makeText(getApplicationContext(), "name:" + name + "    birthday:" + birthday, Toast.LENGTH_SHORT).show();
            }
        }
        mHandler.sendEmptyMessageDelayed(MSG_200, 3000);
    }
    @Override
    public void finish() {
        super.finish();
        overridePendingTransition(R.anim.right_in,R.anim.right_out);//为了使动画统一
    }
}

right_in.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:fromXDelta="100%p"
        android:toXDelta="0"
        android:duration="300"/>
</set>

right_out.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android">
    <translate
        android:fromXDelta="0"
        android:toXDelta="-100%p"
        android:duration="300"/>
</set>

注意:设置singleInstance 打开另一个界面黑屏解决

另一个界面的主题样式需要加上  

<item name="android:windowIsTranslucent">true</item>

效果图

 

 

 

 

 

 

<think> 我们有两个消费者:一个使用concurrency=2(即两个消费者线程),另一个是独立的消费者(一个线程)。它们都在同一个消费组中。 注意:题目要求“同一个消费组3个消费者”,其中两个是由concurrency=2产生的,另一个是独立的(独立进程?)。但是,在Spring Boot中,通常我们会在同一个项目中编写多个消费者,然后通过配置来启动多个消费者实例(例如,使用不同的端口启动多个实例)或者在一个实例中使用多个线程。 然而,题目要求有一个是“独立的进程”,这意味着我们不能只在一个Spring Boot应用中启动所有消费者(因为这样它们都在同一个JVM中)。因此,我们需要运行两个Spring Boot应用: 1. 第一个Spring Boot应用:包含生产者和一个消费者(使用concurrency=2,即两个线程)。我们称之为主应用。 2. 第二个Spring Boot应用:只包含另一个独立的消费者(一个线程)。注意,这个应用需要配置相同的消费组ID。 但请注意:题目要求“启动1个生产者和同一个消费组3个消费者”,并且要求关闭concurrency=2的消费者(即关闭第一个应用中的消费者监听容器)后观察剩余消费者(第二个应用中的消费者)的变化。 因此,我们需要两个独立的Spring Boot应用(两个进程): 应用A:包含生产者、Consumer1(使用@KafkaListener(concurrency=2)) -> 这将启动两个消费者线程(同一个组内的两个消费者实例)。 应用B:包含Consumer2(一个消费者线程) -> 同一个消费组,因此消费组内共有三个消费者实例。 注意:由于应用A和应用B都是独立的进程,所以我们需要分别打包并运行。 具体步骤: 1. 创建Spring Boot项目(一个项目,但通过不同配置运行两个进程): 我们可以创建两个主类,或者更简单的方式是:将应用A和应用B的代码放在同一个项目中,然后通过不同的配置文件(或命令行参数)来运行两次,指定不同的端口和消费者配置(注意:应用B只需要消费者,不需要生产者,但为了简单,我们可以让两个应用都有相同的代码,但在应用B中禁用生产者相关的功能?或者我们分开写) 另一种做法:创建两个独立的项目,但共享相同的消费者代码。但为了作业方便,我们可以在一个项目中实现,然后通过配置来区分。 这里我们采用一个项目,通过不同的配置文件(application-appA.yml和application-appB.yml)来启动两个进程。 2. 项目结构: - 生产者代码(在应用A中启用,在应用B中不启用?但应用B不需要生产者,所以我们可以将生产者放在一个单独的配置中,或者通过条件注解来控制) - 消费者1(concurrency=2)在应用A中启用 - 消费者2(独立)在应用B中启用 3. 如何运行: 步骤1:打包项目(生成一个jar包) 步骤2:分别使用两个不同的配置文件(或通过命令行参数运行两次: java -jar kafka-demo.jar --spring.profiles.active=appA --server.port=8080 java -jar kafka-demo.jar --spring.profiles.active=appB --server.port=8081 4. 配置消费者组:两个应用配置相同的消费组ID(在各自的配置文件中设置相同的group-id)。 5. 注意:由于我们的消费者监听同一个主题,且都在同一个消费组,所以分区会被分配给三个消费者实例(两个来自应用A,一个来自应用B)。 6. 关闭concurrency=2的消费者:即停止应用A(或者停止应用A中的消费者容器,但题目要求关闭concurrency=2的消费者,我们可以停止应用A进程)。 7. 观察应用B(独立消费者)的日志:它将接管原来由应用A的两个消费者线程处理的分区,进行再平衡。 具体代码调整: 为了避免应用A和应用B的干扰,我们可以使用Spring Profile来条件化创建Bean。 例如: 在应用A的配置(appA)中,我们创建生产者和Consumer1(concurrency=2),不创建Consumer2。 在应用B的配置(appB)中,我们创建Consumer2,不创建生产者和Consumer1。 配置示例: 创建两个配置文件:application-appA.yml 和 application-appB.yml。 application-appA.yml: spring.kafka.consumer.group-id: test-group server.port: 8080 # 其他配置 application-appB.yml: spring.kafka.consumer.group-id: test-group # 同一个消费组 server.port: 8081 代码中: 生产者Controller:我们加上条件注解,只有在appA环境下才生效。 Consumer1:只有在appA环境下才生效。 Consumer2:只有在appB环境下才生效。 示例: ```java @RestController @Profile("appA") public class ProducerController { ... } @Component @Profile("appA") public class Consumer1 { ... } @Component @Profile("appB") public class Consumer2 { ... } ``` 这样,当我们用appA配置启动时,只有生产者和Consumer1被创建;用appB配置启动时,只有Consumer2被创建。 然后按照以下步骤操作: 1. 启动Kafka(在虚拟机中) 2. 启动应用A(appA,端口8080) 3. 启动应用B(appB,端口8081) 4. 访问应用A的生产者接口:http://localhost:8080/send 发送消息 5. 观察应用A和应用B的控制台日志(三个消费者线程在消费) 6. 停止应用A(模拟关闭concurrency=2的消费者) 7. 观察应用B的控制台日志(再平衡后,应用B的消费者接管所有分区) 这样就能满足题目要求。 注意:如果主题有3个分区,那么一开始分区会被分配给三个消费者(应用A的两个线程和应用B的一个线程),每个消费者负责一个分区。当应用A停止后,应用B的消费者会重新分配,接管三个分区。 因此,回答用户的问题:不能都写在一个Spring Boot进程里,因为题目要求有一个独立的进程(即应用B)。我们需要运行两个进程(同一个jar包运行两次,使用不同的profile)。 运行步骤总结: 1. 打包项目:mvn clean package 2. 启动应用A:java -jar target/demo.jar --spring.profiles.active=appA 3. 启动应用B:java -jar target/demo.jar --spring.profiles.active=appB 这样,三个消费者就分布在两个进程中(进程A有两个消费者线程,进程B有一个消费者线程)。 最后,按照题目要求截图即可。 </think> ### 回答:Spring Boot项目整合与运行步骤 您的需求需要拆分为**两个独立的Spring Boot应用**(两个进程),因为: 1. `concurrency=2`的消费者和独立消费者必须在不同JVM进程中运行(题目要求"独立进程") 2. 生产者可与`concurrency=2`消费者部署在同一个应用(App A) 3. 独立消费者需部署在另一个应用(App B) #### 项目结构规划 ```bash kafka-demo/ ├── appA/ # 含生产者 + concurrency=2消费者 │ ├── src/ │ │ ├── main/java/com/example/ │ │ │ ├── ProducerController.java │ │ │ ├── Consumer1.java # @KafkaListener(concurrency=2) │ │ ├── resources/ │ │ │ ├── application.yml ├── appB/ # 独立消费者 │ ├── src/ │ │ ├── main/java/com/example/ │ │ │ ├── Consumer2.java # 独立消费者 │ │ ├── resources/ │ │ │ ├── application.yml └── pom.xml # 共享依赖 ``` #### 关键配置步骤 **1. 共享pom.xml依赖** ```xml <dependencies> <!-- 公共配置 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <version>2.1.6.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.kafka</groupId> <artifactId>spring-kafka</artifactId> <version>2.2.13.RELEASE</version> </dependency> <!-- 强制指定kafka-clients版本 --> <dependency> <groupId>org.apache.kafka</groupId> <artifactId>kafka-clients</artifactId> <version>2.2.1</version> </dependency> </dependencies> ``` **2. AppA配置(生产者 + 并发消费者)** ```yaml # appA/src/resources/application.yml server: port: 8080 # 生产者API端口 spring: kafka: bootstrap-servers: [虚拟机IP]:9092 consumer: group-id: test-group # 与AppB相同组ID enable-auto-commit: false max-poll-records: 10 # 批量消费 ``` **3. AppB配置(独立消费者)** ```yaml # appB/src/resources/application.yml server: port: 8081 # 避免端口冲突 spring: kafka: bootstrap-servers: [虚拟机IP]:9092 consumer: group-id: test-group # 相同消费组 enable-auto-commit: false max-poll-records: 10 ``` #### 运行步骤 1. **启动Kafka集群**(VMware虚拟机内) ```bash bin/zookeeper-server-start.sh config/zookeeper.properties bin/kafka-server-start.sh config/server.properties ``` 2. **编译打包应用** ```bash # 在kafka-demo根目录 mvn clean package ``` 3. **启动AppA(生产者+并发消费者)** ```bash java -jar appA/target/appA.jar # 控制台将显示: # - 生产者发送日志 # - 两个消费者线程日志(Thread-ID不同) ``` 4. **启动AppB(独立消费者)** ```bash java -jar appB/target/appB.jar # 控制台将显示独立消费者日志 ``` 5. **触发生产者发送消息** ```bash curl http://localhost:8080/send # 调用生产者接口 ``` 6. **关闭concurrency=2消费者** ```bash # 直接关闭AppA进程 (Ctrl+C) # AppB控制台将立即显示再平衡日志并接管分区 ``` #### 验证要点 | 场景 | 观察位置 | 关键日志 | |------|----------|----------| | 生产者发送 | AppA控制台 | `[生产者] 发送消息: Hello Kafka, I’m W0111267` | | 三消费者运行 | AppA+AppB控制台 | `[消费者1-线程XX] 消费...`<br>`[消费者2] 消费...` | | 关闭并发消费者 | AppB控制台 | `Revoking partitions...`<br>`Assigned partitions: [所有分区]` | > 📌 **注意**:确保Kafka主题有≥3个分区(`bin/kafka-topics.sh --alter --partitions 3`),否则无法分配3个消费者
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值