加速大量以编程方式创建的按钮显示

时间:2017-11-03 16:28:10

标签: java android multithreading programmatically-created

我有一个活动,它从List中生成一个可滚动列表(让我们说一列)编程创建的按钮,这是一个sqlite表读取的结果,我的问题是随着List的增长(和所以按钮的数量)屏幕的初始绘画变得很慢(此刻需要3秒钟,有50个按钮可以绘制)所以我​​正在寻找解决方案。

起初我想过使用一个线程(runnable,handler或者其他什么是最好的),让我们说在For中创建一个新的线程迭代列表但是它没有工作(或者在至少我无法让它发挥作用)所以我的问题是下一个:

从列表<>开始这是创建大量可滚动按钮的最合适的方式,因此用户在访问屏幕时不会有这样的延迟。

Paginating可能是一种选择,但我想首先了解其他可能性并将其留作最后资源。

谢谢,下面是我的代码。

public static void createButtons(LinearLayout llContainer,
                                     List<TestType> TestTypes, List<Test> Tests,
                                     int buttonFontSize) {

        Context oContext = llContainer.getContext();
        String strTheme = TMAppearance.getThemeFromPreferences(oContext);
        testMe = ((ApplicationConfiguration)oContext.getApplicationContext());
        int callerActivity = TestTypes!=null ? 2 : 1;

        if (TestTypes!=null || Tests!=null) {
            int lCols = strTheme.equals(testMe.theme_vivid) ? 1 : 2;

            //int sourceElementIndex = 0;
            int originListSize = calculateOriginalListSize(callerActivity, TestTypes, Tests);
            int lRows = (int) Math.ceil((double)originListSize/lCols);

            List<String> aStartColors = TMUtils_ThemeVivid.generateStartColorArray(lRows, oContext);
            List<String> aEndColors = TMUtils_ThemeVivid.generateEndColorArray(lRows, oContext);

            for (i = 0; i < lRows; i++) {

                LinearLayout outerButtonLayout = generateOuterButtonLayout(oContext);

                for (j = 0; j < lCols; j++) {

                    final Thread r = new Thread() {
                        public void run() {
                            LinearLayout innerButtonLayout = generateInnerButtonLayout(oContext);
                            outerButtonLayout.addView(innerButtonLayout, j);

                            if (sourceElementIndex<originListSize){
                                final TMButton oButton = new TMButton(oContext);

                                if (callerActivity==1) { //testMenu
                                    setTestMenuButtonSettings(oButton, sourceElementIndex, Tests);
                                } else {
                                    if (callerActivity==2) { //testTypeMenu
                                        setTestTypeMenuButtonSettings(oButton, sourceElementIndex, TestTypes);
                                    }
                                }

                                if (strTheme.equals(testMe.theme_vivid)){
                                    oButton.fontSize = buttonFontSize;
                                    oButton.gradientStartColor = aStartColors.get(i);
                                    oButton.gradientEndColor = aEndColors.get(i);
                                }else{
                                    if (strTheme.equals(testMe.theme_purple)){
                                        oButton.gradientStartColor = testMe.btnStartColor_purple;
                                        oButton.gradientEndColor = testMe.btnEndColor_purple;
                                    }
                                }

                                configureButton(oButton, callerActivity);

                                oButton.setOnTouchListener(new OnTouchListener() {
                                    @Override
                                    public boolean onTouch(View v, MotionEvent event) {

                                        Context oContext = v.getContext();
                                        TMButton oButton = (TMButton) v;

                                        int callerActivity = Integer.valueOf(v.getTag().toString().split("@")[0]);
                                        String sourceId = String.valueOf(v.getTag().toString().split("@")[1]);

                                        if(event.getAction() == MotionEvent.ACTION_DOWN) { //pressed
                                            setButtonPressed(oButton);
                                            TMSound.playButtonSound(oContext);
                                        } else if (event.getAction() == MotionEvent.ACTION_UP) { //released
                                            setButtonReleased(oButton);
                                            startTargetActivity(callerActivity, sourceId, oContext);
                                        }

                                        return true;
                                    }
                                });
                                TMAppearance.doButtonAnimation(oContext, oButton, i);
                                innerButtonLayout.addView(oButton);
                                sourceElementIndex++;
                            }
                        }
                    };
                    r.run();
                }
                llContainer.addView(outerButtonLayout);
            }
        }
    }

1 个答案:

答案 0 :(得分:0)

0X0nosugar 是正确的。 RecycleView将提供更好的性能,但许多初学者在实现它时遇到更多困难,只有50个按钮的性能应该不是真正的问题。虽然我通常喜欢遵守“使用最佳可用解决方案”这一规则,但我认为学习如何实施ListView仍然是合适的。所以...

您需要创建自定义适配器:

public class MyListDataAdapter extends ArrayAdapter<MyListData> {

    private static final String TAG = "MyListDataAdapter";


    public MyListDataAdapter(Context context, ArrayList<MyListData> data) {
        super(context, 0, data);

    }

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

        final MyListData data = getItem(position);

        if(convertView == null){
            convertView = LayoutInflater.from(getContext()).inflate(R.layout.edit_list_item, parent, false);
        }

        // Add a TextView if you need one
        final TextView tvName = (TextView) convertView.findViewById(R.id.tvName);
        Button btnEditTicketHolder = (Button) convertView.findViewById(R.id.btnEdit);
        btnEditTicketHolder.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                long userId = data.getUserId();
                String fName = data.getFirstName();

                Intent intent = new Intent(getContext(), EditActivity.class);
                intent.putExtra("userId", userId);
                intent.putExtra("fName", fName);
                getContext().startActivity(intent);
            }
        });


        String name = data.getFirstName();
        tvName.setText(name);
        return convertView;
    }

}

现在您需要MyListData类来保存数据:

public class MyListData {

    // Add more as you need
    private long userId;
    private String firstName;

    public MyListData(){
    }


    public void setFirstName(String name){ this.firstName = name; }
    public void setUserId(long id){ this.userId = id; }

    public String getFirstName(){ return this.firstName; }
    public long getUserId(){ return this.userId; }
}

您的自定义ListView布局可能如下所示:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
              xmlns:app="http://schemas.android.com/apk/res-auto"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
    >

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_centerVertical="true"
        >

        <TextView
            android:id="@+id/tvName"
            android:text="With Whom"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            />

    </LinearLayout>

    <LinearLayout
        android:orientation="vertical"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentRight="true"
        android:layout_centerVertical="true"
        >

        <Button
            android:id="@+id/btnEdit"
            android:layout_width="wrap_content"
            android:layout_height="40dp"
            android:paddingRight="10dp"
            android:paddingLeft="10dp"
            android:text="Edit"
            android:backgroundTint="@color/colorAccent"
            android:focusable="false"
            />

    </LinearLayout>

</RelativeLayout>

在您的活动中(例如,在onCreate()方法中)ListView,您需要填充ListView的数据。这应该在UI线程上

    ArrayList<MyListData> arrayListData = new ArrayList<MyListData>();
    MyListDataAdapter adapter = new MyListDataAdapter(this, arrayListData);

    for (MyListData g : result) {
        adapter.add(g);
    }
    mLstMy.setAdapter(adapter);

同样在要维护ListView的活动中,如果您需要,请设置一些onClick事件处理程序: (我发现ListView的一个小优势是onClick事件比RecycleView更容易实现

mMyLst = (ListView) findViewById(lstMy);
mMyLst.setOnItemClickListener(new AdapterView.OnItemClickListener() {
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position, long l) {
        MyListData data = (MyListData) parent.getItemAtPosition(position);
        selectedName = data.getName();

        Intent intent = new Intent(ShowListDataActivity.this, MainActivity.class);
        startActivity(intent);
    }
});

mMyLst.setOnItemLongClickListener(new AdapterView.OnItemLongClickListener() {
    @Override
    public boolean onItemLongClick(AdapterView<?> adapterView, View view, int i, long l) {

        MyListData data = (MyistData) adapterView.getItemAtPosition(i);
        selectedName = data.getFirstName();

        selectedTicketPosition = i;
        // removeValue is my own method for removing an entry from the 
        // list MyListData and then call adapter.notifyDataSetChanged();
        removeValue(i);

        return true;
    }
});