2012-02-18 3 views
16

빌드 한 웹 서비스에 대한 간단한 Android 클라이언트를 만들려고하는데 런타임시 문제가 발생합니다.Android 용 저지 클라이언트 - NullPointerException

02-18 16:26:06.446: E/AndroidRuntime(1381): FATAL EXCEPTION: AsyncTask #1 
02-18 16:26:06.446: E/AndroidRuntime(1381): java.lang.RuntimeException: An error occured while executing doInBackground() 
02-18 16:26:06.446: E/AndroidRuntime(1381):  at android.os.AsyncTask$3.done(AsyncTask.java:278) 
02-18 16:26:06.446: E/AndroidRuntime(1381):  at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273) 
02-18 16:26:06.446: E/AndroidRuntime(1381):  at java.util.concurrent.FutureTask.setException(FutureTask.java:124) 
02-18 16:26:06.446: E/AndroidRuntime(1381):  at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307) 
02-18 16:26:06.446: E/AndroidRuntime(1381):  at java.util.concurrent.FutureTask.run(FutureTask.java:137) 
02-18 16:26:06.446: E/AndroidRuntime(1381):  at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:208) 
02-18 16:26:06.446: E/AndroidRuntime(1381):  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076) 
02-18 16:26:06.446: E/AndroidRuntime(1381):  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569) 
02-18 16:26:06.446: E/AndroidRuntime(1381):  at java.lang.Thread.run(Thread.java:856) 
02-18 16:26:06.446: E/AndroidRuntime(1381): Caused by: java.lang.NullPointerException 
02-18 16:26:06.446: E/AndroidRuntime(1381):  at javax.ws.rs.core.MediaType.valueOf(MediaType.java:119) 
02-18 16:26:06.446: E/AndroidRuntime(1381):  at com.sun.jersey.api.client.ClientResponse.getType(ClientResponse.java:615) 
02-18 16:26:06.446: E/AndroidRuntime(1381):  at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:532) 
02-18 16:26:06.446: E/AndroidRuntime(1381):  at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:506) 
02-18 16:26:06.446: E/AndroidRuntime(1381):  at com.sun.jersey.api.client.WebResource.handle(WebResource.java:674) 
02-18 16:26:06.446: E/AndroidRuntime(1381):  at com.sun.jersey.api.client.WebResource.access$200(WebResource.java:74) 
02-18 16:26:06.446: E/AndroidRuntime(1381):  at com.sun.jersey.api.client.WebResource$Builder.get(WebResource.java:503) 
02-18 16:26:06.446: E/AndroidRuntime(1381):  at com.maze.client.MyClient.doInBackground(MyClient.java:25) 
02-18 16:26:06.446: E/AndroidRuntime(1381):  at com.maze.client.MyClient.doInBackground(MyClient.java:1) 
02-18 16:26:06.446: E/AndroidRuntime(1381):  at android.os.AsyncTask$2.call(AsyncTask.java:264) 
02-18 16:26:06.446: E/AndroidRuntime(1381):  at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305) 
02-18 16:26:06.446: E/AndroidRuntime(1381):  ... 5 more 

이해가 안 : 나는 로그 캣이 스택 트레이스를 얻을

@Path("/service") 
public class AndroidService { 

@GET 
@Produces(MediaType.APPLICATION_JSON) 
@Path("/hello") 
public String getJSON(@QueryParam("number") String nr) 
{ 

    String s = "Hi there! The number is: "+nr; 
    return s; 
} 
} 

:

public class MyClient extends AsyncTask<EditText, Integer, String> { 

private EditText text; 

protected String doInBackground(EditText... strings) { 

    RuntimeDelegate 
      .setInstance(new com.sun.ws.rs.ext.RuntimeDelegateImpl()); 
    WebResource wbr; 
    Client client = Client.create(); 
    wbr = client 
      .resource("http://my.ip:8080/MazeService/rest/service/hello"); 
    String result = wbr.queryParam("number", "10") 
      .accept(MediaType.APPLICATION_JSON).get(String.class); 
    text = strings[0]; 
    return result; 
} 

protected void onProgressUpdate(Integer... progress) { 
    // setProgressPercent(progress[0]); 
} 

protected void onPostExecute(String result) { 
    if (result != null) 
     this.text.setText(result); 
    else 
     Log.d("MyApp", "No Result"); 
} 

}

및 서비스 : 여기

는 클라이언트입니다 직업이란 무엇인가? blem은 비슷한 클라이언트가 PC에서 작동하기 때문에 발생합니다. Android VirtualDevice에서 서버에 액세스 할 수 있으므로 IP 주소에는 문제가 없습니다.

Android 버전은 4.0.3 API 버전 15입니다. 클라이언트의 경우 Jersey 1.11을 사용했습니다.

편집

누군가가 그것이 있어야로 사용하지 않는 나에게 말했다 이후는 또한 글고 치기로 전체를 제거하기 위해 노력했다. 여전히 같은 오류가 있습니다. 나는 내가 뭘 잘못하고 있는지 이해할 수 없다. 다른 추가 정보를 표시해야하는 경우 알려 주시기 바랍니다. 또한, 어떤 생각이 좋다. 나는 안드로이드를 처음 접했고 어리석은 실수를 저질렀을지도 모른다. 코드에 따라

+0

귀하의 문제가있다 NullPointer 뭔가'문자열 결과 = wbr.queryParam ("숫자", "10") .accept (MediaType.APPLICATION_JSON) .get (String.class); ' – Blundell

+0

@Blundell 예, 그게 문제가 될 수도 있다고 생각 ,하지만이 코드가 포함 된 간단한 프로그램이 있기 때문에이 문제가 발생하는지 이해할 수 없습니다. 완벽하게 달리고 있습니다. – Dragos

+0

@ L7ColWinters 정확히 어떻게해야하는지 이해가 안됩니다. 몇 가지 코드를 입력하십시오. – Dragos

답변

18

폴의 제안은 정확합니다. 나는 그 주제에서 조금 더 깊어졌고 이유를 발견했다.

Android apk 패키징 도구 (sdklib.jar의 APKBuilder 클래스)는 패키지를 생성하는 동안 (source) 다른 폴더를 무시합니다. 해당 폴더 중 하나는 META-INF입니다. 연결된 라이브러리 또는 프로젝트 원본 폴더에 상관없이 META-INF입니다.

저지의 버전 1.8에 대한 회피책 (및 다른 테스트도 있지만 테스트하지는 않았습니다.)은 사용자 정의 (기본값은 META-INF/services /는 Android APK에 없습니다)를 제공하는 것입니다. ServiceFinder$ServiceIteratorProvider 하드 코딩 된 공급자 클래스 이름이 있습니다.나는 기반 루카스에 의해 제안 된 this 구현에 내 구현 : 내가 그들을 사용하지 않았으며 또한 그들이 달빅의 VM에 확인 오류가 발생 된 이후 내가 클래스의 대부분을 제거

import java.util.ArrayList; 
import java.util.HashMap; 
import java.util.Iterator; 

import android.util.Log; 

import com.sun.jersey.spi.service.ServiceFinder.ServiceIteratorProvider; 

public class AndroidServiceIteratorProvider<T> extends ServiceIteratorProvider<T> { 

    private static final String TAG = AndroidServiceIteratorProvider.class.getSimpleName(); 
    private static final String MESSAGE = "Unable to load provider"; 

    private static final HashMap<String, String[]> SERVICES = new HashMap<String, String[]>(); 

    private static final String[] com_sun_jersey_spi_HeaderDelegateProvider = { 
      "com.sun.jersey.core.impl.provider.header.MediaTypeProvider", 
      "com.sun.jersey.core.impl.provider.header.StringProvider" 
    }; 

    private static final String[] com_sun_jersey_spi_inject_InjectableProvider = { 
    }; 

    private static final String[] javax_ws_rs_ext_MessageBodyReader = { 
      "com.sun.jersey.core.impl.provider.entity.StringProvider", 
      "com.sun.jersey.core.impl.provider.entity.ReaderProvider" 
    }; 

    private static final String[] javax_ws_rs_ext_MessageBodyWriter = { 
      "com.sun.jersey.core.impl.provider.entity.StringProvider", 
      "com.sun.jersey.core.impl.provider.entity.ReaderProvider" 
    }; 

    static { 
     SERVICES.put("com.sun.jersey.spi.HeaderDelegateProvider", 
       com_sun_jersey_spi_HeaderDelegateProvider); 
     SERVICES.put("com.sun.jersey.spi.inject.InjectableProvider", 
       com_sun_jersey_spi_inject_InjectableProvider); 
     SERVICES.put("javax.ws.rs.ext.MessageBodyReader", 
       javax_ws_rs_ext_MessageBodyReader); 
     SERVICES.put("javax.ws.rs.ext.MessageBodyWriter", 
       javax_ws_rs_ext_MessageBodyWriter); 
     SERVICES.put("jersey-client-components", new String[]{}); 
     SERVICES.put("com.sun.jersey.client.proxy.ViewProxyProvider", new String[]{}); 
    } 

    @SuppressWarnings("unchecked") 
    @Override 
    public Iterator<Class<T>> createClassIterator(Class<T> service, 
      String serviceName, ClassLoader loader, 
      boolean ignoreOnClassNotFound) { 

     String[] classesNames = SERVICES.get(serviceName); 
     int length = classesNames.length; 
     ArrayList<Class<T>> classes = new ArrayList<Class<T>>(length); 
     for (int i = 0; i < length; i++) { 
      try { 
       classes.add((Class<T>) Class.forName(classesNames[i])); 
      } catch (ClassNotFoundException e) { 
       Log.v(TAG, MESSAGE,e); 
      } 
     } 
     return classes.iterator(); 
    } 

    @Override 
    public Iterator<T> createIterator(Class<T> service, String serviceName, 
      ClassLoader loader, boolean ignoreOnClassNotFound) { 

     String[] classesNames = SERVICES.get(serviceName); 
     int length = classesNames.length; 
     ArrayList<T> classes = new ArrayList<T>(length); 
      for (int i = 0; i &lt; length; i++) { 
      try { 
       classes.add(service.cast(Class.forName(classesNames[i]) 
         .newInstance())); 
      } catch (IllegalAccessException e) { 
       Log.v(TAG, MESSAGE,e); 
      } catch (InstantiationException e) { 
       Log.v(TAG, MESSAGE,e); 
      } catch (ClassNotFoundException e) { 
       Log.v(TAG, MESSAGE,e); 
      } 
     } 

     return classes.iterator(); 
    } 
} 

...

참고 :이 구현에서는 Jersey에서 지원하는 헤더/유형의 하위 집합 만 사용할 수 있음을 의미합니다 (String 만 필요함). 다른 유형을 지원하려면 jersey-client.jar의 META-INF/services 폴더 (또는 Lucas의 구현)에있는 제공자를 추가하고 Android에서 확인 오류가 발생하지 않는지 확인해야합니다.

ServiceFinder.setIteratorProvider(new AndroidServiceIteratorProvider()); 
Client client = Client.create(); 

편집이 :

문제가 안드로이드 - 받는다는 - 플러그인에 fixed이었을 것으로 보인다 다음과 같이

위의 코드 사용해야합니다.

모사 ... @ gmail.com 썼다 :

수정으로 끌어 오기 요청 마스터에 병합되었고, 3.2.1과 함께 출시됩니다

1

:

com/sun/jersey/api/client/ClientResponse.getType()

613 public MediaType getType() { 
614  String ct = getHeaders().getFirst("Content-Type"); 
615  return (ct != null) ? MediaType.valueOf(ct) : null; 
616 } 

MediaType에 의해 사용 된 대리인이 null이 아니라는 것을 나는 확인할 것. 어쩌면 delegate는 하나의 클라이언트 (안드로이드)와 다른 클라이언트하지 null에 대한 null처럼

javax/ws/rs/core/MediaType.valueOf(java.lang.String)

118 public static MediaType valueOf(String type) throws IllegalArgumentException { 
119  return delegate.fromString(type); 
120 } 

는 것 같습니다.

대리인이 초기화되는 방법에 대한 아이디어를 얻으려면이 부분을 살펴보십시오. 조사에 도움이 될지도 모릅니다.

javax/ws/rs/ext/RuntimeDelegate.java

+0

고맙다. 내가 이걸 가지고 어디로 갈 수 있는지 알아 보겠다. – Dragos