I'm just getting started with Android and was reading up BroadcastReceiver. Since the MainActivity was being used only to get the alarm time in seconds, it got me thinking whether layout XML files are must for every activity in Android. I mean, is it possible to have an app that when launched, shows no view, but successfully sets up a receiver?
The answer is yes it's possible. Activities don't have to have a UI. It's mentioned in the documentation, e.g.:
An activity is a single, focused thing that the user can do. Almost
all activities interact with the user [...]
(see http://developer.android.com/reference/android/app/Activity.html)
Related SO question: https://stackoverflow.com/a/12817384/534471
To e.g. display a Toast from an Activity without layout you would define the activity in your manifest like so:
<activity
android:name=".MainActivity"
android:theme="#android:style/Theme.NoDisplay">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
The code would look like this:
public class MainActivity extends Activity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Toast.makeText(this, "I'm alive", Toast.LENGTH_LONG).show();
finish();
}
}
You can implement an Activity without a UI. In the manifest you can specify android:theme="#android:style/Theme.NoDisplay". Take a look at this
You can also implement a Service which does not have any UI so you do not need layout inflation. Service just runs in background and shows no views.
Take a look at Android Training and API Guide to learn more about Services
Related
I would like to apologize if this is somehow a repeated question that has been answered. I have tried the solutions I was able to find here and still not able to do the thing I need.
I am still trying to learn programming with android system and currently trying to do something like the chat bubble that draws over other app. From learning on this site, I was able to do it by opening an intent, but I have not been able to find a way to close the app completely--even after swiping it to close after pressing the home key for a short period of time, the app will automatically reopens itself. Let me try to explain it better with what I am doing.
In manifest:
I have
and these:
<activity
android:name=".Play"
android:label="#string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name="com.example.play.MainClass"
android:exported="true" />
In Play.java
public class Play extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent svc = new Intent(this, MainClass.class);
startService(svc);
}
#Override
public void onDestroy() {
super.onDestroy();
}
}
In MainClass.java
I am using this
public class MainClass extends Service {
.......
}
as well as using
private WindowManager wm;
and do the codes using the wm to display the chat bubble i need.
I have been trying to search how to close android app programmatically and phrases like that and I found that many answers include doing:
System.exit(0);
or
finish();
or
Process.killProcess(int pid)
But then again, I am not able to close my app completely--it runs again by itself after around 10-20seconds. I am thinking it is because I am using 'Service' so I am not able to close the app completely.
I am looking forward to any of your kind reply and patience.
I apologize in advance for if this is still answered somewhere that I was not able to find it.
Thank you very much.
I would like to launch my application and check the connectivity state in application's onCreate method then decide which activity to start! I know that I could finish() a default MAIN/LAUNCHER activity before to setLayout while starting another if it's relevant but that seems messy to me!
So, I would like to know if it is possible to start an application whose doesn't manifest an activity with action.MAIN / category.LAUNCHER? I tried this way but it doesn't work! I mean the application seems to start but no activity is shown!
(This is not a sample from my real code, I'm not at home right now! Some arguments and stuff may be missing but I think you get the point!)
public class MyApp extends Application {
onCreate() {
Intent intent = new Intent(this, MyActivity.class);
intent.setFlags(Intent.NEW_TASK);
this.startActivity(intent);
}
}
Also, the first activity of my application may be an AlertDialog and I'm wondering if I can start one while no activity is started or if I'm forced to set an activity's theme with #android:style/Theme.Dialog?
I tried the same as for the above example but same result : logcat saying application alive while no printing at all...
Tell me if I'm not clear enough and in which way! I'm not an english speaker and I'm not used to ask in forums!
You will have to go this way:
public class MainActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.some_empty_or_loading_view); //optional probably, not sure
//TODO: check whatever you want
if(condition) {
startActivity(this, SomeActivity.class);
} else {
startActivity(this, AnotherActivity.class);
}
finish();
}
}
Specify Your App's Launcher Activity
When the user selects your app icon from the Home screen, the system calls the onCreate() method for the Activity in your app that you've declared to be the "launcher" (or "main") activity. This is the activity that serves as the main entry point to your app's user interface.
You can define which activity to use as the main activity in the Android manifest file, AndroidManifest.xml, which is at the root of your project directory.
The main activity for your app must be declared in the manifest with an that includes the MAIN action and LAUNCHER category. For example:
<activity android:name=".MainActivity" android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Note: When you create a new Android project with the Android SDK tools, the default project files include an Activity class that's declared in the manifest with this filter.
If either the MAIN action or LAUNCHER category are not declared for one of your activities, then your app icon will not appear in the Home screen's list of app
I'm trying to implement Facebook's Deep Linking feature on my app and encountered the following scenario:
I have an activity called MainActivity which is declared like so:
<activity
android:name="com.mypackage.android.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
This activity + my package name are also declared in my app's settings on facebook developer website.
Once a link gets clicked on Facebook's app, I'm supposed to handle this event via the onCreate method of my activity.
The following code handle the event:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Uri target = getIntent().getData();
if (target != null){
// got here via Facebook deep link
// once I'm done parsing the URI and deciding
// which part of my app I should point the client to
// I fire an intent for a new activity and
// call finish() the current activity (MainActivity)
}else{
// activity was created in a normal fashion
}
}
All goes according to plan except for the following scenario:
User launched my app
MainActivity created
SecondaryActivity created
MainActivity finished
App goes to background via the device home button
Deep link gets clicked on Facebook's app
In this case my app goes to foreground again, but MainActivity's onCreate / onNewIntent
don't get called, instead SecondaryActivity's onResume() gets called and restored to it's
last state.
Note: I've tested this issue on a Samsung Nexus with Android 4.2.1 and got to this result, though when tested on Galaxy S1 with Android 2.3.5 it worked as I initially expected.
Any help would be greatly appreciated,
Thank you.
Facebook is starting your app from their own app by explicitly start your "MainActivity" (the one your provided them in the developer page).
by that - Android's default behavior is: if the application already runs, then calling again to startActivity() won't start new task from scratch, but only restore to foreground the already running task.
but the good news are that you can change this default behavior by adding to your MainActivity the android:launchMode="singleTask". it definition is:
the system creates a new task and instantiates the activity at the root of the new task. However, if an instance of the activity already exists in a separate task, the system routes the intent to the existing instance through a call to its onNewIntent() method, rather than creating a new instance. Only one instance of the activity can exist at a time.
from this point you could always respond to the starting intent, and from that point you can always navigate back to the task that already was in background(if exists) by restarting activity with both flags Intent.FLAG_ACTIVITY_SINGLE_TOP && Intent.FLAG_ACTIVITY_CLEAR_TOP combination
See http://developer.android.com/guide/topics/manifest/activity-element.html
You can play with:
android:clearTaskOnLaunch
android:noHistory
android:launchMode
You need to have more information in your intent filter:
<intent-filter>
<action android:name="android.intent.action.VIEW"></action>
<category android:name="android.intent.category.DEFAULT"></category>
<category android:name="android.intent.category.BROWSABLE"></category>
<data android:host="www.yoursite.com" android:scheme="http"></data>
</intent-filter>
This will capture links going to your site (make sure to change the URL), and direct them to whatever Activity you define this intent filter under.
I have an app with some activities. These activities need common resources (matrix arrayLists), so in order to avoid reload several times this resources (when change to another activity or on an orientation change), I've created a service.
Firstly I call it with startService(Intent) for let it be sticky.
After that, I bind the service to the activity, bindService(sIntent, mConnection, BIND_AUTO_CREATE);
Finally, I have some code which try to get data from the service, but it generates a NullPointerException. I know that's because (as I see with logs) the service starts after the app has crashed, although I put startService and bindService before the accessing data code.
Anyone knows how can I ensure to get loaded data before trying to access it?
Thanks in advance.
It might be easier for you to save your common resources in SharedPreference, The SharedPreference is accessible by all threads of your application, and is persistent between runs. This depending on what your resources are.
If you want your services to work for your method you could do this with a transparent Activity. AsyncTask might be an easier and simpler solution though.
Try to load your data with an AsyncTask, you can choose whatever you want what the Activity does while loading (Progress dialog? ) and make sure you continue your app using your data after when your AsyncTask calls the ready method ( onPostExecute() ). This means AsyncTask will replace your idea of a service as background thread, managing your resources. (loading, downloading, etc).
Also post your logs next time, they might help.
Start your Service in the onCreate() of a class that extends Application. Or even better, do the work the Service is doing in your Application class, which is guaranteed to be created before any other part of your app. A Service may take a while to start up and you may encounter a race condition, but the class extending Application is always the first part of an app to be launched.
I recently came across this problem and created a solution. Similar to the invisible activity, but the idea is to create a "loading" activity that does not need the service. Here is an example:
in AndriodManifest.xml:
...
<application
... >
<activity
android:name="com.example.LoadingActivity"
android:label="#string/app_name" >
<!-- A do-nothing activity that is used as a placeholder while the service is started. -->
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.example.MyActivity"
android:label="#string/app_name" >
<!-- The real activity, started by the loading activity. -->
</activity>
<service
android:name="com.example.MyService" >
<!-- The background service, started by the loading activity. -->
</service>
</application>
...
com/example/LoadingActivity.java:
package com.example;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
public class LoadingActivity extends Activity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
super.setContentView(R.layout.activity_loading);
super.startService(new Intent(this, MyService.class)); // listed first so it will start before the activity
Intent intent = new Intent(this, MyActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); // makes it so the 'loading' activity is not kept on the back-stack
super.startActivity(intent);
}
}
The MyActivity.java and MyService.java files are just standard. You also need an activity_loading.xml layout resource, probably just an ImageView.
I have written a few Android apps, and have always declared a starting Activity as the:
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
It would be great for scoping some global methods, statics, shared prefs, etc if I could start my app using an Application that then calls the first Activity from it's onCreate() after setting up prefs, etc, but I haven't been able to find any examples of this design pattern... when I try this in code, I get a ClassCastException:
public class MyApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
// do stuff (prefs, etc)
// start the initial Activity
Intent i = new Intent(this, InitialActivity.class);
startActivity(i);
}
}
InitialActivity.class is indeed an Activity that works fine if I set it to be MAIN, but trying to start it from MyApplication that is declared MAIN generates the error. Probably a very silly question, but am I tackling this all wrong?
Thanks,
Paul
You can fix this by using FLAG_ACTIVITY_NEW_TASK flag:
Intent intent = new Intent(this, ApplicationActivity.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
That's because you need to start new task when Activity is started outside of Activity context. But I strongly recommend to not start Activity from your Application's onCreate().
Android has 4 components: Activity, Service, ContentProvider and Broadcast.
When Android needs to activate one of this components from your application, it looks if there is already existing running process with your application. If not, then Android starts new process, initializes it, then it initializes your custom Application instance. And then it activates one of needed components.
Now, let's consider next scenario: your application declared content provider in AndroidManifest.xml, and Android just about to start your application so you can provide some data to another foreground application.
Content Provider request is sent
Your application wasn't running, and Android starts new process for it.
Your custom Application instance is created
Application.onCreate() is called.
You start an activity
Your Content Provider receives request
Somebody just wanted to connect to your content provider, but your application started an Activity instead. Same true for starting background Service and sometimes broadcast receivers.
And also consider if some other application's activity A wanted to started activity X from your application. But in onCreate() you started activity Y, and then X is also started by Android. Then user presses back. What should happen? Its tricky...
Starting activities from Application's onCreate may result in quite weird user experience. So don't do it.
UPDATE:
Because Android guarantees that Application will be created only once and before any other component, you can use next code to access your Application's single instance:
public class MyApplication extends Application
{
private static MyApplication s_instance;
public MyApplication()
{
s_instance = this;
}
public static MyApplication getApplication()
{
return s_instance;
}
}
Did you set it in you manifest activity tag for this intent you are starting (another one besides your main) ?
</activity>
<activity android:name=".InitialActivity"
android:label="#string/app_name">
<intent-filter>
<action android:name="com.package.INITACT" /> <--- this is only name by which you activity can be called.
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>