Android的装载机,要走的路? [英] Android loaders, the way to go?

查看:108
本文介绍了Android的装载机,要走的路?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我用的建筑列表中使用的适配器机器人。如果我需要一些长到获取数据,我用一个AsyncTask的,或者一个简单的可运行的,及时更新的数据结构上的适配器依赖,并调用notifyDataChanged适配器上。

虽然它不是简单的,我终于发现这是一个简单的模型,它允许逻辑presentation良好的分离(在AsyncTask的,更新的数据结构)和视图(适配器作为一个视图工厂,大多数情况下)。

不过,我最近读到的蜂窝介绍并包含在向后兼容支持库装载机,我想他们找到了引入大量的复杂性。他们是难以处理,并通过加载程序经理加入某种魔力这整个过程中,添加了大量的code和不降低类或合作项目的数量,但我​​可能是错的,想听到一些在装载机好点。

  • 什么是在code,清晰度和精力线路方面装载机他们的优势?
  • 什么是装载机的优势,他们在角色分离方面的数据加载过程中,或者更广泛地说,在设计方面?
  • 难道他们要走的路,我应该取代我的所有列表数据加载,通过装载机实施呢?

好吧,这是一个developpers论坛,所以这里就是一个例子。请,使之更好地与装载机:

 包com.sof.test.loader;

进口的java.util.ArrayList;
进口的java.util.List;

进口android.app.ListActivity;
进口android.os.AsyncTask;
进口android.os.Bundle;
进口android.view.View;
进口android.view.ViewGroup;
进口android.view.ViewGroup.LayoutParams;
进口android.widget.ArrayAdapter;
进口android.widget.TextView;

/ **活动。 * /
公共类LoaderTestActivity扩展ListActivity {

    私人DataSourceOrDomainModel dataSourceOrDomainModel =新DataSourceOrDomainModel();
    私人列表<人> listPerson;
    私人PersonListAdapter personListAdapter;
    私人TextView的emptyView;

    / **第一次创建活动时调用。 * /
    @覆盖
    公共无效的onCreate(包savedInstanceState){
        super.onCreate(savedInstanceState);
        listPerson =新的ArrayList<人>();
        personListAdapter =新PersonListAdapter(listPerson);
        setListAdapter(personListAdapter);
        setUpEmptyView();
        新PersonLoaderThread()执行()。
    }

    公共无效setUpEmptyView(){
        emptyView =新的TextView(本);
        emptyView.setLayoutParams(新的LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT));
        emptyView.setVisibility(View.GONE);
         ((的ViewGroup)getListView()的getParent())addView(emptyView)。
        getListView()setEmptyView(emptyView)。
    }

    / **模拟一个长期的任务来获取数据。 * /
    私有类PersonLoaderThread扩展的AsyncTask<太虚,整数,列表<人>> {
        @覆盖
        受保护的名单,其中,人物> doInBackground(空... PARAMS){
            返回dataSourceOrDomainModel.getListPerson(新ProgressHandler());
        }

        @覆盖
        保护无效onProgressUpdate(整数...值){
            emptyView.setText(加载数据:+将String.valueOf(值[0])+%);
        }

        @覆盖
        保护无效onPostExecute(名单<人>的结果){
            listPerson.clear();
            listPerson.addAll(结果);
            personListAdapter.notifyDataSetChanged();
        }

        私有类ProgressHandler实现ProgressListener {

            @覆盖
            公共无效personLoaded(诠释计数,诠释总计){
                publishProgress(100 *数/总);
            }

        }
    }

    / **清单项目视图工厂:适配器。 * /
    私有类PersonListAdapter扩展ArrayAdapter<人> {

        公共PersonListAdapter(名单<人> listPerson){
            超级(LoaderTestActivity.this,0,listPerson);
        }

        @覆盖
        公共查看getView(INT位置,查看convertView,ViewGroup中父){
            如果(convertView == NULL){
                convertView =新PersonView(的getContext());
            }
            PersonView personView =(PersonView)convertView;
            personView.setPerson((人)的getItem(位置));
            返回personView;
        }
    }
}
 

有关进展情况的小幅回调接口

 包com.sof.test.loader;

/ **在数据加载进度回调处理程序。 * /
公共接口ProgressListener {
    公共无效personLoaded(诠释计数,诠释总计);
}
 

一个列表项部件

 包com.sof.test.loader;

进口com.sof.test.loader.R;
进口android.content.Context;
进口android.view.LayoutInflater;
进口android.widget.LinearLayout;
进口android.widget.TextView;

/ **列表项目视图,显示一个人* /
公共类PersonView扩展的LinearLayout {

    私人TextView的personNameView;
    私人TextView的personFirstNameView;

    公共PersonView(上下文的背景下){
        超(上下文);
        LayoutInflater充气=(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        inflater.inflate(R.layout.person_view,这一点);
        personNameView =(TextView中)findViewById(R.id.person_name);
        personFirstNameView =(TextView中)findViewById(R.id.person_firstname);
    }

    公共无效setPerson(人人){
      personNameView.setText(person.getName());
      personFirstNameView.setText(person.getFirstName());
    }
}
 

这是XML:RES / person_view.xml

 < XML版本=1.0编码=UTF-8&GT?;
< RelativeLayout的的xmlns:机器人=htt​​p://schemas.android.com/apk/res/android
    机器人:ID =@ + ID / person_view
    机器人:layout_width =FILL_PARENT
    机器人:layout_height =WRAP_CONTENT>

    <的TextView
        机器人:ID =@ + ID / PERSON_NAME
        机器人:layout_width =WRAP_CONTENT
        机器人:layout_height =WRAP_CONTENT
        机器人:layout_alignParentLeft =真/>

    <的TextView
        机器人:ID =@ + ID / person_firstname
        机器人:layout_width =WRAP_CONTENT
        机器人:layout_height =WRAP_CONTENT
        机器人:layout_toRightOf =@ ID / PERSON_NAME/>

< / RelativeLayout的>
 

数据源或模型,提供数据(慢)

 包com.sof.test.loader;

进口的java.util.ArrayList;
进口的java.util.List;

/ **数据的来源,可以是数据库,Web服务或模型。 * /
公共类DataSourceOrDomainModel {
    私有静态最终诠释PERSON_COUNT = 100;

    公开名单<人> getListPerson(ProgressListener监听器){
        名单<人> listPerson =新的ArrayList<人>();
        的for(int i = 0; I< PERSON_COUNT;我++){
            listPerson.add(新的人(人,+ i)段);
            //孩子,从来没有这样做,在家里!
            暂停();
            如果(听众!= NULL){
                listener.personLoaded(ⅰ,PERSON_COUNT);
            }//如果
        }
        返回listPerson;
    } //满足

    私人无效暂停(){
        尝试 {
            视频下载(100);
        }赶上(InterruptedException异常E){
            e.printStackTrace();
        }
    }
}
 

该POJO重新presenting人:

 包com.sof.test.loader;

/ **甲简单的POJO要显示在列表中,可以manipualted作为域对象。 * /
公共类Person {
    私人字符串名称;
    私人字符串的firstName;

    公众人物(字符串名称,字符串的firstName){
        this.name =名称;
        this.firstName =名字;
    }

    公共字符串的getName(){
        返回名称;
    }
    公共无效setname可以(字符串名称){
        this.name =名称;
    }
    公共字符串的getFirstName(){
        返回的firstName;
    }
    公共无效setFirstName(字符串的firstName){
        this.firstName =名字;
    }
}//类
 

解决方案

有一个问题你code具有装载机旨在解决的是,如果你的活动重新启动会发生什么(比如由于设备旋转或配置的变化),而您的异步工作仍在进行中?你的情况你重启活动将启动任务的第二个实例,扔掉从第一个结果。当第一个完成就可以结束与崩溃由于这样的事实的异步任务都有一个参考是什么现在完成的活性。

和是用装载机往往使更多的/更复杂code,特别是如果你不能使用所提供的装载机之一。

I am used to building lists in android using adapters. If I need some long-to-get data, I use an asynctask, or a simple runnable, to update the data structure on which the adapter rely, and call notifyDataChanged on the adapter.

Although it is not straightforward, I finally find this is a simple model and it allows a good separation of logic presentation (in the asynctask, update a data structure) and the view (an adapter acting as a view factory, mostly).

Nevertheless, I read recently about loaders introduced in HoneyComb and included in the backward compatibility support-library, I tried them and find the introduce a lot of complexity. They are difficult to handle and add some kind of magic to this whole process through loader managers, add a lot of code and don't decrease the number of classes or collaborating items but I may be wrong and would like to hear some good points on loaders.

  • What are they advantages of loaders in terms of lines of code, clarity and effort ?
  • What are they advantages of loaders in terms of role separation during data loading, or more broadly, in terms of design ?
  • Are they the way to go, should I replace all my list data loading to implement them through loaders ?

Ok, this is a developpers' forum, so here is an example. Please, make it better with loaders :

package com.sof.test.loader;

import java.util.ArrayList;
import java.util.List;

import android.app.ListActivity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewGroup.LayoutParams;
import android.widget.ArrayAdapter;
import android.widget.TextView;

/** The activity. */
public class LoaderTestActivity extends ListActivity {

    private DataSourceOrDomainModel dataSourceOrDomainModel = new DataSourceOrDomainModel();
    private List<Person> listPerson;
    private PersonListAdapter personListAdapter;
    private TextView emptyView;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        listPerson = new ArrayList<Person>();
        personListAdapter = new PersonListAdapter( listPerson );
        setListAdapter( personListAdapter );
        setUpEmptyView();
        new PersonLoaderThread().execute();
    }

    public void setUpEmptyView() {
        emptyView = new TextView( this );
        emptyView.setLayoutParams( new LayoutParams( LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT ) );
        emptyView.setVisibility(View.GONE);
         ((ViewGroup)getListView().getParent()).addView(emptyView);
        getListView().setEmptyView(emptyView);
    }

    /** Simulate a long task to get data. */
    private class PersonLoaderThread extends AsyncTask<Void, Integer, List<Person>> {
        @Override
        protected List<Person> doInBackground(Void... params) {
            return dataSourceOrDomainModel.getListPerson( new ProgressHandler());
        }

        @Override
        protected void onProgressUpdate(Integer... values) {
            emptyView.setText( "Loading data :" + String.valueOf( values[ 0 ] ) +" %" );
        }

        @Override
        protected void onPostExecute(List<Person> result) {
            listPerson.clear();
            listPerson.addAll( result );
            personListAdapter.notifyDataSetChanged();
        }

        private class ProgressHandler implements ProgressListener {

            @Override
            public void personLoaded(int count, int total) {
                publishProgress( 100*count / total );
            }

        }
    }

    /** List item view factory : the adapter. */
    private class PersonListAdapter extends ArrayAdapter<Person> {

        public PersonListAdapter( List<Person> listPerson ) {
            super(LoaderTestActivity.this, 0, listPerson );
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            if( convertView == null ) {
                convertView = new PersonView( getContext() );
            }
            PersonView personView = (PersonView) convertView;
            personView.setPerson( (Person) getItem(position) );
            return personView;
        }
    }
}

A small callback interface for progress

package com.sof.test.loader;

/** Callback handler during data load progress. */
public interface ProgressListener {
    public void personLoaded(int count, int total );
}

A list item widget

package com.sof.test.loader;

import com.sof.test.loader.R;
import android.content.Context;
import android.view.LayoutInflater;
import android.widget.LinearLayout;
import android.widget.TextView;

/** List Item View, display a person */
public class PersonView extends LinearLayout {

    private TextView personNameView;
    private TextView personFirstNameView;

    public PersonView(Context context) {
        super(context);
        LayoutInflater inflater= (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
        inflater.inflate( R.layout.person_view,this );
        personNameView = (TextView) findViewById( R.id.person_name );
        personFirstNameView = (TextView) findViewById( R.id.person_firstname );
    }

    public void setPerson( Person person ) {
      personNameView.setText( person.getName() );   
      personFirstNameView.setText( person.getFirstName() );
    }
}

It's xml : res/person_view.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/person_view"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content" >

    <TextView
        android:id="@+id/person_name"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true" />

    <TextView
        android:id="@+id/person_firstname"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_toRightOf="@id/person_name" />

</RelativeLayout>

The data source or model, providing data (slowly)

package com.sof.test.loader;

import java.util.ArrayList;
import java.util.List;

/** A source of data, can be a database, a WEB service or a model. */
public class DataSourceOrDomainModel {
    private static final int PERSON_COUNT = 100;

    public List<Person> getListPerson( ProgressListener listener ) {
        List<Person> listPerson = new ArrayList<Person>();
        for( int i=0; i < PERSON_COUNT ; i ++ ) {
            listPerson.add( new Person( "person", "" + i ) );
            //kids, never do that at home !
            pause();
            if( listener != null ) {
                listener.personLoaded(i,PERSON_COUNT);
            }//if
        }
        return listPerson;
    }//met

    private void pause() {
        try {
            Thread.sleep( 100 );
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

The POJO representing a person :

package com.sof.test.loader;

/** A simple POJO to be displayed in a list, can be manipualted as a domain object. */
public class Person {
    private String name;
    private String firstName;

    public Person(String name, String firstName) {
        this.name = name;
        this.firstName = firstName;
    }

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getFirstName() {
        return firstName;
    }
    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }
}//class

解决方案

One problem your code has which loaders aim to fix is what happens if your activity is restarted (say due to device rotation or config change) while your async task is still in progress? in your case your restarted activity will start a 2nd instance of the task and throw away the results from the first one. When the first one completes you can end up with crashes due to the fact your async task has a reference is what is now a finished activity.

And yes using loaders often makes for more/more complex code, particularly if you can't use one of the provided loaders.

这篇关于Android的装载机,要走的路?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆