2012-02-18 28 views
16

Tôi đang cố gắng tạo một ứng dụng khách Android đơn giản cho dịch vụ web mà tôi đã tạo, nhưng đã xảy ra sự cố khi chạy.Khách hàng Jersey trên Android - NullPointerException

Đây là Chủ đầu tư:

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"); 
} 

}

và Dịch vụ:

@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; 
} 
} 

tôi nhận được stacktrace này trong LogCat:

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 

Tôi không hiểu những gì các chuyên nghiệp blem là, vì một máy khách tương tự hoạt động trên PC. Không có vấn đề gì với địa chỉ IP, vì tôi có thể truy cập máy chủ từ Android VirtualDevice.

Phiên bản Android là phiên bản 4.0.3 API 15. Đối với ứng dụng khách, tôi đã sử dụng Jersey 1.11.

EDIT

Tôi cũng đã cố gắng để loại bỏ toàn bộ điều với EditText, vì ai đó nói với tôi nó không được sử dụng như nó phải được. Tuy nhiên, tôi đã nhận được lỗi tương tự. Tôi chỉ đơn giản là không thể hiểu tôi đang làm gì sai. Nếu tôi nên hiển thị bất kỳ thông tin bổ sung nào khác, vui lòng cho tôi biết. Ngoài ra, BẤT K idea ý tưởng là tốt. Tôi mới sử dụng Android và tôi có thể đã mắc phải một số lỗi lầm ngu ngốc.

+0

Vấn đề của bạn là một NullPointer một cái gì đó để làm với 'String kết quả = wbr.queryParam (" số "," 10 ") . Chấp nhận (MediaType.APPLICATION_JSON) .get (String.class);' – Blundell

+0

@Blundell Vâng, tôi nghĩ rằng có thể là vấn đề , nhưng tôi không hiểu TẠI SAO vấn đề này xuất hiện, vì một chương trình đơn giản có chứa mã đó là chạy hoàn hảo. – Dragos

+0

@ L7ColWinters Tôi không hiểu chính xác tôi phải làm như thế nào. Vui lòng cung cấp một số mã. – Dragos

Trả lời

18

Đề xuất của Paul là chính xác. Tôi đã có một chút sâu sắc hơn trong chủ đề đó và tìm thấy một lý do.

Công cụ đóng gói apk Android (Lớp APKBuilder từ sdklib.jar) bỏ qua các thư mục khác nhau khi tạo gói (source). Một trong những thư mục đó là META-INF - bất kể nó nằm trong thư viện đính kèm hay trong thư mục nguồn của dự án.

Giải pháp cho phiên bản 1.8 (và có lẽ khác, nhưng tôi không kiểm tra) của Jersey là cung cấp tùy chỉnh (mặc định một tra cứu META-INF/dịch vụ/không có trong apk android) triển khai cho ServiceFinder$ServiceIteratorProvider có tên lớp của nhà cung cấp được mã hóa cứng.Tôi dựa thực hiện của tôi trên this thực hiện bởi Lucas đề xuất:

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(); 
    } 
} 

Tôi đã gỡ bỏ hầu hết các lớp học vì tôi không sử dụng chúng và cũng có thể họ đã gây ra lỗi xác minh trên Dalvik vm ...

LƯU Ý : Nó có nghĩa là với việc thực hiện này, bạn chỉ có thể sử dụng tập con của các tiêu đề/kiểu được hỗ trợ bởi Jersey (tôi chỉ cần String). Để hỗ trợ các loại khác, bạn phải thêm các nhà cung cấp nằm trong thư mục META-INF/services của jersey-client.jar (hoặc từ triển khai Lucas) và kiểm tra xem chúng có gây ra lỗi xác minh trên Android hay không.

Đoạn mã trên nên được sử dụng như sau:

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

EDIT:

Dường như vấn đề đã fixed trong android-maven-plugin.

mosa ... @ gmail.com viết:

Yêu cầu kéo với việc sửa chữa đã được sáp nhập vào tổng thể và sẽ được phát hành với 3.2.1:

1

Tiếp theo mã:

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 } 

tôi muốn kiểm tra xem các đại biểu được sử dụng bởi MediaType không phải là 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 } 

Dường như có lẽ delegatenull cho một khách hàng (Android) và không null cho khách hàng khác của bạn.

Hãy xem điều này để có ý tưởng về cách ủy quyền được khởi tạo. Nó có thể giúp điều tra của bạn.

javax/ws/rs/ext/RuntimeDelegate.java

+0

Cảm ơn bạn, tôi sẽ xem nơi tôi có thể nhận được với điều này. – Dragos

Các vấn đề liên quan