【Android开发日记】初次探秘Android Service!Service开机启动+重力感应+弹窗+保持运行

前言:

      最近在写一个小程序,需求是手机摇一摇就弹窗出来。第一次使用了Service,学习了两天,实现了Service弹窗,开机启动,Service启动和销毁,Service保持一直运行。满足了自己的需求。现记录学习心得。希望能给你带来一些帮助。


1.Service创建:重写4个方法

  • onBind():返回一个IBinder对象,这个对象可以使应用程序与Service通信。如果用startService、stopService启动和关闭Service的话,Service和访问者是无法通信交换数据的。onBind()返回值设为null即可。但是如果想要交换数据,就要用bindService、unbindService来启动和关闭Service。这时,onBind()要返回一个有效的IBinder对象。
  • onCreate():Service第一次被创建时调用此方法。
  • onStartCommand():理解为onStart()的新一代。每次通过startService(Intent)启动Service时都会调用此方法。
  • onDestroy():Service被关闭之前调用此方法。

package com.service;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.util.Log;

public class PopupService extends Service {

    @Override
    public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		return null;
    }  
      
    @Override  
    public void onCreate() {  
        super.onCreate();  
        System.out.println("Service is Created");
    }  
 
    @Override  
    public int onStartCommand(Intent intent, int flags, int startId) {  
    	 System.out.println("Service is Started");
    	 
         
         return START_STICKY;
    }

    @Override  
    public void onDestroy() {  
        super.onDestroy();  
        System.out.println("Service is Destroyed");

    } 
    
}

2.Service配置:在AndroidManifest.xml中声明

<service 
     android:name="com.service.PopupService" 
     android:priority = "1000"    <!-- 提高优先级-->
     android:persistent="true">  <!-- 免杀,不知道有没有起作用-->
     <intent-filter>
          <action android:name="com.service.POPUP_SERVICE" />               
     </intent-filter>
</service>

3.Service开机启动:使用BroadcastReceiver

   文件创建:

package com.service;  
    
import android.content.BroadcastReceiver;  
import android.content.Context;  
import android.content.Intent;  
     
    public class StartupReceiver extends BroadcastReceiver  
    {  
        @Override  
        public void onReceive(Context context, Intent intent)  
        {  
            //  启动一个Service  
            Intent serviceIntent = new Intent(context, PopupService.class);          
            context.startService(serviceIntent);   
        }  
    } 

    文件配置:在 AndroidManifest.xml中声明

 <receiver android:name="com.service.StartupReceiver"> 
      <intent-filter> 
            <action android:name="android.intent.action.BOOT_COMPLETED" /> 
            <category android:name="android.intent.category.LAUNCHER" /> 
      </intent-filter> 
 </receiver> 

    注意权限:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> 

4.Service从Activity中启动:

   在主Activity中使用startService(Intent)

Intent popupintent=new Intent();
popupintent.setAction("com.service.POPUP_SERVICE");
startService(popupintent);

5.Service监听重力感应并且弹窗:

  •    这里使用Sensor.TYPE_ACCELEROMETER加速度感应器。和其他监听器比如手势等一样,包括声明、注册、监听等
  •    弹窗使用的是theme定义为dialog,notitle的activity。

   弹窗相关代码:


Intent activityIntent = new Intent(this, SelectFriendsActivity.class);  
//要想在Service中启动Activity,必须设置如下标志  
activityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  
startActivity(activityIntent);  

   完整代码:

package com.service;

import com.task.SelectFriendsActivity;

import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.IBinder;
import android.os.Vibrator;
import android.util.Log;

public class PopupService extends Service implements SensorEventListener{
	
	//sensorManager
	private SensorManager sensorManager;  
	private Vibrator vibrator;  
	Intent activityIntent;
	
	@Override
	public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		return null;
	}  
      
    @Override  
    public void onCreate() {  
        super.onCreate();  
        System.out.println("Service is Created");
        
        sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);  
	    vibrator = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE); 
    }  
 
    @Override  
    public int onStartCommand(Intent intent, int flags, int startId) {  
    	 System.out.println("Service is Started");
    	 //启动service,将serviceon置为TRUE,可弹窗。
    	 SelectFriendsActivity.serviceon = true;
    	 if (sensorManager != null) {// 注册监听器  
             sensorManager.registerListener(this, sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER), SensorManager.SENSOR_DELAY_NORMAL);  
             // 第一个参数是Listener,第二个参数是所得传感器类型,第三个参数值获取传感器信息的频率  
         } 
    	 activityIntent = new Intent(this, SelectFriendsActivity.class);  
         //  要想在Service中启动Activity,必须设置如下标志  
         activityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  
         
         return START_STICKY;
    }

    @Override  
    public void onDestroy() {  
        super.onDestroy();  
        System.out.println("Service is Destroyed");

    } 
    
    /** 
     * 重力感应监听 
     */  
    public void onSensorChanged(SensorEvent event) {  
        // 传感器信息改变时执行该方法  
        float[] values = event.values;  
        float x = values[0]; // x轴方向的重力加速度,向右为正  
        float y = values[1]; // y轴方向的重力加速度,向前为正  
        float z = values[2]; // z轴方向的重力加速度,向上为正  
        Log.i("group", "x轴方向的重力加速度" + x +  ";y轴方向的重力加速度" + y +  ";z轴方向的重力加速度" + z);  
        // 一般在这三个方向的重力加速度达到40就达到了摇晃手机的状态。  
        int medumValue = 19;// 三星 i9250怎么晃都不会超过20,没办法,只设置19了  
        if (Math.abs(x) > medumValue || Math.abs(y) > medumValue || Math.abs(z) > medumValue) {  
           
            if(SelectFriendsActivity.serviceon){
            	vibrator.vibrate(200);  
            	System.out.println("Service:shaked and popup!!!!!!!");
            	startActivity(activityIntent);  
            }else{
            	System.out.println("Service:shaked only!!!!!!!");
            }
        }  
    }  

    @Override  
    public void onAccuracyChanged(Sensor sensor, int accuracy) {  

    }  

}

 
弹出的Activity就是一般的Activity,只不过要在其xml中设置其大小,在AndroidManifest.xml中将其theme设置为notitle,dialog类型 

可以使用这个style:

    <style name="dialogTheme" parent="android:Theme.Dialog"> 
        <item name="android:windowNoTitle">true</item>
    </style>

弹窗要求添加权限:

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>

6.Service 保持一直运行,不被杀死 的方法:

   重写onDestroy():

    @Override  
    public void onDestroy() {  
       // super.onDestroy();  
       // System.out.println("Service is Destroyed");
          System.out.println("Service is Destroyed,and is Restarted");
          Intent localIntent = new Intent(); localIntent.setClass(this, PopupService.class); //销毁时重新启动
          Service this.startService(localIntent); 
     }

 
    这样无论如何Service都一直在后台运行了。 

7.图文记录:

7.1 启动app,MainActivity中调用了startService(popupintent);

   结果:说明依次调用了Service中的onCreate()、onStartCommand()方法,Service开始运行

 7.2 震动手机,Service响应弹窗

    结果:弹窗,Service正常运行,重力感应器正常运行

7.3 杀死应用进程,震动手机,Service仍然响应弹窗

    结果:弹窗,说明虽然应用进程被杀死,但是Service仍保持正常运行,重力感应器正常运行

7.4 点击弹窗的Avtivity中的按钮,按钮监听代码:

Intent popupintent=new Intent();
popupintent.setAction("com.service.POPUP_SERVICE");		    
stopService(popupintent);
即调用了stopService(Intent) 方法

结果:打印出Service is Destroyed,说明调用了Service的onDestroy()方法

7.5 再次震动手机,发现还是有打印输出:

   结果:说名虽然调用了onDestroy()方法,但是其Context未被清除,Service仍然存在

7.6 杀死所有有关此弹窗的进程,再次震动手机,发现没有打印输出了:

    结果:一旦其Context被完全清除,Service就真正停止了。



感谢newcj 的博客 文章 Android 中的 Service 全面总结 让我受益匪浅。大家可以去看看,评论区很精彩:




第一次学着用Service,文中如果有错误请大家指正。


 




  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
由于涉及到硬件操作,需要通过外部模块来实现控制。 以下是参考代码: 1. 添加权限信息 ``` <uses-permission android:name="android.permission.TRANSMIT_IR" /> ``` 2. 编写控制代码 ``` private ConsumerIrManager mConsumerIrManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mConsumerIrManager = (ConsumerIrManager) getSystemService(CONSUMER_IR_SERVICE); Button powerOnButton = findViewById(R.id.power_on_button); powerOnButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { int[] pattern = {3500, 1750, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 9000}; mConsumerIrManager.transmit(38000, pattern); } }); Button powerOffButton = findViewById(R.id.power_off_button); powerOffButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { int[] pattern = {3500, 1750, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 450, 9000}; mConsumerIrManager.transmit(38000, pattern); } }); } ``` 3. 控制指令解释 红外线遥控空调的指令通常是由前导码和数据码组成,前导码是一个长时间的脉冲或闪烁信号,用于告知空调接下来的指令数据信息的长度和格式。数据码通常是一个二进制编码,用于表达空调的不同操作状态。 控制指令需要结合具体的空调品牌和型号来设计,可以通过在线提供的空调红外码库来获取。 参考链接: - [探秘红外线遥控](https://developer.android.com/reference/android/hardware/ConsumerIrManager) - [红外遥控器与使用](https://developer.android.com/guide/topics/connectivity/irda) - [NEC红外遥控器编码](https://www.sbprojects.net/knowledge/ir/nec.php)

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值