【问题标题】:How to call a Web Services using Android如何使用 Android 调用 Web 服务
【发布时间】:2018-04-21 16:16:52
【问题描述】:

我是 Android 应用程序开发的新手。我正在开发一个购物车应用程序。我正在尝试使用 android 以 GET 方法调用 Web 服务。但是我该怎么做呢?我试过的就在这里。但它给了我一个错误PostResponseAsyncTask: 405 Method not allowed。如何解决?任何人都可以帮助我吗?提前致谢。

MainFragment 类

public class MainFragment extends Fragment implements AsyncResponse, AdapterView.OnItemClickListener{
    public static final String PREFS = "prefFile";
    final String LOG = "MainFragment";

    final static String url = "http://10.0.3.2:8080/WebService/rest/get/products";

    private ArrayList<Products> productList;
    private ListView lv;
    FunDapter<Products> adapter;

    View view;


    public MainFragment() {

    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {

        view = inflater.inflate(R.layout.fragment_main, container, false);

        ImageLoader.getInstance().init(UILConfig.config(MainFragment.this.getActivity()));

        PostResponseAsyncTask taskRead = new PostResponseAsyncTask(MainFragment.this.getActivity(), this);
        taskRead.execute(url);


        return view;
    }

    @Override
    public void processFinish(String s) {

        productList = new JsonConverter<Products>().toArrayList(s, Products.class);

        BindDictionary dic = new BindDictionary();

        dic.addStringField(R.id.tvName, new StringExtractor<Products>() {
            @Override
            public String getStringValue(Products item, int position) {
                return item.name;
            }
        });

        dic.addStringField(R.id.tvDesc, new StringExtractor<Products>() {
            @Override
            public String getStringValue(Products item, int position) {
                return item.description;
            }
        }).visibilityIfNull(View.GONE);

        dic.addStringField(R.id.tvPrice, new StringExtractor<Products>() {
            @Override
            public String getStringValue(Products item, int position) {
                return ""+item.price;
            }
        });

        dic.addDynamicImageField(R.id.ivImage, new StringExtractor<Products>() {
            @Override
            public String getStringValue(Products item, int position) {
                return item.pic;
            }
        }, new DynamicImageLoader() {
            @Override
            public void loadImage(String url, ImageView img) {
                //Set image
                ImageLoader.getInstance().displayImage(url, img);
            }
        });

        dic.addBaseField(R.id.btnCart).onClick(new ItemClickListener() {
        });

        adapter = new FunDapter<>(MainFragment.this.getActivity(), productList, R.layout.product_row, dic);
        lv = (ListView)view.findViewById(R.id.lvProduct);
        lv.setAdapter(adapter);

        lv.setOnItemClickListener(this);

    }

    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {

    }
}

【问题讨论】:

  • 服务器端好像有问题。由于405错误代码提示“请求方法被服务器知道但已被禁用,无法使用。”
  • @WaqarUlHaq 这不是服务器端问题。是他的请求方法问题。
  • 我认为处理网络 api 的最佳方法是使用改造。并检查数据来定义 url 并定义 405 错误

标签: android rest web-services


【解决方案1】:

尝试使用一些库,例如 Retrofit、Volley、Loopj 等来处理异步 GET 或 POST HTTP 请求。

要从 url 或文件路径实现动态图像,请使用 Piccasso 或 Glide 库。

这里有一些关于这些库的示例和文档

循环

  1. Loopj official Documentation and Example

改造

  1. Retrofit official Documentation By SquareUp
  2. Retrofit Tutorial from JournelDev

凌空抽射

  1. Volley official Documenation By Android Developers
  2. Volley tutorial from Journeldev

动态图像处理

毕加索

Android Picasso Library

滑行

Glide Library for Android

希望这些对你有帮助

改造示例

build.gradle(app)

        implementation 'com.google.code.gson:gson:2.6.2'
        implementation 'com.squareup.retrofit2:retrofit:2.0.2'
        implementation 'com.squareup.retrofit2:converter-gson:2.0.2'

主片段

public class MainFragment extends Fragment {

    public static final String PREFS = "prefFile";
    final String LOG = "MainFragment";

    private ArrayList<Product> productList;
    private ListView lv;
    FunDapter adapter;
    private ApiInterface apiInterface;

    View view;


    public MainFragment() {
        // Required empty public constructor
    }


    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_main, container, false);
    }

    @Override
    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);


        lv = (ListView) view.findViewById(R.id.lvProduct);
        apiInterface = ApiClient.getRetrofitApiClient().create(ApiInterface.class);

        productList  = new ArrayList<Product>();

        adapter= new FunDapter (getContext(), 0, productList);
        lv.setAdapter(adapter);

        getProduct();


    }

    private void getProduct() {

        Call<List<Product>> call = apiInterface.getProducts();
        call.enqueue(new Callback<List<Product>>() {
            @Override
            public void onResponse(Call<List<Product>> call, Response<List<Product>> response) {

                List<Product> products= response.body();
                Log.d("TEST", "onResponse: "+response.body().size());
                if(products.size()>0){
                    productList.addAll(products);
                }

                adapter.notifyDataSetChanged();
            }

            @Override
            public void onFailure(Call<List<Product>> call, Throwable t) {

            }
        });

    }
}

ApiClient

import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

/**
 * Created by android on 3/10/17.
 */
class ApiClient {

        public static final String BASE_URL = "http://10.0.2.2:8080/WebService/rest/";

        public static Retrofit retrofit = null;

        public static Retrofit getRetrofitApiClient() {
            if (retrofit == null) {
                retrofit = new Retrofit.Builder().baseUrl(BASE_URL).addConverterFactory(GsonConverterFactory.create()).build();
            }

            return retrofit;
        }
    }

API接口

import java.util.List;

import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.GET;
import retrofit2.http.POST;
import retrofit2.http.Query;


public interface ApiInterface {

    @GET("get/products")
    Call<List<Product>> getProducts();

}

产品

import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;

class Product {

    @SerializedName("name")
    @Expose
    private String name;
    @SerializedName("ram")
    @Expose
    private String ram;
    @SerializedName("price")
    @Expose
    private String price;
    @SerializedName("pic")
    @Expose
    private String pic;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getRam() {
        return ram;
    }

    public void setRam(String ram) {
        this.ram = ram;
    }

    public String getPrice() {
        return price;
    }

    public void setPrice(String price) {
        this.price = price;
    }

    public String getPic() {
        return pic;
    }

    public void setPic(String pic) {
        this.pic = pic;
    }

}

FunDapter

class FunDapter extends ArrayAdapter<Product> {

    private Context context;
    private ArrayList<Product> objects;
    private static LayoutInflater inflater = null;

    public FunDapter(@NonNull Context context, int resource, @NonNull ArrayList<Product> objects) {
        super(context, resource, objects);
        try {
            this.context = context;
            this.objects = objects;

            inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        } catch (Exception e) {

        }
    }
    public int getCount() {
        return objects.size();
    }

    public Product getItem(Product position) {
        return position;
    }

    public long getItemId(int position) {
        return position;
    }

    public static class ViewHolder {
        public TextView display_name;
        public TextView display_number;
        public ImageView image;

    }

    public View getView(int position, View convertView, ViewGroup parent) {
        View vi = convertView;
        final ViewHolder holder;
        try {
            if (convertView == null) {
                vi = inflater.inflate(R.layout.singlerow_mylistview, null);
                holder = new ViewHolder();

                holder.display_name = (TextView) vi.findViewById(R.id.title_listview);
                holder.display_number = (TextView) vi.findViewById(R.id.subtitle_listview);
                holder.image = (ImageView) vi.findViewById(R.id.icon_listview);



                vi.setTag(holder);
            } else {
                holder = (ViewHolder) vi.getTag();
            }



            holder.display_name.setText(objects.get(position).getName());
            holder.display_number.setText(objects.get(position).getPrice());

            Picasso.with(context)
                    .load(objects.get(position).getPic())
                    .resize(50, 50)
                    .centerCrop()
                    .into(holder.image);


        } catch (Exception e) {


        }
        return vi;
    }
}

不要忘记在 Manifest 中添加&lt;uses-permission android:name="android.permission.INTERNET" /&gt;

【讨论】:

  • @AbrahamArnold :在提供的链接中,您将看到示例。
  • 在不知道返回 JSON 和您处理它的逻辑的情况下,我们无法为您提供准确的代码。通过使用 Retrofit tou 可以将 Result JSON 直接转换为 bean Class Arraylist...
  • 我可以提供返回json数据。我试过loopJretrofit。但无法弄清楚如何获取当前片段。
  • 非常感谢。它工作得很好。一次又一次地感谢你。 :)
  • :) 很高兴看到这里。快乐编码@AbrahamArnold
【解决方案2】:

您正在通过执行此 PostResponseAsyncTask 执行 POST 请求,这就是您收到 405 Method not allowed 的原因。如果该端点接受 GET,则执行 GET 请求。最好使用 VolleyRetrofit 库进行网络通信。

【讨论】:

  • 如何发送 GET 请求?我需要将响应数据与此片段同步。那么我该如何发送 GET 请求先生?如果你能给我代码它会帮助我,因为我是android开发的新手。
  • 试试这个例子examples.javacodegeeks.com/android/core/android-volley-example如果你得到帮助,别忘了接受我的回答或投票:)
  • 你能告诉我如何将它添加到此类并在 ProcessFinish 方法中获取数据。
  • 到目前为止,我还没有找到和可能的方法来使用您当前的库进行 GET 请求
  • 如果我使用您提供的那个 volley 库。如何将该代码添加到此 MainFragment 并在 ProcessFinish 方法中获取数据?先生,这是一个很大的帮助。
【解决方案3】:

尝试使用retrofit,先添加如下依赖

compile 'com.squareup.retrofit2:retrofit:2.3.0'

compile 'com.squareup.retrofit2:converter-gson:2.3.0'

首先尝试找出您从后端获得的 json 响应类型 - 它可以是数组响应/对象响应。

Json 数组响应的形式为 [{"field1":"value1",..},{"field2":"value2",..}..] 而对象 回复的格式为{"field1":"value1",..}

您可以查看this tutorial 了解如何解析 json 响应

如果您检查后端并找出响应,那么您可以使用来自http://www.jsonschema2pojo.org/ 的相同生成模型类

案例 1:假设您有一个 json object 响应({"field1":"value1",..})

首先使用上面提到的jsonschema2pojo 的响应创建一个模型类,然后像下面这样调用它(假设YourObjectModel 是你的模型类)

Retrofit retrofit = new Retrofit.Builder()
            .baseUrl("http://10.0.3.2:8080/WebService/")
            .addConverterFactory(GsonConverterFactory.create())
            .build();

    SampleInterface request = retrofit.create(SampleInterface.class);
    Call<YourObjectModel> call1=request.getResponse();
    call1.enqueue(new Callback<YourObjectModel>() {
        @Override
        public void onResponse(Call<YourObjectModel> call, Response<YourObjectModel> response) {
            Toast.makeText(MainActivity.this,response.body().toString(),Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onFailure(Call<YourObjectModel> call, Throwable t) {
            Toast.makeText(MainActivity.this,t.toString(),Toast.LENGTH_SHORT).show();
        }

    });

SampleInterface.java

public interface SampleInterface {
@GET("rest/get/products")
Call<YourObjectModel> getResponse();
}

案例 2:假设您有一个 json array 响应([{"field1":"value1",..},{"field2":"value2",..}..])

首先像上面的例子一样创建一个模型类,因为它是一个数组响应,您可能需要将响应作为列表获取,因此将所有call 方法从Call&lt;YourObjectModel&gt; 更改为Call&lt;List&lt;YourArrayModel&gt;&gt;

YourArrayModel 是您的 json 数组响应的模型类

【讨论】:

  • 感谢您的回答。
【解决方案4】:

试试这个例子很容易这个例子必须帮助你。

  1. asynctask-callback
  2. volley-callback

【讨论】:

  • 感谢您的回答。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-28
  • 2011-08-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多