Qt5.3编写Android定时器

3870阅读 0评论2014-09-23 AoyamaRyo
分类:Android平台


                                         基于Qt5.3编写Android定时器

                                                        Author:AoyamaRyo
                                                EMail:wind.river.sun@gmail.com

        前言
        只是一个不系统的实践笔记。连门都入不了,因为本人之前并没有接触过安卓编程。所以,如有谬误,恳请指正。
        缺少的东西:Manifest.xml的编写方法,Android编程的一般思路。
        包含的东西:在Qt中如何使用Android的震动、顶层推送、WakeLock等。
        程序是由Qt5.3中的notifier example改编而来,本文记述此过程中遇到的问题。

         一、关于元对象系统
        

点击(此处)折叠或打开

  1. QTimer *mainTimer = new QTimer(&view);
  2.     view.engine()->rootContext()->setContextProperty(QLatin1String("mainTimer"),
  3.                                                      mainTimer);
         坦白地说,虽然用了一段时间Qt,但对于Qt引以为傲的元对象系统却避之不及——要考虑哪些实例会被自动释放,哪些实例没有,是否会产生重复释放等问题。但看上面的两句代码,在QML中却带来了莫大的便利——可以直接在JS文件中使用该C++对象的指针(红框所示),否则的话只能通过信号与槽进行连接(橙框所示)。

点击(此处)折叠或打开

  1.         Button {
  2.                 id: btnStart
  3.                 text: qsTr("开始")
  4.                 onClicked: {
  5.                     mw.restTimeInt = sldInterval.value*60;
  6.                     mainTimer.start(sldInterval.value*60*1000)
  7.                     sigWakeLockAcq();
  8.                 }
  9.             }
      Q_PROPERTY(QString notification READ notification WRITE setNotification NOTIFY sigNotificationChanged)  

         一直以来将Qt视作一个基本C++库,所以对于Q_PROPERTY宏也为留意,但是现在看来开发QML时使用这些特性可以避免一些awkard approaches。

          二、关于Android的震动、指示灯、传感器等等
          这些内容并不复杂,但Qt-Project要做一个“适配尽最可能多的Android手机的库”还是需要时间打磨的。所以对于Qter,可以通过JNI自行封装相应的功能,以震动为例:

点击(此处)折叠或打开

  1. package org.qtproject.example.notification;
    
    
    import android.app.Notification;
    import android.app.NotificationManager;
    import android.content.Context;
    
    
    import android.os.Bundle;
    import android.app.Activity;
    import android.app.Service;
    import android.os.Vibrator;
    import android.os.PowerManager;
    
    
    import android.app.AlarmManager;
    import android.app.PendingIntent;
    import android.content.Intent;
    
    
    public class NotificationClient extends org.qtproject.qt5.android.bindings.QtActivity
    {
     private static NotificationManager m_notificationManager;
     private static Notification.Builder m_builder;
     private static NotificationClient m_instance;
    
    
     private static Vibrator m_vibrator;
    
    
     private static AlarmManager m_alarmManager;
     private static PowerManager m_powerManager;
     private static PowerManager.WakeLock m_wakeLock;
    
    
     public NotificationClient()
     {
     m_instance = this;
    // m_powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE);
    // m_wakeLock = m_powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,
    // "MyWakelockTag");
     }
    
    
     public static void wakeLockAcquire(){
         if(m_powerManager == null)
              m_powerManager = (PowerManager)m_instance.getSystemService(Context.POWER_SERVICE);
         if(m_wakeLock == null){
              m_wakeLock = m_powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK,"NotifierWakeLock");
         }
         m_wakeLock.acquire();
         return;
     }
     public static void wakeLockRelease(){
         if(m_wakeLock != null){
              m_wakeLock.release();
              m_wakeLock = null;
         }
     }
    
    
     public static void notify(String s)
     {
         if (m_notificationManager == null) {
             m_notificationManager = (NotificationManager)m_instance.getSystemService(Context.NOTIFICATION_SERVICE);
             m_builder = new Notification.Builder(m_instance);
             m_builder.setSmallIcon(R.drawable.icon);
             m_builder.setContentTitle("A message from Qt!");
         }
    
    
         m_builder.setContentText(s);
         m_notificationManager.notify(1, m_builder.build());
     }
    
    
     public static void vibrate(long[] pattern,boolean isRepeat) {
         if(m_vibrator == null){
              m_vibrator = (Vibrator) m_instance.getSystemService(Context.VIBRATOR_SERVICE);
         }
         m_vibrator.vibrate(pattern, isRepeat ? 1 : -1);
     }
    
    
     public static void vibrate(boolean isRepeat) {
         if(m_vibrator == null){
              m_vibrator = (Vibrator) m_instance.getSystemService(Context.VIBRATOR_SERVICE);
         }
         m_vibrator.vibrate(new long[]{100,10,100,100},isRepeat ? 1 : -1);
         }
    }

        以上Java代码,WakeLock.isHeld()方法可以用来判断该WakeLock实例是否持有锁,但该方法存在于高版本SDK中,我所用的是低版本。 Application context和Activity context是两种不同的context,前者的生命周期伴随Application的生命周期,与activity的生命周期无关;后者t跟Activity的生命周期是相关的,但是对一个Application来说,Activity可以销毁几次,那么属于Activity的context就会销毁多次。有时候必须使用Application的context则可以可以通过Context.getApplicationContext或者Activity.getApplication方法获取。
        还要在Manifest.xml中添加权限相关的许可:

点击(此处)折叠或打开

  1. <uses-permission android:name="android.permission.INTERNET"/>
  2.     <uses-permission android:name="android.permission.VIBRATE"/>
  3.     <uses-permission android:name="android.permission.WAKE_LOCK"/>
  4.     <uses-permission android:name="android.permission.DEVICE_POWER"/>
  5.     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
        具体各项意义,参考Reference Manual,不再罗列。
        以下是C++函数调用上面Java方法的例子,主要就是一个QAndroidJniObject::callStaticMethod,注意其“描述Java方法参数与返回值”的格式(signature)。是因为高级语言的函数重载特性,导致只有函数名是无法确定调用哪个函数的。具体意义参考其他文档,很容易查到。

点击(此处)折叠或打开

  1. void NotificationClient::sltUpdateAndroidNotification()
    {
     QAndroidJniObject javaNotification = QAndroidJniObject::fromString(m_notification);
     QAndroidJniObject::callStaticMethod<void>("org/qtproject/example/notification/NotificationClient",
     "notify",
     "(Ljava/lang/String;)V",
     javaNotification.object<jstring>());
    }
    void NotificationClient::sltVibrate(){
     QAndroidJniObject::callStaticMethod<void>("org/qtproject/example/notification/NotificationClient",
     "vibrate",
     "(Z)V",
     false);
    }
    void NotificationClient::sltWakeLockAcquire(){
     QAndroidJniObject::callStaticMethod<void>("org/qtproject/example/notification/NotificationClient",
     "wakeLockAcquire",
     "()V");
    }
    void NotificationClient::sltWakeLockRelease(){
     QAndroidJniObject::callStaticMethod<void>("org/qtproject/example/notification/NotificationClient",
     "wakeLockRelease",
     "()V");
    }

        三、最后提一下WakeLock
        没有开启WakeLock的定时程序,当屏幕关闭后,没法正常工作。因为Android为了省电,系统认为“没有紧要任务”时会将CPU休眠,而且不打招呼。所以,需要后台运行任务时,要告诉系统维持CPU正常运转(参看上面的Java片段)。只是要注意,CPU的高频状态是个耗电大户,故而一旦不再需要了务必要把WakeLock释放掉。

        最后,还缺什么呢?答:(1)C++和Java之间如何大量数据传输(2)与其他Android应用交换数据。以后再说吧,困了。
上一篇:Linux I2C驱动分析(一)----I2C架构和总线驱动
下一篇:C++11多线程希尔排序