问题
I want to write an app that sits in the 'Share via' menu (for quickly emailing myself links to things I find on the web or look at in RSS readers) For this I'm declaring my app with an intent.action.SEND intent-filter:
<activity
android:name="uk.co.baroquedub.checkit.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="text/plain" />
</intent-filter>
</activity>
Here's a skeleton of the MainActivity package
package uk.co.baroquedub.testcheck;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.widget.Toast;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// real code here grabs URL from intent then emails it as an asyncTask:
doSendTask task = new doSendTask();
task.execute(new String[] { "urlString" });
}
protected void showDialog (String response){
Toast.makeText(this, response, Toast.LENGTH_SHORT).show();
finish();
}
private class doSendTask extends AsyncTask<String, Void, String> {
@Override
protected String doInBackground(String... urls) {
String response = "";
// Real code here sends the email
// Simulate waiting for the email to be sent:
try {
Thread.sleep(5000);
response = "Waited";
}
catch (InterruptedException ex) { }
return response;
}
@Override
protected void onPostExecute(String result) {
showDialog(result);
}
}
}
The problem is that my app is opening on top of the browser (a white screen appears with a title bar showing the name of the app) - which is stopping the browser from being accessible until the 'wait' is finished (hence defeating the purpose of wrapping my sendEmail functionality within an asyncTask).
See: screencast for demo of problem
See: related question with full code
Can anyone tell me how I can have my app start (from the 'Share via' menu) and execute my code but without actually having a 'View' (if that's the right terminology for the blank screen and title bar)?
回答1:
- start an activity without any UI
- start a service to do your background service in OnCreate
- finish the activity as soon as you start service
- let the service post notification or Toast about completion.
If you do want to show a dialog, you could start a separate activity with just the dialog from service, but it is usually intrusive to show dialog.
回答2:
Thanks to Nandeesh for putting me on the right path. For those wanting to know exactly how to do it, here's the full solution:
1: start an activity without any UI to do this I used the following Theme in the AndroidManifest:
android:theme="@android:style/Theme.NoDisplay"
which makes the initial application not just transparent but completely without a UI
2: start a service to do your background service in OnCreate Here I still had to 'grab' the URL from the Share intent and pass it as an Extra to the service:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// get url
Intent intent = getIntent();
intent.setFlags( Intent.FLAG_ACTIVITY_CLEAR_TOP );
String action = intent.getAction();
// if this is from the share menu
if (Intent.ACTION_SEND.equals(action)) {
title = intent.getStringExtra(Intent.EXTRA_SUBJECT);
url = intent.getStringExtra(Intent.EXTRA_TEXT);
// Flipboard fix (remove title in URL)
url = url.replace(title, "");
if (url != null){
url = title+"\n"+url;
} else {
url = "error getting URL";
}
// prepare service
Intent emailSendIntent = new Intent(getApplicationContext(), EmailSendService.class);
emailSendIntent.putExtra("extraData", url);
startService(emailSendIntent);
finish();
}
}
3: finish the activity as soon as you start service - see above
Note that in the service the Extras are passed to the OnStart method (not the On Create method as might be expected) See: link
4: let the service post notification or Toast about completion. I couldn't get the Service to open a Dialog notification(as per my original app), this kept on crashing the app/service but Toast works great - and as Nandeesh suggests, it's probably less intrusive.
Here's the service package:
public class EmailSendService extends Service {
String url;
String message;
@Override
public IBinder onBind(Intent arg0) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onDestroy() {
super.onDestroy();
}
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
url = intent.getExtras().getString("extraData");
String senderPassword = getResources().getString(R.string.senderPassword);
String senderEmail = getResources().getString(R.string.senderEmail);
String recipientEmail = getResources().getString(R.string.recipientEmail);
String subjectText = getResources().getString(R.string.subjectText);
GMailSender sender = new GMailSender(senderEmail, senderPassword);
try {
sender.sendMail(subjectText,
url,
senderEmail,
recipientEmail);
message = "Email sent";
} catch (Exception e) {
message = "Error sending email";
}
Toast.makeText(this, message, Toast.LENGTH_LONG).show();
}
}
NB. remember to declare the service in the manifest (inside the application tag):
<service
android:name=".EmailSendService"
android:label="CheckIt EmailSendService" >
</service>
来源:https://stackoverflow.com/questions/13728628/share-via-application-that-runs-without-a-view