自定义适配器的异步行为

时间:2017-01-23 18:30:07

标签: java android android-adapter

我已经在我的Android应用程序中创建了自己的自定义适配器类,我从我的一个活动中调用它。我正在从适配器类添加一些元素到视图,我需要从我的活动类访问这些变量。

现在,理想情况下我希望它填充视图然后在我的activity类中执行更多代码,但是适配器类需要一些时间来填充视图,同时我的activity类中的其他代码正在执行尚未添加此类元素。 我该如何处理这种情况?我来自js背景。我们在java中有类似promises的内容吗?

根据答案,我将我的代码更改为:

public class HomeActivity extends Activity {

    GridView grid;
    String text[] = {"Calendar","Uber","Weather","News","Youtube","Clock","Email","Maps","Twitter","Facebook"};
    String list_app_name[] = {"calendar","uber","weather","news","youtube","clock","email","maps","twitter","facebook"};
    String id_button[] = {"button_calendar","button_uber","button_weather","button_news","button_youtube","button_clock","button_email","button_maps","button_twitter","button_facebook"};
    int image[] = {R.drawable.social_icons1,R.drawable.social_icons2,R.drawable.social_icons3,R.drawable.social_icons4,
            R.drawable.social_icons5,R.drawable.social_icons6, R.drawable.social_icons7,R.drawable.social_icons8,
            R.drawable.social_icons9,R.drawable.social_icons10};
    private DrawerLayout mDrawerLayout;
    private ActionBarDrawerToggle mDrawerToggle;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        setContentView(R.layout.activity_home);

        //setting up the adapter for gridView
        grid = (GridView)findViewById(R.id.simpleGrid);
        ImageAdapter ia = new ImageAdapter(this,image,text,id_button);
        grid.setAdapter(ia);

        ia.notifyDataSetChanged();

        try {
            initStateOfApps();
        } catch (JSONException e) {
            e.printStackTrace();
        }

    }

    public void initStateOfApps() throws JSONException {
        Log.d("here","here");
        ArrayList<String> list = getEnabledApps();
        Log.d("apps",list.toString());
        for(int i=0;i<list.size();i++) {
            String app_name = list.get(i);

            ToggleButton button=null;
            if(app_name.equals("calendar")) {
                button = (ToggleButton)findViewById(R.id.button_calendar);
                button.setChecked(true);
            } 

        }
    }
}

所以发生的事情是我正在创建一些切换按钮,这些按钮会在我编写的ImageAdapter类中填充。 调用ImageAdapter后,我调用适配器上的notifydatasetchanged()以更新视图。 我在适配器中做的是给每个切换按钮一些我在res/values/ids.xml中写的自定义ID。 在每个切换按钮上使用setId后,我尝试在我的activity class中使用该ID,但它在我nullPointerException中的initStateOfApps()我试图改变状态按钮。

因此,即使使用notifyDataSetChanged后,它仍然表现相同。

ImageAdapter.java

public class ImageAdapter extends BaseAdapter {
    private Context context;
    private final int item_image[];
    private final String item_text[];
    private final String button_id[];
    public ImageAdapter(Context context, int item_image[], String[] item_text,String[] button) {
        this.context = context;
        this.item_image = item_image;
        this.item_text = item_text;
        this.button_id = button;
    }

    public View getView(int position, View convertView, ViewGroup parent) {

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

        View gridView;

        if (convertView == null) {
            gridView = new View(context);

            // get layout from custom_gridview.xml
            gridView = inflater.inflate(R.layout.item, null);

            // set value into imageview
            final ImageView image = (ImageView) gridView.findViewById(R.id.item_image);
            image.setImageResource(item_image[position]);

            // set value into textview
            TextView text = (TextView) gridView.findViewById(R.id.item_text);
            text.setText(item_text[position]);

            final ToggleButton button_ = (ToggleButton) gridView.findViewById(R.id.item_button);

            if(position==0) {
                button_.setId(R.id.button_calendar);
                image.setId(R.id.image_calendar);
            } 


            button_.setOnCheckedChangeListener( new CompoundButton.OnCheckedChangeListener()
            {
                @Override
                public void onCheckedChanged(CompoundButton toggleButton, boolean isChecked)
                {

                    if(context.getResources().getResourceEntryName(toggleButton.getId()).equals("button_calendar")) {
                        if(isChecked) {
                            try {
                                setStateOfApp("calendar","true");
                            } catch (JSONException e) {
                                e.printStackTrace();
                            }
                            Intent intent = new Intent(context, GoogleApp.class);
                            ((Activity) context).startActivityForResult(intent,10);

                        } else {
                            try {
                                setStateOfApp("calendar","false");
                            } catch (JSONException e) {
                                e.printStackTrace();
                            }
                        }
                    } 
                }
            }
        } else {
            gridView = (View) convertView;
        }

        return gridView;
    }
}

4 个答案:

答案 0 :(得分:1)

您正在尝试访问不属于View内容视图的Activity。因此,您无法直接访问该视图。

button = (ToggleButton)findViewById(R.id.button_calendar); // will return null

此ToggleButton将为null,因为findViewById将无法在当前内容视图中找到ToggleButton,因为该视图存在于适配器中而不是内容视图中。

你得到nullpointerException,因为你试图在null视图上访问属性。

button.setChecked(true); // This button is null

答案 1 :(得分:0)

在java中,我们有<Future>,但我不认为这是您正在寻找的内容。

适配器(扩展BaseAdaper)行为允许您创建适配器,即使在第二时刻,也可以通过getAdapter()。setData()或您选择添加的任何方法来更改基础数据。

从这个角度来看,适配器是一个&#34;愚蠢的&#34;作为A View容器的组件,你应该在别处检索数据(CursorAdapter是不同的)。

因此,在您的Activity中,使用所需数据填充适配器,完成后,调用adapter.notifyDatasetChanged()。这将通知适配器其自己的数据已更改,并且必须刷新视图

答案 2 :(得分:0)

是的,理想情况下,适配器的数量应来自外部。适配器应该只是接收数据列表并将数据映射到视图。例如,Activity中的某些方法或任务可以生成一个数据列表(可能是异步的......因为你提到它)然后传递给适配器然后你可以根据需要通知notifyDataSetChanged()。

我看不到您的代码,但如果由于某种原因确实需要从适配器内部填充数据,您可以使用事件总线并在Activity中订阅它。我建议使用第一个选项,但如果您选择使用事件总线,这里有一些链接:

https://github.com/greenrobot/EventBus

http://square.github.io/otto/

答案 3 :(得分:0)

根据我对你的问题的理解 您没有正确管理活动中的适配器数据。 如果任何数据或代码与适配器数据或值相互关联 然后,您可以在检索值或数据并更新活动中的视图后启动这些代码。 请注意,在适配器中使用Viewholders可以避免在listviews中缓慢填充和滚动。 观众可以顺利完成您的流程。

我个人建议你这样做 请使用Recyclerview和RecyclerViewAdapter。 很多Android开发人员都在使用它。

如果你在适配器中有后台任务,你可以选择使用RX Java或EventBus

如果您提供代码 我们建议确切的解决方案更好