用 CursorAdapter 中的新数据更新相同的 ListView

Posted

技术标签:

【中文标题】用 CursorAdapter 中的新数据更新相同的 ListView【英文标题】:Update same ListView with new data in CursorAdapter 【发布时间】:2017-06-29 00:55:38 【问题描述】:

我真的被困住了,不知道该怎么办。我研究了startActivityForResult 和内容提供者,但我不知道如何为这个应用程序实现它们中的任何一个。

我没有看到如何从数据库中获取数据并使用相同的listview 更新displayBottomList,因此我不必将用户重定向到新的布局/活动。不确定我是否可以调用一个新查询并将其设置为不同的光标并在它们之间切换。我见过swapCursor,但是在使用同一个适配器时它是如何工作的?

我有一个ListView,当用户单击列表中的一行时,我想用来自 Web 服务调用的新数据进行刷新。我正在使用CursorAdapter。我可以正确获取行的onClick 的数据。

我卡住的地方是如何更新 listView 以重新填充来自数据库/响应的新信息,而无需将我发送到另一个活动。我希望用户留在同一屏幕上,但只需使用新数据更新 listView

onClick 在适配器中,但ListView 正在MainActivity 中创建时,不确定如何让适配器通知适配器更新和填充新的ListView

BottomListView 的适配器,我想在单击一行时更新。

public class BottomListViewAdapter extends CursorAdapter 

    private String mEmployeeNumber;
    private EmployeeDBHandler dbHandler;

    public BottomListViewAdapter(Context context, Cursor cursor) 
        super(context, cursor, 0);
    

    @Override
    public View newView(Context context, Cursor cursor, ViewGroup parent) 
        return LayoutInflater.from(context).inflate(R.layout.contact_cardview_layout, parent, false);
    

    @Override
    public void bindView(View view, final Context context, final Cursor cursor) 
        dbHandler = new EmployeeDBHandler(context);
        ViewHolder holder;
        holder = new ViewHolder();
        holder.tvFirstName = (TextView) view.findViewById(R.id.personFirstName);
        holder.tvLastName = (TextView) view.findViewById(R.id.personLastName);
        holder.tvTitle = (TextView) view.findViewById(R.id.personTitle);
        holder.mPeepPic = (ImageView) view.findViewById(R.id.person_photo);
        holder.mDetailsButton = (ImageButton) view.findViewById(R.id.fullDetailButton);
        holder.mCardView = (CardView) view.findViewById(R.id.home_screen_cardView);

        String mFirstName = cursor.getString(cursor.getColumnIndexOrThrow("First_name"));
        String mLastName = cursor.getString(cursor.getColumnIndexOrThrow("Last_name"));
        String mTitle = cursor.getString(cursor.getColumnIndexOrThrow("Payroll_title"));
        String mThumbnail = cursor.getString(cursor.getColumnIndexOrThrow("ThumbnailData"));

        holder.tvFirstName.setText(mFirstName);
        holder.tvLastName.setText(mLastName);
        holder.tvTitle.setText(mTitle);

        if (mThumbnail != null) 
            byte[] imageAsBytes = Base64.decode(mThumbnail.getBytes(), Base64.DEFAULT);
            Bitmap parsedImage = BitmapFactory.decodeByteArray(imageAsBytes, 0, imageAsBytes.length);
            holder.mPeepPic.setImageBitmap(parsedImage);
         else 
            holder.mPeepPic.setImageResource(R.drawable.img_place_holder_adapter);
        

        final int position = cursor.getPosition();

        holder.mDetailsButton.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View view) 
                cursor.moveToPosition(position);
                String mEmployeeNumber = cursor.getString(1);
                String mEmail = cursor.getString(8);
                String mFirstName = cursor.getString(2);
                String mLastName = cursor.getString(3);
                String mPhoneMobile = cursor.getString(4);
                String mPhoneOffice = cursor.getString(5);
                String mCostCenter = cursor.getString(10);
                String mHasDirectReports = cursor.getString(7);
                String mTitle = cursor.getString(6);
                String mPic = cursor.getString(9);
                Intent mIntent = new Intent(context, EmployeeFullInfo.class);
                mIntent.putExtra("Employee_number", mEmployeeNumber);
                mIntent.putExtra("Email", mEmail);
                mIntent.putExtra("First_name", mFirstName);
                mIntent.putExtra("Last_name", mLastName);
                mIntent.putExtra("Phone_mobile", mPhoneMobile);
                mIntent.putExtra("Phone_office", mPhoneOffice);
                mIntent.putExtra("Cost_center_id", mCostCenter);
                mIntent.putExtra("Has_direct_reports", mHasDirectReports);
                mIntent.putExtra("Payroll_title", mTitle);
                mIntent.putExtra("ThumbnailData", mPic);
                mIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                view.getContext().startActivity(mIntent);
            
        );

        holder.mCardView.setOnClickListener(new View.OnClickListener() 
            @Override
            public void onClick(View v) 
                cursor.moveToPosition(position);
                mEmployeeNumber = cursor.getString(1);
                Toast.makeText(context, mEmployeeNumber, Toast.LENGTH_SHORT).show();
                callNewDirectReport();
                notifyDataSetChanged();

            
        );
    

    public static class ViewHolder 
        TextView tvFirstName;
        TextView tvLastName;
        TextView tvTitle;
        ImageView mPeepPic;
        ImageButton mDetailsButton;
        CardView mCardView;
    

    private void callNewDirectReport() 
        String mDirectReportUrl = "mURL";

        HttpUrl.Builder urlBuilder = HttpUrl.parse(mDirectReportUrl).newBuilder();
        urlBuilder.addQueryParameter("manager_employee_number", mEmployeeNumber);
        String url = urlBuilder.build().toString();


        OkHttpClient client = getUnsafeOkHttpClient();
        Request request = new Request.Builder()
                .url(url)
                .build();

        client.newCall(request).enqueue(new Callback() 
            @Override
            public void onFailure(Call call, IOException e) 
                e.printStackTrace();
            

            @Override
            public void onResponse(Call call, Response response) throws IOException 
                    final String responseData = response.body().string();
                    final InputStream stream = new ByteArrayInputStream(responseData.getBytes());
                    final XMLPullParserHandler parserHandler = new XMLPullParserHandler();
                    final ArrayList<Employee> employees = (ArrayList<Employee>) parserHandler.parse(stream);

                    for (Employee e : employees) 
                        dbHandler.addEmployee(e);
                    
            
        );
    

    @Override
    public void notifyDataSetChanged() 
        super.notifyDataSetChanged();
    

调用适配器的我的 MainActivity

public class MainActivity extends AppCompatActivity 

    private ProgressBar mProgressBar;
    private BottomListViewAdapter mBottomAdapter;
    private View mDividerView;
    EmployeeDBHandler dbHandler;
    private int mStartingEmployeeID = mStartingID;
    private String table = "employees";
    private static final int LOADER_INTEGER = 1;
    private Cursor mBottomCursor, mTopCursor;

    @Override
    protected void onCreate(Bundle savedInstanceState) 
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mProgressBar = (ProgressBar) findViewById(R.id.progressBar);
        mDividerView = findViewById(R.id.divider);
        dbHandler = new EmployeeDBHandler(getApplicationContext());
        mProgressBar.setVisibility(View.VISIBLE);
        mDividerView.setVisibility(View.GONE);
        getXMLData();

        //GUI for seeing android SQLite Database in Chrome Dev Tools
        Stetho.InitializerBuilder inBuilder = Stetho.newInitializerBuilder(this);
        inBuilder.enableWebKitInspector(Stetho.defaultInspectorModulesProvider(this));
        Stetho.Initializer in = inBuilder.build();
        Stetho.initialize(in);
    

    public void getXMLData() 
        OkHttpClient client = getUnsafeOkHttpClient();
        Request request = new Request.Builder()
                .url(getString(R.string.API_FULL_URL))
                .build();
        client.newCall(request).enqueue(new Callback() 
            @Override
            public void onFailure(Call call, IOException e) 
                e.printStackTrace();
            

            @Override
            public void onResponse(Call call, final Response response) throws IOException 
                final String responseData = response.body().string();
                final InputStream stream = new ByteArrayInputStream(responseData.getBytes());
                final XMLPullParserHandler parserHandler = new XMLPullParserHandler();
                final ArrayList<Employee> employees = (ArrayList<Employee>) parserHandler.parse(stream);

                for (Employee e : employees) 
                    dbHandler.addEmployee(e);

                

                runOnUiThread(new Runnable() 
                    @Override
                    public void run() 
                        mProgressBar.setVisibility(View.GONE);
                        mDividerView.setVisibility(View.VISIBLE);
                        displayTopList();
                        displayBottomList();
                    
                );
            
        );
    

    public void displayTopList() 
        SQLiteDatabase db = dbHandler.getWritableDatabase();
        mTopCursor = db.rawQuery("SELECT * FROM " + table + " WHERE " + "Employee_number" + "=" + mStartingEmployeeID, null);
        ListView mTopListView = (ListView) findViewById(R.id.mTopList);
        TopListCursorAdapter topAdapter = new TopListCursorAdapter(this, mTopCursor);
        mTopListView.setAdapter(topAdapter);
    

    public void displayBottomList() 
        SQLiteDatabase db = dbHandler.getWritableDatabase();
        mBottomCursor = db.rawQuery("SELECT * FROM " + table + " WHERE " +
                "Employee_number" + "!=" + mStartingEmployeeID + " AND " +
                "Manager_employee_number" + "=" + mStartingEmployeeID + " ORDER BY " +
                "Last_name" + " ASC", null);

        ListView mBottomListView = (ListView) findViewById(R.id.mDirectReportList);
        mBottomAdapter = new BottomListViewAdapter(this, mBottomCursor);
        mBottomListView.setAdapter(mBottomAdapter);
        mBottomAdapter.notifyDataSetChanged();

    

【问题讨论】:

使用 volley library..使用新信息重新填充列表视图的最佳方法之一..! 你有任何链接可以显示这种情况吗?不想只是切换我的网络呼叫,然后花几天时间试图弄清楚这是如何完成的。 androidhive.info/2014/05/android-working-with-volley-library-1 仍然困惑于如何改变我的网络调用方式将帮助我更新 CursorAdapter 中的 listview onClick 事件更新相同的列表。 developer.android.com/training/volley/index.html 这里是你的困惑的链接......对不起......! 【参考方案1】:

现在,callNewDirectReport() 中的代码发出 API 请求并将结果存储在数据库中。这不会更新适配器以显示新项目,而是您需要重新查询数据库并获取更新的光标。以下是您可以如何做到的示例:

public class BottomListViewAdapter extends CursorAdapter 

    private String mEmployeeNumber;
    private EmployeeDBHandler dbHandler;
    private Activity activityRef;   

    public BottomListViewAdapter(Context context, Cursor cursor) 
        super(context, cursor, 0);
        // keep a reference to the activity
        activityRef = (Activity) context;
    
        
    //...

    private void callNewDirectReport() 
        //...
        client.newCall(request).enqueue(new Callback() 
            @Override
            public void onFailure(Call call, IOException e) 
                e.printStackTrace();
            

            @Override
            public void onResponse(Call call, Response response) throws IOException 
                    final String responseData = response.body().string();
                    final InputStream stream = new ByteArrayInputStream(responseData.getBytes());
                    final XMLPullParserHandler parserHandler = new XMLPullParserHandler();
                    final ArrayList<Employee> employees = (ArrayList<Employee>) parserHandler.parse(stream);

                    for (Employee e : employees) 
                        dbHandler.addEmployee(e);
                    
                    // the new items are in the database so requery the database to get a new fresher Cursor:
                    SQLiteDatabase db = dbHandler.getWritableDatabase();
                    Cursor fresherCursor = db.rawQuery("SELECT * FROM " + table + " WHERE " +
                        "Employee_number" + "!=" + mStartingEmployeeID + " AND " +
                        "Manager_employee_number" + "=" + mStartingEmployeeID + " ORDER BY " +
                        "Last_name" + " ASC", null);
                    //change the adapter's Cursor
                    activityRef.runOnUiThread(new Runnable() 
                        public void run() 
                            swapCursor(freshedCursor);
                        
                    );
            
        );
    

【讨论】:

【参考方案2】:

您可以使用 startActivityForResult 接收来自活动的回调,这里有一个说明如何使用它的教程:https://developer.android.com/training/basics/intents/result.html

当你在onActivityResult中收到回调时,你可以更新你的数据并调用notifyDatasetChanged。

您不能从另一个活动中调用代码,因为活动是由 android 处理的。 Android 可能会终止您尝试调用的 Activity,并会在必要时重新创建它。

【讨论】:

所以我必须将 mCardView.setOnClickListener 发送到一个新活动,创建一个列表视图然后将其传递给 MainActivity? 不,除了调用startActivity,你调用startActivityForResult传递和ID。您调用 startActivityForResult 的活动将在 onActivityResult 中收到返回。阅读我在回复中附加的链接。 对如何在我的 CursorAdapter 中的 OnClickListener 上传递 startActivityForResult 以更新 MainActivity 中的 listView 感到困惑。似乎我需要在 mCardView.setOnClickListener 中获取响应,使用 startActivityforResult 转到一个新活动,然后在该活动中执行另一个活动以传递回 mainAcitivty 以使用来自 onclick 的新数据更新列表视图?

以上是关于用 CursorAdapter 中的新数据更新相同的 ListView的主要内容,如果未能解决你的问题,请参考以下文章

VFP CursorAdapter 起步二(作者:Dung Hennig 译者:fbilo)

Web 服务同步后 ListView 未更新

如何在pyspark中使用具有相同客户ID的新数据框的值更新一行旧数据框

ListView 上来自 SQLite 的大数据

使用自定义 CursorAdapter 时 ListView 未显示在活动中

在 cursoradapter 中从 ListView 中删除项目