Android:启动时启动服务,但不启动GUI

时间:2013-05-06 21:00:00

标签: android android-activity boot launch

我正在编写一个Android应用程序,它有两个主要组件:一个在启动时启动的服务,以及一个我只想在我通过其图标手动启动它时启动的GUI,而不是在设备启动时启动。我知道如何在启动时启动服务,但它也会在启动时启动GUI,这是我不想要的。

我认为这与我的清单中的设置有关,但是尽管尝试了很多事情,我还没想出如何防止GUI也在启动时启动。

我应该补充一点,我没有在启动时以编程方式启动GUI。我确实在GUI的活动类中引用了静态公共变量,但我没有进行任何方法调用或向GUI的活动发送任何意图。

这是我的清单。我究竟做错了什么?非常感谢你。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="my.package.name"
      android:versionCode="0"
      android:versionName="0.1.0">

    <uses-sdk
        android:minSdkVersion="11" 
        android:targetSdkVersion="17"/>

    <uses-permission android:name="android.permission.RECEIVE_SMS"/>
    <uses-permission android:name="android.permission.READ_SMS"/>
    <uses-permission android:name="android.permission.WRITE_SMS"/>
    <uses-permission android:name="android.permission.SEND_SMS"/>
    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.GET_ACCOUNTS" />
    <uses-permission android:name="android.permission.MANAGE_ACCOUNTS" />
    <uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

    <application android:icon="@drawable/icon"
                 android:label="@string/app_name"
                 android:allowBackup="true" >

        <!-- XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
               I want MainActivity to only start when I
               select its icon, NOT at boot time. However,
               it always starts up at boot.
             XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
        -->
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:launchMode="singleTop">
           <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
           </intent-filter>
        </activity>

        <!-- XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
               MyBootReceiver properly starts up at boot time,
               and it properly invokes MyBootService. At
               the appropriate time, MyBootService invokes
               RegisterActivity. 
             XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
        -->
        <activity android:name=".RegisterActivity"
                  android:label="@string/app_name">
        </activity>
        <receiver
            android:name=".MyBootReceiver"
            android:enabled="true"
            android:exported="false">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
                <category android:name="android.intent.category.DEFAULT"/>
                <category android:name="my.package.name" />
            </intent-filter>
        </receiver>
        <service android:name=".MyBootService" />

    </application>
</manifest>

添加广播接收器类:

package my.package.name;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

public class MyBootReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {
        Intent bootIntent = new Intent(context, MyBootService.class);
        bootIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startService(bootIntent);
    }
}

添加服务类...

package my.package.name;

import java.util.ArrayList;

import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AccountManagerCallback;
import android.accounts.AccountManagerFuture;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.telephony.TelephonyManager;

public class MyBootService extends Service {

    private static final String GOOGLE_ACCOUNT_TYPE    = "com.google";
    private static final String GOOGLE_ACCOUNT_FEATURE = "service_ah";

    private Context context = null;

    @Override
    public IBinder onBind(Intent intent) {
        this.display("onBind");
        return (null);
    }

    @Override
    public void onCreate() {
        super.onCreate();
    }

    @Override
    public void onStart(Intent intent, int startId) {
        super.onStart(intent, startId);
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        super.onStartCommand(intent, flags, startId);

        AccountManager am = AccountManager.get(this);
        am.getAccountsByTypeAndFeatures(GOOGLE_ACCOUNT_TYPE, new String[]{GOOGLE_ACCOUNT_FEATURE},
                new AccountManagerCallback<Account[]>() {
                    @Override
                    public void run(AccountManagerFuture<Account[]> acclist) {
                        MyBootService parent = MyBootService.this;
                        Intent regIntent = new Intent(parent.getApplicationContext(), RegisterActivity.class);
                        try {
                            ArrayList<String> accountNameList = new ArrayList<String>();
                            for (Account a: acclist.getResult()) {
                                accountNameList.add(a.name);
                            }
                            regIntent.putStringArrayListExtra("accountNames", accountNameList);
                            try {
                                TelephonyManager tmgr = (TelephonyManager) parent.getApplicationContext().getSystemService(Context.TELEPHONY_SERVICE);
                                String phoneNo = tmgr.getLine1Number();
                                regIntent.putExtra("phoneNumber", phoneNo);
                            }
                            catch (Throwable t) {
                            }
                        }
                        catch (Throwable t) {
                            // put error message here
                        }
                        regIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                        parent.startActivity(regIntent);
                    } 
                }, null);

        return (START_STICKY);
    }

    @Override
    public void onDestroy() {
        this.display("onDestroy");
        super.onDestroy();
    }
}

更多信息

我想出了一些正在发生的事情。首先,我错误地说我的MainActivity正在开始。经过更详细的调试,我发现没有调用 onCreate() onResume()方法。但是,应用程序的视图显示:黑屏,显示应用程序名称和默认图标。我最初误以为这是一个完整启动的迹象。

当然,这首先提出了为什么这个视图出现在启动时的问题。我有一些关于这个的信息,虽然我仍然对发生了什么感到困惑。我删除了由MyBootService调用的RegisterActivity类的 onCreate()方法。当调用 this.getIntent()时,应用程序的视图会在启动时显示。当 this.getIntent()被注释掉时,应用程序的视图不会在启动时显示。

请注意,这是RegisterActivity类的 onCreate(),MainActivity的 NOT

你们是否知道在调用 this.getIntent()时可能导致应用程序的视图出现的原因?

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // If the following line is commented out, the
    // application's view does not show up on boot;
    // if the following line is not commented out,
    // the application's view shows up.

    Intent intent = this.getIntent();
}

2 个答案:

答案 0 :(得分:3)

我认为您所看到的是Android使用的预览,以使应用启动速度更快。此预览基于您活动的主题

尝试为RegisterActivity设置一个更接近最终结果的自定义主题。例如,如果您的活动是对话框,请创建一个扩展Theme.DialogTheme.Light.Dialog

的主题

您可以从Cyril Mottier的这篇博客文章中获取更多信息:Android App Launching Made Gorgeous


编辑:改为实际回答问题

答案 1 :(得分:0)

真实的,实际的答案

由于我得到的帮助和反馈,我终于找到了问题并解决了它:

我首先使用Activity(我的RegisterActivity类)是错误的,因为我不希望我最初放入RegisterActivity的功能与GUI相关联。由于缺乏Android模型的经验和缺乏足够的文档阅读,我没有意识到Activity总是有一个与之相关的视图。

现在我知道这一点,我重构了我的应用程序,以便以前在RegisterActivity中的所有功能都已移至MyBootService。现在,启动时没有弹出视图,我的应用程序就是我想要的。

感谢所有人的帮助和耐心。