使用卡片视图在回收器视图中加载文本太慢

时间:2015-12-22 12:32:26

标签: android android-fragments android-asynctask android-recyclerview

我对回收商视图和卡片视图有疑问。我正在使用asynctask从API获取信息,现在我只得到一个名字 - 这意味着,我在卡片视图中只显示一个文本视图。但是,当我加载列表时,它非常慢。在log cat中我可以看到应用程序正在快速获取数据,但在回收站视图中显示它需要花费大量时间。

我正在添加一些样本 - 来自回收器视图的适配器和保存回收器视图的片段。也许我在适配器中做错了。

感谢您的帮助!

适配器:

public class PlacesListAdapter extends RecyclerView.Adapter<PlacesListAdapter.ListViewHolder>{
ArrayList<PlaceItem> items;
Context context;

public PlacesListAdapter(Context context,ArrayList<PlaceItem> placeItems){
    this.context = context;
    this.items = placeItems;
}

public void swap(ArrayList<PlaceItem> places){
    items.clear();
    items.addAll(places);
    notifyDataSetChanged();
}

@Override
public ListViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    View v = LayoutInflater.from(context).inflate(R.layout.card_view, parent, false);
    return new ListViewHolder(v);
}

@Override
public void onBindViewHolder(ListViewHolder holder, int position) {
    PlaceItem item = items.get(position);
    holder.bindData(item);
}

@Override
public int getItemCount() {
    return items.size();
}

public class ListViewHolder extends RecyclerView.ViewHolder{
    TextView title;
    PlaceItem placeItem;
    public ListViewHolder(View itemView) {
        super(itemView);
        title = (TextView) itemView.findViewById(R.id.txtTitlePlace);
    }

    public void bindData(PlaceItem item){
        this.placeItem = item;
        title.setText(placeItem.getTitle());
    }
  }
}

片段:

public class FragmentListPlaces extends Fragment implements  View.OnClickListener {

ArrayList<PlaceItem> placeItems;
PlacesListAdapter adapter;
RecyclerView list;
EditText editName;

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

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    View v = inflater.inflate(R.layout.fragment_list_places, container, false);
    editName = (EditText) v.findViewById(R.id.editPlaceName);
    v.findViewById(R.id.btnGetLocations).setOnClickListener(this);
    v.findViewById(R.id.btnSearchByText).setOnClickListener(this);
    placeItems = new ArrayList<>();
    placeItems.add(new PlaceItem("Example"));
    adapter = new PlacesListAdapter(getContext(), placeItems);
    list = (RecyclerView) v.findViewById(R.id.placesList);
    list.setLayoutManager(new LinearLayoutManager(getContext()));
    list.setAdapter(adapter);
    return v;
}

@Override
public void onClick(View v) {
    switch (v.getId()){
        case R.id.btnGetLocations:
            GetUserLocation location = new GetUserLocation();
            location.getLocation(getActivity());
            adapter.swap(placeItems);
            break;
        case R.id.btnSearchByText:
            // this is the method loading data with user input
            String getNameFromUser = editName.getText().toString();
            searchPlaceByText(getNameFromUser);
            adapter.swap(placeItems);
            break;
    }
}

public void searchPlaceByText(String place){
    // instantiate the asynctask here
    LocationDetailsByText locationDetailsByText = new LocationDetailsByText(placeItems);
    locationDetailsByText.execute("http://api.v3.factual.com/t/places-il?q=" + place + "&KEY=AFvDryDJmPkkgXohbpFdqkRQelT9w0HKtyEqXy3G");
}

从网络上加载数据:

public class LocationDetailsByText extends AsyncTask<String, Void, String> {

ArrayList<PlaceItem> placeItems = new ArrayList<>();

public LocationDetailsByText(ArrayList<PlaceItem> places){
    this.placeItems = places;
}
@Override
protected String doInBackground(String... params) {
    StringBuilder result = new StringBuilder();
    BufferedReader reader;
    HttpURLConnection connection = null;
    URL url;

    String query = (params[0]);
    try {
        url = new URL(query);
        connection = (HttpURLConnection)url.openConnection();

        if(connection.getResponseCode() != 200){
            return "Error!";
        }

        reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));

        String line = "";
        while((line = reader.readLine())!= null){
            result.append(line);
        }
    } catch (MalformedURLException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }finally {
        connection.disconnect();
    }
    return result.toString();
}

@Override
protected void onPostExecute(String s) {
    PlaceItem placeItem;
    try {
        JSONObject root = new JSONObject(s);
        JSONObject response = root.getJSONObject("response");
        JSONArray data = response.getJSONArray("data");

        for(int i = 0; i < data.length(); i++){
            JSONObject getData = data.getJSONObject(i);
            String title = getData.getString("name");
            placeItem = new PlaceItem(title);
            placeItems.add(placeItem);
        }
    } catch (JSONException e) {
        e.printStackTrace();
    }
}

3 个答案:

答案 0 :(得分:2)

除了@M G指出一般会弄乱行为的问题。 你还有其他2个主要缺陷,其中1)主要影响你。

1)你做了所有Json解析+将数据移动到你的POJO(PlaceItem [])onPostExecute。这是错的!

  • 这在计算上会非常沉重
  • 这样你可以创建2个很多GC的中间对象

我建议将这些内容移到后台并使用Gson。

2)您似乎经常进行大量的网络通话。这需要更好地管理从网络流获得的并发请求,网络连接,线程,流和数据阵列。这可能导致大量的GC。

我建议使用为此目的而制作的网络库,例如改装,排球或jus。这些都可以处理在后台直接解析您的POJO网络数据,并最大限度地降低GC和性能。

答案 1 :(得分:1)

您的代码几乎没有问题

searchPlaceByText(getNameFromUser);
adapter.swap(placeItems);

adapter.swap(placeItems);在您启动AsyncTask之后立即开始,但您还没有下载任何内容。这是错的。您应该从此处删除adapter.swap(placeItems);并执行以下操作:

@Override
public void onClick(View v) {
    switch (v.getId()){
        case R.id.btnGetLocations:
            GetUserLocation location = new GetUserLocation();
            location.getLocation(getActivity());
            adapter.swap(placeItems);//also here probably
            break;
        case R.id.btnSearchByText:
            // this is the method loading data with user input
            String getNameFromUser = editName.getText().toString();
            searchPlaceByText(getNameFromUser);
            break;
    }
}
public void searchPlaceByText(final String place) {
        // instantiate the asynctask here
        LocationDetailsByText locationDetailsByText = new LocationDetailsByText(placeItems) {

            @Override
            protected void onPostExecute(String s) {
                super.onPostExecute(s);
                adapter.swap(placeItems);
            }
        };
        locationDetailsByText.execute("http://api.v3.factual.com/t/places-il?q=" + place + "&KEY=AFvDryDJmPkkgXohbpFdqkRQelT9w0HKtyEqXy3G");
 }

接下来就是清除你的清单

items.clear();
items.addAll(places);

这基本上也会删除placeItems中的所有内容,因为您在此课程中设置了this.items = placeItems;。所以在PlacesListAdapter只做

public void swap(ArrayList<PlaceItem> places){
     notifyDataSetChanged();
}

答案 2 :(得分:0)

在您的Asynctask中,在OnPostExcute中,在它结束时通知您的适配器有关数据中的更改,这就是为什么除非再次点击编辑文本,否则无法看到您的数据。

相关问题