问题
I'm trying to create remote service that will take care for all client-server communication for few different apps. The main idea is starting the service from main activity and open a communication socket to a server. after that, the socket will be used by other apps - that's why i want to use remote service for it...
now i have an issue with the socket connection, it throws null exception on my device. it works fine on AVD using older android version.
here's some parts of my code:
my main activity:
final ServiceConnection conn = new ServiceConnection() {
public void onServiceConnected(ComponentName name, IBinder service) {
myRemoteService = ConnectionInterface.Stub.asInterface(service);
}
public void onServiceDisconnected(ComponentName name) {
myRemoteService = null;
}
};
final Thread t = new Thread(){
public void run(){
bindService(new Intent(getApplicationContext(), ConnectionRemoteService.class),conn,Context.BIND_AUTO_CREATE);
while(true){}
}
};
later on i start the Thread t with t.start();
my ConnectionRemoteService:
package com.mainlauncher;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ResourceBundle;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.net.wifi.WifiManager;
import android.os.IBinder;
import android.widget.Toast;
public class ConnectionRemoteService extends Service {
private static final int SERVERPORT = 7777;
private static final String SERVERADDRESS = "192.168.1.106";
private String deviceID;
private Socket socket;
private DataInputStream in;
private DataOutputStream out;
@Override
public void onCreate() {
super.onCreate();
WifiManager wm = (WifiManager)getSystemService(Context.WIFI_SERVICE);
deviceID = wm.getConnectionInfo().getMacAddress();
Toast.makeText(this, "Service On.", Toast.LENGTH_LONG).show();
open();
}
@Override
public void onDestroy() {
Toast.makeText(this, "Service Off.", Toast.LENGTH_LONG).show();
close();
}
@Override
public IBinder onBind(Intent intent) {
return myRemoteServiceStub;
}
private ConnectionInterface.Stub myRemoteServiceStub = new ConnectionInterface.Stub() {
};
void open(){
try{
socket = new Socket(SERVERADDRESS,SERVERPORT);
in = new DataInputStream(socket.getInputStream());
out = new DataOutputStream(socket.getOutputStream());
out.writeUTF(deviceID);
}
catch(Exception e){
System.err.println(e.getMessage());
}
}
void close(){
try {
if(in!=null)
in.close();
if(out!=null)
out.close();
if(socket!=null)
socket.close();
}
catch(Exception e){
System.err.println(e.getMessage());
}
socket=null;
}
}
Main Manifest file:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.mainlauncher"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="15" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<application
android:icon="@drawable/ic_launcher"
android:label="@string/app_name" >
<activity android:name=".MainLauncherWindow" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".ConnectionRemoteService"
android:process=":remote"/>
</application>
here's DDMS log on "debug" mode as requested:
11-06 12:13:45.130: D/InputDispatcher(392): notifyMotion - eventTime=4210399491000, deviceId=6, source=0x1002, policyFlags=0x0, action=0x0, flags=0x0, metaState=0x0, buttonState=0x0, edgeFlags=0x0, xPrecision=1.529167, yPrecision=1.383594, downTime=4210399491000 11-06 12:13:45.130: D/InputDispatcher(392): Pointer 0: id=0, toolType=1, x=66.049042, y=492.196503, pressure=0.233333, size=0.250980, touchMajor=44.054604, touchMinor=44.054604, toolMajor=4.818472, toolMinor=4.818472, orientation=0.000000 11-06 12:13:45.130: D/InputDispatcher(392): Dispatch MotionEvent [action=0] ToCurrentInputTarget: 40f9a6a8 com.mainlauncher/com.mainlauncher.MainLauncherWindow (server) 11-06 12:13:45.150: D/PowerManagerService(392): setPowerState: mPowerState=0x3, newState=0x3, noChangeLights=false, reason=3, force=false, mProximitySensorActive=false, mBootCompleted=true, mUseSoftwareAutoBrightness=true (repeat:1) 11-06 12:13:45.160: D/PowerManagerService(392): setPowerState: mPowerState=0x3, newState=0x3, noChangeLights=false, reason=2, force=false, mProximitySensorActive=false, mBootCompleted=true, mUseSoftwareAutoBrightness=true 11-06 12:13:45.160: I/PowerManagerService-JNI(392): [Stability] PowerManagerService_userActivity JNI pass power key event to PowerManagerService userActivity() 11-06 12:13:45.160: D/PowerManagerService(392): setTimeoutLocked: now=4210399, timeoutOverride=-1, nextState=0x3, when=4216399 (mKeylightDelay=6000, mDimDelay=2147469000, mScreenOffDelay=7000) 11-06 12:13:45.190: D/InputDispatcher(392): notifyMotion - eventTime=4210464940000, deviceId=6, source=0x1002, policyFlags=0x0, action=0x1, flags=0x0, metaState=0x0, buttonState=0x0, edgeFlags=0x0, xPrecision=1.529167, yPrecision=1.383594, downTime=4210399491000 11-06 12:13:45.190: D/InputDispatcher(392): Pointer 0: id=0, toolType=1, x=65.395096, y=492.919250, pressure=0.233333, size=0.219608, touchMajor=38.547779, touchMinor=38.547779, toolMajor=4.818472, toolMinor=4.818472, orientation=0.000000 11-06 12:13:45.190: D/InputDispatcher(392): Dispatch MotionEvent [action=1] ToCurrentInputTarget: 40f9a6a8 com.mainlauncher/com.mainlauncher.MainLauncherWindow (server) 11-06 12:13:45.220: D/dalvikvm(153): Before fork 11-06 12:13:45.230: D/dalvikvm(20210): Fork pid: 0 11-06 12:13:45.230: D/dalvikvm(20210): Late-enabling CheckJNI 11-06 12:13:45.230: D/dalvikvm(153): Fork pid: 20210 11-06 12:13:45.240: D/Performance(392): AutoProf Starting process { Process=com.mainlauncher:remote, ActivityName=com.mainlauncher/.ConnectionRemoteService}, pid=20210 11-06 12:13:45.240: I/ActivityManager(392): Start proc com.mainlauncher:remote for service com.mainlauncher/.ConnectionRemoteService: pid=20210 uid=10080 gids={3003} 11-06 12:13:45.300: D/ConnSrv_Debug(392): get mDefaultProxy null by 20210/10080 11-06 12:13:45.300: D/WifiStateMachine(392): syncRequestConnectionInfo mWifiInfo=SSID: linksys, BSSID: 00:14:bf:e6:13:8f, MAC: 18:87:96:88:cd:68, Supplicant state: COMPLETED, RSSI: -83, Link speed: 36, Frequency: 2462, Net ID: 1, Explicit connect: false 11-06 12:13:45.320: D/AndroidRuntime(20210): Shutting down VM 11-06 12:13:45.320: W/dalvikvm(20210): threadid=1: thread exiting with uncaught exception (group=0x40a6b228) 11-06 12:13:45.320: E/EmbeddedLogger(392): App crashed! Process: com.mainlauncher:remote 11-06 12:13:45.320: E/EmbeddedLogger(392): App crashed! Package: com.mainlauncher v1 (1.0) 11-06 12:13:45.320: E/AndroidRuntime(20210): FATAL EXCEPTION: main 11-06 12:13:45.320: E/AndroidRuntime(20210): java.lang.RuntimeException: Unable to create service com.mainlauncher.ConnectionRemoteService: java.lang.NullPointerException 11-06 12:13:45.320: E/AndroidRuntime(20210): at android.app.ActivityThread.handleCreateService(ActivityThread.java:2593) 11-06 12:13:45.320: E/AndroidRuntime(20210): at android.app.ActivityThread.access$1600(ActivityThread.java:139) 11-06 12:13:45.320: E/AndroidRuntime(20210): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1326) 11-06 12:13:45.320: E/AndroidRuntime(20210): at android.os.Handler.dispatchMessage(Handler.java:99) 11-06 12:13:45.320: E/AndroidRuntime(20210): at android.os.Looper.loop(Looper.java:156) 11-06 12:13:45.320: E/AndroidRuntime(20210): at android.app.ActivityThread.main(ActivityThread.java:5025) 11-06 12:13:45.320: E/AndroidRuntime(20210): at java.lang.reflect.Method.invokeNative(Native Method) 11-06 12:13:45.320: E/AndroidRuntime(20210): at java.lang.reflect.Method.invoke(Method.java:511) 11-06 12:13:45.320: E/AndroidRuntime(20210): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784) 11-06 12:13:45.320: E/AndroidRuntime(20210): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551) 11-06 12:13:45.320: E/AndroidRuntime(20210): at dalvik.system.NativeStart.main(Native Method) 11-06 12:13:45.320: E/AndroidRuntime(20210): Caused by: java.lang.NullPointerException 11-06 12:13:45.320: E/AndroidRuntime(20210): at com.android.internal.os.LoggingPrintStream.println(LoggingPrintStream.java:298) 11-06 12:13:45.320: E/AndroidRuntime(20210): at com.mainlauncher.ConnectionRemoteService.open(ConnectionRemoteService.java:60) 11-06 12:13:45.320: E/AndroidRuntime(20210): at com.mainlauncher.ConnectionRemoteService.onCreate(ConnectionRemoteService.java:33) 11-06 12:13:45.320: E/AndroidRuntime(20210): at android.app.ActivityThread.handleCreateService(ActivityThread.java:2571) 11-06 12:13:45.320: E/AndroidRuntime(20210): ... 10 more 11-06 12:13:45.330: E/EmbeddedLogger(392): Application Label: Launcher
I get the exception on this line:
socket = new Socket(SERVERADDRESS,SERVERPORT);
I know few things that can make that exception:
1. I use <uses-permission android:name="android.permission.INTERNET" />
in my main manifest.
2. The Service run under separated thread, not on the main activity thread.
3. There's no firewall etc...
4. I checked connection with the server already (all worked fine without the service).
5. I'm using android:process=":remote" in my manifest too.
any ideas why that exception occurs? how can i debug it to get more details?
it worked find on AVD using OS 2.3, so i think it's something with the main activity thread exception, but i can't find out why.
thanks, Lioz.
回答1:
You are calling open()
from onCreate()
. onCreate()
is called on the main thread. You shouldn't do network I/O on the main thread. You've got the separate thread thing in the wrong place. In your activity you're starting a separate thread that calls bindService()
and then loops forever (infinite loop chewing up CPU cycles, not a good thing). You don't need to call bindService()
from inside a separate thread because bindService()
is asynchronous. It only initiates the binding, it doesn't actually wait for the binding to complete. This can be done on the main thread.
Where you need to start a thread is inside your service. When your service gets created, you should start a separate thread in onCreate()
and that separate thread needs to do the network I/O (ie: open socket, read, write, etc.).
Also, you can make debugging easier by removing android:process=":remote"
from the manifest. This will allow you to set breakpoints easier in the service methods.
回答2:
Did you tried to put the Internet permission in your AndroidManifest.xml? Connecting to a server (even its a "local" running server) needs internet permissions i think.
来源:https://stackoverflow.com/questions/13239139/android-service-opening-socket-throws-null-exception