java - 服务和 Activity 通信...从服务接收到数据时更新 UI

标签 java android listview android-sqlite

我正在尝试实现一个应用程序,该应用程序每 15 秒更新一次用户位置,将数据存储到数据库并将其显示到我的 Activity 中的 ListView 。 即使 Activity 销毁,位置也应该始终更新,为此我创建了 LocationService 类。

问题是我能够获取更新,也能够存储到数据库中,但我无法在运行时在 ListView 中显示这些更新,这意味着我希望列表应该每 15 秒刷新一次并将其显示给 UI。 此外,当我从数据库获取详细信息时,我无法获取最新的详细信息,而是每次都会获取整个数组列表,这会影响我的 Activity 响应。我希望仅从数据库中获取新添加的数据,以便加载所需的时间更少,但我想每次都显示要列出的所有数据。

我已经实现了一个线程(注释代码),它获取数据并显示到 ListView ,但这不是更新 UI 的正确方法。请建议我一种方法,以便我可以在将新数据添加到数据库时刷新我的列表

这是我的 Activity

    public class MainActivity extends Activity {
    List<MyLocation> locationList = new ArrayList();
    ListView mList;
    LocationAdapter adapter;
    BroadcastReceiver receiver;
    LocationService mService;
    boolean mBound = false;
    private DbHelper dbHelper;
    private Button updateLocation;
        private ServiceConnection mConnection = new ServiceConnection() {

        @Override
        public void onServiceConnected(ComponentName className,
                                       IBinder service) {

            LocationService.LocalBinder binder = (LocationService.LocalBinder) service;
            mService = binder.getService();
            mBound = true;

        }

        @Override
        public void onServiceDisconnected(ComponentName arg0) {
            mBound = false;
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        updateLocation = (Button) findViewById(R.id.update_location);

        mList = (ListView) findViewById(R.id.listView);

        dbHelper = new DbHelper(this);


        updateLocation.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {

                    locationList = mService.displayLocation();
                    adapter = new LocationAdapter(MainActivity.this, locationList);
                    mList.setAdapter(adapter);
            }
        });
    /*
        Thread mThread = new Thread() {

            @Override
            public void run() {
                try {
                    while (!isInterrupted()) {
                        Thread.sleep(500);
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {

                                    locationList = dbHelper.getLocationDetails();
                                    Collections.reverse(locationList);
                                    adapter = new LocationAdapter(MainActivity.this, locationList);
                                    mList.setAdapter(adapter);

                            }
                        });
                    }
                } catch (InterruptedException e) {
                }
            }
        };

        mThread.start();*/

    }

    @Override
    protected void onStart() {
        super.onStart();

        Intent intent = new Intent(this, LocationService.class);
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
    }

}

位置服务

    public class LocationService extends Service implements LocationListener, GoogleApiClient.ConnectionCallbacks {
    private final IBinder mBinder = new LocalBinder();
    ArrayList<MyLocation> locationList = new ArrayList<>();
    private DbHelper dbHelper;
    private Location mLocation;
    private GoogleApiClient mGoogleApiClient;
    private LocationRequest mLocationRequest;
    private String TAG = "Service";

    @Override
    public IBinder onBind(Intent arg0) {
        return mBinder;
    }

    @Override
    public void onCreate() {
        super.onCreate();
        mGoogleApiClient = new GoogleApiClient.Builder(this)
                .addConnectionCallbacks(this)
                .addApi(LocationServices.API).build();
        mGoogleApiClient.connect();

        dbHelper = new DbHelper(this);
        createLocationRequest();
        displayLocation();

    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {

        Toast.makeText(this, "Service Started", Toast.LENGTH_LONG).show();
        return START_STICKY;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.d(TAG, "service destroy");

    }

         public List<MyLocation> displayLocation() {

           mLocation = LocationServices.FusedLocationApi
                   .getLastLocation(mGoogleApiClient);
           if (mLocation != null) {

               double latitude = mLocation.getLatitude();
               double longitude = mLocation.getLongitude();
               String lastUpdateTime = DateFormat.getTimeInstance().format(new Date());
               dbHelper.insertLocationDetails(longitude, latitude, lastUpdateTime);
               locationList = dbHelper.getLocationDetails();

               return locationList;

           } else {
               return null;
           }

    }


    protected void startLocationUpdates() {

        LocationServices.FusedLocationApi.requestLocationUpdates(
                mGoogleApiClient, mLocationRequest, this);
        Log.d(TAG, "Connected to update");

    }

    protected void createLocationRequest() {
        mLocationRequest = new LocationRequest();
        mLocationRequest.setInterval(5000);
        mLocationRequest.setFastestInterval(5000);
        mLocationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);

    }

    public void onLocationChanged(Location location) {

        mLocation = location;

        Toast.makeText(getApplicationContext(), "Location changed",
                Toast.LENGTH_SHORT).show();

        displayLocation();
    }

    public void onConnected(Bundle arg0) {

        startLocationUpdates();

    }

    @Override
    public void onConnectionSuspended(int arg0) {
        mGoogleApiClient.connect();

    }

    public class LocalBinder extends Binder {
        public LocationService getService() {

            return LocationService.this;
        }
    }


}

数据库帮助程序

    public class DbHelper extends SQLiteOpenHelper {
    private static final int DATABASE_VERSION = 1;
    private static final String LONGITUDE = "longitude";
    private static final String LATITUDE = "latitude";
    private static final String LOCATION_CHANGE_TIME = "location_change_time";
    private static final String LOCATION_DETAIL_TABLE = "location_detail_table";
    private static final String CREATE_TABLE_LOCATION = "CREATE TABLE "
            + LOCATION_DETAIL_TABLE + " (" + LONGITUDE + " TEXT,"
            + LOCATION_CHANGE_TIME + " TEXT,"
            + LATITUDE + " TEXT)";
    public static String DATABASE_NAME = "Location_database";

    public DbHelper(Context context) {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);

    }

    @Override
    public void onCreate(SQLiteDatabase database) {
        database.execSQL(CREATE_TABLE_LOCATION);


    }

    public void insertLocationDetails(double longitude, double latitude, String time) {
        SQLiteDatabase database = this.getWritableDatabase();

        ContentValues values = new ContentValues();
        values.put(LONGITUDE, longitude);
        values.put(LATITUDE, latitude);
        values.put(LOCATION_CHANGE_TIME, time);
        long id=  database.insert(LOCATION_DETAIL_TABLE, null, values);
        System.out.println("Newly added item id "+id);
        database.close();



    }

    public ArrayList<MyLocation> getLocationDetails() {

        ArrayList<MyLocation> locationList = new ArrayList();
        String selectQuery = "SELECT  * FROM " + LOCATION_DETAIL_TABLE;
        SQLiteDatabase database = this.getReadableDatabase();
        Cursor cursor = database.rawQuery(selectQuery, null);

        if (cursor.moveToNext()) {
            do {
                MyLocation location = new MyLocation();

                String longitude = cursor.getString(cursor
                        .getColumnIndexOrThrow(LONGITUDE));
                String latitude = cursor.getString(cursor.getColumnIndexOrThrow(LATITUDE));
                String time = cursor.getString(cursor
                        .getColumnIndexOrThrow(LOCATION_CHANGE_TIME));
                location.setLatitude(latitude);
                location.setLongitude(longitude);
                location.setLastUpdatedTime(time);
                locationList.add(location);

            } while (cursor.moveToNext());
        }

        if (cursor != null) {
            cursor.close();
        }
        database.close();
        return locationList;
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {


    }
}

最佳答案

就您而言,您可以使用 ContentProvider 并在 activity 中实现 LoaderManager.LoaderCallbacks

@Nullable
@Override
public Uri insert(Uri uri, ContentValues values) {

    db = dbHelper.getWritableDatabase();

    String table = uri.getLastPathSegment();

    long rowID = db.insert(table, null, values);

    Uri CONTENT_URI = Uri.parse("content://"
            + AUTHORITY + "/" + table);

    Uri resultUri = ContentUris.withAppendedId(CONTENT_URI, rowID);

    getContext().getContentResolver().notifyChange(resultUri, null);
    return resultUri;
}

getContext().getContentResolver().notifyChange(resultUri, null);

ContentProvider中会导致重新查询数据。在 Activity 中使用 SimpleAdapter 将更新您的 UI。

关于java - 服务和 Activity 通信...从服务接收到数据时更新 UI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35177443/

相关文章:

Java 应用服务器;哪个更好?

java - 将十进制转换为二进制

Android ImageButton 选择器 - 每个按钮一个 xml?

reactjs - React Native 需要点击两次 onPress 才能工作

java - 颜色值无效 -- 必须是 #rgb、#argb、#rrggbb 或 #aarrggbb

java - java中以int数组作为键的哈希表

android - Android 上的 GPS 如何获取海拔高度?

android - 如果 token 过期怎么办

c# - Windows Phone 8.1 ListView.ReorderMode 不通知 ObservableCollection

Android ListView 自定义 header