Hello,
I have a android service for a chatter app.
This service runs in its own process and manage the connection to the server with push Technology.
Manifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.jukusoft.chatter" >
<permissions>
<!-- own permission for get message content -->
<permission
android:name="com.jukusoft.chatter.permission.GET_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="com.jukusoft.chatter.permission.GET_MESSAGE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<!-- using external storage for imageCache -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<!-- for get telephone number -->
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
</permissions>
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name=".MainActivity"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".profile.FirstStartActivity"
android:label="@string/title_activity_first_start"
android:parentActivityName=".MainActivity" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.jukusoft.chatter.MainActivity" />
</activity>
<provider
android:name=".contentprovider.ChatContentProvider"
android:authorities="com.jukusoft.chatter.contentprovider"
android:enabled="true"
android:exported="false" >
</provider>
<!-- service in its own process -->
<service
android:name=".service.ChatService"
android:enabled="true"
android:exported="true"
android:process=":remote" ><!-- process :my_process -->
<!-- <intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter> -->
</service>
<!-- broadcast receiver which is called on boot -->
<receiver
android:name=".broadcastreceiver.ChatBootReceiver"
android:enabled="true"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" >
</action>
</intent-filter>
</receiver>
<activity
android:name=".ui.ChatLoginActivity"
android:label="@string/title_activity_chat_login"
android:parentActivityName=".MainActivity" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.jukusoft.chatter.MainActivity" />
</activity>
<activity
android:name=".ui.RegistrationActivity"
android:label="@string/title_activity_registration"
android:parentActivityName=".MainActivity" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.jukusoft.chatter.MainActivity" />
</activity>
</application>
</manifest>
Alles anzeigen
But if i want to start the service in the MainActivity, it causes an exception.
MainActivity.java:
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//bind to service
this.serviceConnectionManager = new ServiceConnectionManager();
if (!this.serviceConnectionManager.isServiceAvailable()) {
//start service
this.serviceConnectionManager.startService(this.getBaseContext());
}
//...
}
Alles anzeigen
ServiceConnectionManager.java:
package com.jukusoft.chatter.service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.*;
import android.util.Log;
import com.jukusoft.chatter.IChatService;
import java.util.List;
/**
* Created by Justin on 10.01.2015.
*/
public class ServiceConnectionManager {
private IChatService mIChatService = null;
public ServiceConnectionManager () {
//
}
public boolean isServiceAvailable () {
if (this.mIChatService != null) {
return true;
} else {
return false;
}
}
public void startService (Context ctx) {
Intent intent = new Intent();
intent.setClass(ctx.getApplicationContext(), IChatService.class);
intent.setAction("com.jukusoft.chatter.serviceConnection");
intent.putExtra("buildNumber", "1");
intent.setPackage(IChatService.class.getPackage().getName());
intent = ServiceConnectionManager.createExplicitFromImplicitIntent(ctx.getApplicationContext(), intent);
ctx.bindService(ServiceConnectionManager.createExplicitFromImplicitIntent(ctx, intent), this.mConnection, Context.BIND_AUTO_CREATE);
}
/***
* Android L (lollipop, API 21) introduced a new problem when trying to invoke implicit intent,
* "java.lang.IllegalArgumentException: Service Intent must be explicit"
*
* If you are using an implicit intent, and know only 1 target would answer this intent,
* This method will help you turn the implicit intent into the explicit form.
*
* Inspired from SO answer: http://stackoverflow.com/a/26318757/1446466
* @param context
* @param implicitIntent - The original implicit intent
* @return Explicit Intent created from the implicit original intent
*/
public static Intent createExplicitFromImplicitIntent(Context context, Intent implicitIntent) {
//http://blog.android-develop.com/2014/10/android-l-api-21-javalangillegalargumen.html
// Retrieve all services that can match the given intent
PackageManager pm = context.getPackageManager();
List<ResolveInfo> resolveInfo = pm.queryIntentServices(implicitIntent, 0);
// Make sure only one match was found
if (resolveInfo == null || resolveInfo.size() != 1) {
return null;
}
// Get component info and create ComponentName
ResolveInfo serviceInfo = resolveInfo.get(0);
String packageName = serviceInfo.serviceInfo.packageName;
String className = serviceInfo.serviceInfo.name;
ComponentName component = new ComponentName(packageName, className);
// Create a new intent. Use the old one for extras and such reuse
Intent explicitIntent = new Intent(implicitIntent);
// Set the component to be explicit
explicitIntent.setComponent(component);
return explicitIntent;
}
public void killService () {
if (this.isServiceAvailable()) {
try {
int pid = this.mIChatService.getPid();
android.os.Process.killProcess(pid);
Log.d("ServiceConnectionManager", "Service was killed.");
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
public IChatService getService () {
return this.mIChatService;
}
private ServiceConnection mConnection = new ServiceConnection() {
// Called when the connection with the service is established
public void onServiceConnected(ComponentName className, IBinder service) {
// Following the example above for an AIDL interface,
// this gets an instance of the IRemoteInterface, which we can use to call on the service
ServiceConnectionManager.this.mIChatService = IChatService.Stub.asInterface(service);
}
// Called when the connection with the service disconnects unexpectedly
public void onServiceDisconnected(ComponentName className) {
Log.e("ServiceConnectionManager", "Service has unexpectedly disconnected");
ServiceConnectionManager.this.mIChatService = null;
}
};
}
Alles anzeigen
IChatService is the AIDL interface.
// IChatService.aidl
package com.jukusoft.chatter;
import com.jukusoft.chatter.ISocketListener;
// Declare any non-default types here with import statements
interface IChatService {
//enum SOCKET_STATE { OPEN, CLOSED };
//http://developer.android.com/guide/components/aidl.html#CreateAidl
int getPid ();
void registerSocketListener (ISocketListener listener);
void removeSocketListener ();
List<String> listLoadBalancerServer ();
void setChatSession ();
int getSocketState ();
void setCheckInterval (int interval);
void setAppActive (boolean appState);
void updateLoadBalancerList ();
void auth (String telephoneNumber, String password);
}
Alles anzeigen
ChatService.java:
package com.jukusoft.chatter.service;
import android.app.Service;
import android.content.Intent;
import android.os.*;
import android.util.Log;
import com.jukusoft.chatter.IChatService;
import com.jukusoft.chatter.ISocketListener;
import com.jukusoft.chatter.data.ChatSession;
import com.jukusoft.chatter.profile.ProfileManager;
import com.jukusoft.chatter.service.task.UpdateLoadBalancerListTask;
import com.jukusoft.chatter.service.task.listener.OnUpdateLoadBalancerListTaskFinishedListener;
import java.util.ArrayList;
import java.util.List;
public class ChatService extends Service {
private ISocketListener socketListener = null;
private List<String> loadBalancerList = new ArrayList<String>();
private SOCKET_STATE socketState = SOCKET_STATE.CLOSED;
private int checkInterval = 1;
private boolean appActive = false;
private String loadBalancerUpdateURL = "http://192.168.2.110:8080/loadBalancer.txt";
private ChatSession chatSession = null;
private ProfileManager profileManager = null;
public enum SOCKET_STATE { OPEN, CLOSED };
public ChatService() {
//http://techtej.blogspot.com.es/2011/03/android-thread-constructspart-4.html
//http://www.vogella.com/tutorials/AndroidServices/article.html
Runnable socketRunnable = new Runnable() {
@Override
public void run() {
//open a socket.io connection
//...
}
};
Thread thread = new Thread(socketRunnable);
}
@Override
public void onCreate() {
super.onCreate();
//create chat session
Log.d("ChatService", "create service.");
}
@Override
public IBinder onBind(Intent intent) {
return this.mBinder;
}
//...
private final IChatService.Stub mBinder = new IChatService.Stub() {
public int getPid(){
return android.os.Process.myPid();
}
//...
};
}
Alles anzeigen
I get the following error message:
01-13 18:15:31.017 2407-2407/com.jukusoft.chatter E/AndroidRuntime﹕ FATAL EXCEPTION: main
Process: com.jukusoft.chatter, PID: 2407
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.jukusoft.chatter/com.jukusoft.chatter.MainActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.content.Intent.resolveTypeIfNeeded(android.content.ContentResolver)' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2298)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2360)
at android.app.ActivityThread.access$800(ActivityThread.java:144)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1278)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String android.content.Intent.resolveTypeIfNeeded(android.content.ContentResolver)' on a null object reference
at android.app.ApplicationPackageManager.queryIntentServicesAsUser(ApplicationPackageManager.java:644)
at android.app.ApplicationPackageManager.queryIntentServices(ApplicationPackageManager.java:656)
at com.jukusoft.chatter.service.ServiceConnectionManager.createExplicitFromImplicitIntent(ServiceConnectionManager.java:61)
at com.jukusoft.chatter.service.ServiceConnectionManager.startService(ServiceConnectionManager.java:42)
at com.jukusoft.chatter.MainActivity.onCreate(MainActivity.java:39)
at android.app.Activity.performCreate(Activity.java:5933)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1105)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2251)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2360)
at android.app.ActivityThread.access$800(ActivityThread.java:144)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1278)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
Alles anzeigen
The method createExplicitFromImplicitIntent(Context context, Intent implicitIntent) is from stackoverflow, but it doesnt work.
The service has to be a explecit service since Android 5.0, because they had change something in the code.
Now i have tried this, but it doesnt work.
Can anyone help me?
Do i have to change the Mainfest.xml, so that the service is founded by the PackageManager?