Actively read 150 x 150 pixels from a camera preview - camera

I have set up an Android camera application that allows me to preview the camera in a Frame Layout within my main Activity. What I would like to do (without using camera specific functionality; I want this to be completely independent of hardware.) is out line 150 X 150 pixels in the center of the preview either by showing a box around the pixels or blurring all of the pixels except the 150 x 150. Additionally, without taking a picture, I would like to read these pixels. Ultimately the effect I am going for is, as the camera is moved I display the change in the red, green, and blue color concentrations within the 150 x 150 area. I know how to do the nested for loop and get the color from the pixel, but I would need to know how to get the offset for the height and weight to start reading the pixels from.
Thanks in advance for all of your help!
Mike
public class MyActivity extends Activity {
final public String TAG = "MyActivity";
static private Camera mCamera = null;
static public Camera getCamera() { return mCamera; }
private static boolean mBPreviewingCamera = false;
private PreviewSurface mPS;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
String lMTH = "onCreate ";
Log.i(TAG, lMTH + "Start");
setContentView(R.layout.activity_color_temperature_estimator);
if (isThereACamera()) {
mPreviewCamera(true);
TextView lTVTemp = (TextView) findViewById(R.id.TV_TEMP);
lTVTemp.setText("Camera exists able to proceed");
lTVTemp = null;
} else {
Toast.makeText(this, "No camera! Uunable to proceed", Toast.LENGTH_LONG).show();
TextView lTVTemp = (TextView) findViewById(R.id.TV_TEMP);
lTVTemp.setText("No camera! Uunable to proceed");
lTVTemp = null;
}
}
public void mPreviewCamera(boolean pBPreviewingCamera) {
String lMTH = "mPreviewCamera ";
try {
if (pBPreviewingCamera) {
Log.i(TAG, lMTH + "Open Camera");
mCamera = Camera.open();
mPS = new PreviewSurface(this);
FrameLayout lFVPreview = (FrameLayout) findViewById(R.id.FL_Preview);
lFVPreview.addView(mPS);
lFVPreview = null;
mBPreviewingCamera = true;
Button lBTNTemp = (Button) findViewById(R.id.BTN_CLOSE);
lBTNTemp.setText(R.string.BTN_CLOSE);
lBTNTemp = null;
} else {
Log.i(TAG, lMTH + "Open Camera");
mCloseCamera();
Button lBTNTemp = (Button) findViewById(R.id.BTN_CLOSE);
lBTNTemp.setText(R.string.BTN_OPEN);
lBTNTemp = null;
}
} catch (Exception e) {
Log.i(TAG, lMTH + e.getMessage());
mCloseCamera();
e.printStackTrace();
}
}
public void mCloseCamera() {
String lMTH = "mCloseCamera ";
Log.i(TAG, lMTH + "Turn Camera Off");
if (mCamera != null) {
mCamera.stopPreview();
mCamera.release();
}
mCamera = null;
mBPreviewingCamera = false;
}
#Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
String lMTH = "onPause ";
Log.i(TAG, lMTH + "Turn Camera Off");
mPreviewCamera(false);
}
#Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
String lMTH = "onDestroy ";
Log.i(TAG, lMTH + "Turn Camera Off");
mPreviewCamera(false);
}
/** Check if this phone has a camera */
private boolean isThereACamera() {
if (getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)){
// There is a camera
return true;
} else {
// There isn't a camera
return false;
}
}
public void mBTN(View view) {
mPreviewCamera(!mBPreviewingCamera);
}
}
public class PreviewSurface extends SurfaceView implements SurfaceHolder.Callback {
final static public String TAG = "PreviewSurface";
private SurfaceHolder mSH;
/**
* #param context
*/
public PreviewSurface(Context pContext) {
super(pContext);
// TODO Auto-generated constructor stub
String lMTH = "PreviewSurface(Context pContext) ";
Log.i(TAG, lMTH + "Constructor");
pContext = null;
mSH = getHolder();
mSH.addCallback(this);
mSH.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}
/* (non-Javadoc)
* #see android.view.SurfaceHolder.Callback#surfaceChanged(android.view.SurfaceHolder, int, int, int)
*/
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3) {
String lMTH = "surfaceChanged ";
// TODO Auto-generated method stub
Log.i(TAG, lMTH + "arg1 = " + arg1 + " arg2 " + arg2 + " arg3 " + arg3);
if (arg0.getSurface() != null) {
// stop old preview if it exists
try {
Log.i(TAG, lMTH + "Stop Preview ");
MyActivity.getCamera().stopPreview();
} catch (Exception e) {
Log.i(TAG, lMTH + "Stoping preview exception " + e.getMessage());
}
// start new preview
try {
Log.i(TAG, lMTH + "Set Preview ");
MyActivity.getCamera().setPreviewDisplay(arg0);
Log.i(TAG, lMTH + "Start Preview ");
MyActivity.getCamera().startPreview();
} catch (Exception e){
Log.i(TAG, lMTH + "Starting camera preview exception " + e.getMessage());
}
}
// stop preview before making changes
}
/* (non-Javadoc)
* #see android.view.SurfaceHolder.Callback#surfaceCreated(android.view.SurfaceHolder)
*/
public void surfaceCreated(SurfaceHolder arg0) {
String lMTH = "surfaceCreated ";
// TODO Auto-generated method stub
try {
Log.i(TAG, lMTH + "Set Preview ");
MyActivity.getCamera().setPreviewDisplay(arg0);
Log.i(TAG, lMTH + "Start Preview ");
MyActivity.getCamera().startPreview();
} catch (Exception e) {
Log.i(TAG, lMTH + "Exception " + e.getMessage());
e.printStackTrace();
}
}
/* (non-Javadoc)
* #see android.view.SurfaceHolder.Callback#surfaceDestroyed(android.view.SurfaceHolder)
*/
public void surfaceDestroyed(SurfaceHolder arg0) {
String lMTH = "surfaceDestroyed ";
// TODO Auto-generated method stub
Log.i(TAG, lMTH + "Activity will handle destroy");
}

"I would need to know how to get the offset for the height and weight
to start reading the pixels from"
An easy way to get the offset for your nested for-loop is walked through with descriptive variables:
int xWidth = 150; // The length you want to concentrate on
int yHeight = 150;
int xCenter = previewWidth/2;
int yCenter = previewHeight/2;
int xStart = xCenter - xWidth/2;
int xEnd = xCenter + xWidth/2;
int yStart = yCenter - yHeight/2;
int yEnd = yCenter + yHeight/2;
for(int y = yStart; y < yEnd; y++) {
for(int x = xStart; x < xEnd; x++) {
// read pixels
}
}
The previewWidth and previewHeight can be easily gotten from surfaceChange():
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
previewWidth = w;
previewHeight = h;
...
}
The reason I use many variables here is so that you can clearly see how I walked through this problem.
Let me know how it goes.

Related

jvm condition and locksupport which is faster?

An experimental example of synchronous call is made. Each thread task waits for a task callback with its own value of + 1. The performance difference between condition and locksupport is compared. The result is unexpected. The two times are the same, but the difference on the flame diagram is very big. Does it mean that the JVM has not optimized locksupport
enter image description here
public class LockerTest {
static int max = 100000;
static boolean usePark = true;
static Map<Long, Long> msg = new ConcurrentHashMap<>();
static ExecutorService producer = Executors.newFixedThreadPool(4);
static ExecutorService consumer = Executors.newFixedThreadPool(16);
static AtomicLong record = new AtomicLong(0);
static CountDownLatch latch = new CountDownLatch(max);
static ReentrantLock lock = new ReentrantLock();
static Condition cond = lock.newCondition();
static Map<Long, Thread> parkMap = new ConcurrentHashMap<>();
static AtomicLong cN = new AtomicLong(0);
public static void main(String[] args) throws InterruptedException {
long start = System.currentTimeMillis();
for (int num = 0; num < max; num++) {
consumer.execute(() -> {
long id = record.incrementAndGet();
msg.put(id, -1L);
call(id);
if (usePark) {
Thread thread = Thread.currentThread();
parkMap.put(id, thread);
while (msg.get(id) == -1) {
cN.incrementAndGet();
LockSupport.park(thread);
}
} else {
lock.lock();
try {
while (msg.get(id) == -1) {
cN.incrementAndGet();
cond.await();
}
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
latch.countDown();
});
}
latch.await();
consumer.shutdown();
producer.shutdown();
System.out.printf("park %s suc %s cost %s cn %s"
, usePark
, msg.entrySet().stream().noneMatch(entry -> entry.getKey() + 1 != entry.getValue())
, System.currentTimeMillis() - start
, cN.get()
);
}
private static void call(long id) {
producer.execute(() -> {
try {
Thread.sleep((id * 13) % 100);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (usePark) {
msg.put(id, id + 1);
LockSupport.unpark(parkMap.remove(id));
} else {
lock.lock();
try {
msg.put(id, id + 1);
cond.signalAll();
} finally {
lock.unlock();
}
}
});
}
}

How to set both axis's scales to be always the same?

MPAndroidChart allows you to zoom in the X axis, Y axis and both. I would like to rescale the remaining axis (or both) to match the one(s) being scaled.
For that I've created a OnChartGestureListener:
public class ZoomNotDistorting implements OnChartGestureListener {
private Chart chart;
private ViewPortHandler viewPortHandler;
private float startDist = 1f;
private float scaleX, scaleY;
public ZoomNotDistorting(Chart chart) {
this.chart = chart;
this.viewPortHandler = chart.getViewPortHandler();
}
#Override
public void onChartGestureStart(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture) {
int action = me.getAction() & MotionEvent.ACTION_MASK;
if(action == MotionEvent.ACTION_POINTER_DOWN && me.getPointerCount() >= 2) {
startDist = spacing(me);
}
}
#Override
public void onChartGestureEnd(MotionEvent me, ChartTouchListener.ChartGesture lastPerformedGesture) {
switch (lastPerformedGesture) {
case PINCH_ZOOM:
float scale = spacing(me) / startDist; // total scale
boolean isZoomingOut = (scale < 1);
if(isZoomingOut) {
if(scaleX < scaleY) {
viewPortHandler.zoom(scaleX, scaleX);
} else {
viewPortHandler.zoom(scaleY, scaleY);
}
} else {
if(scaleX > scaleY) {
viewPortHandler.zoom(scaleX, scaleX);
} else {
viewPortHandler.zoom(scaleY, scaleY);
}
}
break;
case X_ZOOM:
viewPortHandler.zoom(scaleX, scaleX);
break;
case Y_ZOOM:
viewPortHandler.zoom(scaleY, scaleY);
break;
}
chart.invalidate();
}
#Override
public void onChartLongPressed(MotionEvent me) {}
#Override
public void onChartDoubleTapped(MotionEvent me) {}
#Override
public void onChartSingleTapped(MotionEvent me) {}
#Override
public void onChartFling(MotionEvent me1, MotionEvent me2, float velocityX, float velocityY) {}
#Override
public void onChartScale(MotionEvent me, float scaleX, float scaleY) {
this.scaleX = scaleX;
this.scaleY = scaleY;
}
#Override
public void onChartTranslate(MotionEvent me, float dX, float dY) {}
/**
* returns the distance between two pointer touch points
*/
private static float spacing(MotionEvent event) {
float x = event.getX(0) - event.getX(1);
float y = event.getY(0) - event.getY(1);
return (float) Math.sqrt(x * x + y * y);
}
}
That class doesn't seem to be doing anything,How to set both axis's scales to be always the same?
Also, here is my chart class:
public class MathGraph extends LineChart {
public static final int BOUNDARIES = 100;
public static final int DATA_POINTS = 200;
private static final int LINE_WIDTH = 2;
private LineData data;
public MathGraph(Context context, AttributeSet attrs) {
super(context, attrs);
super.setDescription(null);
//Misc
getLegend().setEnabled(false);
setRenderer(new LineChatRendererNoData(this, mAnimator, mViewPortHandler));
//Lines encasing the chart
getXAxis().setAxisLineWidth(LINE_WIDTH);
getAxisLeft().setAxisLineWidth(LINE_WIDTH);
getAxisRight().setEnabled(false);
//Line for (x; 0)
getAxisLeft().setDrawZeroLine(true);
getAxisLeft().setZeroLineWidth(LINE_WIDTH);
getAxisRight().setDrawZeroLine(true);
getAxisRight().setZeroLineWidth(LINE_WIDTH);
//Line for (0; y)
LimitLine limitLine = new LimitLine(0f);
limitLine.setLineColor(Color.GRAY);
limitLine.setLineWidth(LINE_WIDTH);
getXAxis().addLimitLine(limitLine);
setOnChartGestureListener(new ZoomNotDistorting(this));
}
public void setFunction(Function f) {
if(!f.checkSyntax()) throw new IllegalStateException("Error in function: " + f.toString() + "!");
setDescription(f);
data = null;
LoadFunctionAsyncTask l = new LoadFunctionAsyncTask(f, -BOUNDARIES, BOUNDARIES, DATA_POINTS,
(List<Entry> pointList) -> {
if(data == null) {
ILineDataSet dataSet = new LineDataSet(new ArrayList<>(), null);
dataSet.setValueFormatter(new PointValueFormatter());
dataSet.setHighlightEnabled(true);
for (Entry dataPoint : pointList) {
dataSet.addEntry(dataPoint);
}
data = new LineData(dataSet);
setData(data);
} else {
for (Entry dataPoint : pointList) {
data.addEntry(dataPoint, 0);// 0 is the only dataset
}
data.notifyDataChanged();
notifyDataSetChanged();
invalidate();
}
});
l.execute();
}
private void setDescription(Function f) {
Description desc = new Description();
desc.setText(f.getDescription());
desc.setPosition(16, getBottom() - 16);
setDescription(desc);
}
private class PointValueFormatter implements IValueFormatter {
#Override
public String getFormattedValue(float value, Entry entry, int dataSetIndex, ViewPortHandler viewPortHandler) {
return "(" + entry.getX() + ", " + entry.getY() + ")";
}
}
}
OK, apparently chart.invalidate() isn't enough, the Matrix needs to be refreshed:
Matrix matrix = null;
//...
matrix = viewPortHandler.zoom(scaleX, scaleX);
//...
if(matrix != null) {
viewPortHandler.refresh(matrix, chart, true);
}
As a bonus, the last true in refresh() is for invalidate, so no need for chart.invalidate();.

How to move map marker like moving car on road from source to destination

I want to move marker on Google map from source to destination like Uber or Ola and i am working on google map, I am new so Please help me how it is possible ...?
My code is :
public void onMapReady(GoogleMap googleMap) {
GoogleMap gMap = googleMap;
addMarks1(gMap);
if (ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(getActivity(), Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
// TODO: Consider calling
// ActivityCompat#requestPermissions
// here to request the missing permissions, and then overriding
// public void onRequestPermissionsResult(int requestCode, String[] permissions,
// int[] grantResults)
// to handle the case where the user grants the permission. See the documentation
// for ActivityCompat#requestPermissions for more details.
return;
}
gMap.setMyLocationEnabled(true);
gMap.getUiSettings().setZoomControlsEnabled(true);
// Turns on 3D buildings
gMap.setBuildingsEnabled(true);
}
private void addMarks1(GoogleMap googleMap) {
googleMap.clear();
// updateRouteOnMAp();
double d_lat=Double.valueOf(rideDetailSessionManager.getColumnFromTaxiDriver(RideDetailSessionManager.KEY_START_LAT));
double d_loing=Double.valueOf(rideDetailSessionManager.getColumnFromTaxiDriver(RideDetailSessionManager.KEY_START_LNG));
fromPosition=new LatLng(d_lat,d_loing);
toPosition=new LatLng(Double.valueOf(rideDetailSessionManager.getColumnFromTaxiDriver(RideDetailSessionManager.KEY_END_LAT)),
Double.valueOf(rideDetailSessionManager.getColumnFromTaxiDriver(RideDetailSessionManager.KEY_END_LNG)));
List<Marker> markersList = new ArrayList<Marker>();
Marker StartLatLon= googleMap.addMarker(new MarkerOptions().position(fromPosition).title("Start Point").icon(BitmapDescriptorFactory.fromResource(R.drawable.red_car_image)));
Marker EndLatLon= googleMap.addMarker(new MarkerOptions().position(toPosition).icon(BitmapDescriptorFactory.fromResource(R.drawable.red_car_image)));
markersList.add(StartLatLon);
markersList.add(EndLatLon);
builder = new LatLngBounds.Builder();
for (Marker m : markersList) {
builder.include(m.getPosition());
}
int padding = 150;
LatLngBounds bounds = builder.build();
cu = CameraUpdateFactory.newLatLngBounds(bounds, padding);
googleMap.animateCamera(cu);
traceMe(googleMap);
}
private void traceMe(final GoogleMap googleMap) {
String srcParam;
String destParam;
String startLat=rideDetailSessionManager.getColumnFromTaxiDriver(RideDetailSessionManager.KEY_START_LAT);
String startLng=rideDetailSessionManager.getColumnFromTaxiDriver(RideDetailSessionManager.KEY_START_LNG);
GPSTracker gpsTracker=new GPSTracker(getActivity());
srcParam = startLat + "," + startLng;
destParam = gpsTracker.getLatitude() + "," + gpsTracker.getLongitude();
Log.d("drop lat pp2", ":" + destParam);
String modes[] = {"driving", "walking", "bicycling", "transit"};
String url = "https://maps.googleapis.com/maps/api/directions/json?origin=" + srcParam + "&destination=" + destParam + "&sensor=false&units=metric&mode=driving";
StringRequest jsonObjectRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.d("dkp lat long", ":" + response);
JSONObject jsonObject=null;
try {
jsonObject=new JSONObject(response);
} catch (JSONException e) {
e.printStackTrace();
}
MapDirectionsParser parser = new MapDirectionsParser();
List<List<HashMap<String, String>>> routes = parser.parse(jsonObject);
for (int i = 0; i < routes.size(); i++) {
points = new ArrayList<LatLng>();
List<HashMap<String, String>> path = routes.get(i);
Log.d("dkp lat long", ":" + path);
for (int j = 0; j < path.size(); j++) {
HashMap<String, String> point = path.get(j);
double lat = Double.parseDouble(point.get("lat"));
double lng = Double.parseDouble(point.get("lng"));
LatLng position = new LatLng(lat, lng);
points.add(position);
}
}
Log.d("dkp points lat long", ":" + points);
drawPoints(points, googleMap);
String str_dist=parser.distance();
//String str_dur=parser.duration();
if (!str_dist.equals("null"))
{
distance= Integer.parseInt(str_dist);
//estimate_distance= (distance/100)+50;
//rideEstimateDistance.setText((estimate_distance-50)+"-"+estimate_distance);
Log.d("dkp kkk distance", ":" + distance);
}
/*if (!str_dur.equals("null"))
{
int duration=Integer.parseInt(parser.duration());
estimate_duration= duration/60;
ideEstimateDistance.setText((estimate_distance-50)+"-"+estimate_distance);
Log.d("dkp kkk duration", ":" + duration);
}*/
}
},
new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
if (error instanceof TimeoutError || error instanceof NoConnectionError) {
Log.d("error ocurred", "TimeoutError");
//Toast.makeText(getActivity(), "TimeoutError", Toast.LENGTH_LONG).show();
} else if (error instanceof AuthFailureError) {
Log.d("error ocurred", "AuthFailureError");
//Toast.makeText(getActivity(), "AuthFailureError", Toast.LENGTH_LONG).show();
} else if (error instanceof ServerError) {
Log.d("error ocurred", "ServerError");
// emailEdt.requestFocus();
// Toast.makeText(getActivity(), "Please enter valid email or password", Toast.LENGTH_LONG).show();
// Toast.makeText(getActivity(), "ServerError", Toast.LENGTH_LONG).show();
} else if (error instanceof NetworkError) {
Log.d("error ocurred", "NetworkError");
//Toast.makeText(getActivity(), "NetworkError", Toast.LENGTH_LONG).show();
} else if (error instanceof ParseError) {
Log.d("error ocurred", "ParseError");
//Toast.makeText(getActivity(), "ParseError", Toast.LENGTH_LONG).show();
}
}
});
// MyApplication.getInstance().addToRequestQueue(jsonObjectRequest, "jreq");
RequestQueue requestQueue = Volley.newRequestQueue(getActivity());
requestQueue.add(jsonObjectRequest);
}
private void drawPoints(ArrayList<LatLng> points, GoogleMap mMaps) {
if (points == null) {
return;
}
traceOfMe = points;
PolylineOptions polylineOpt = new PolylineOptions();
for (LatLng latlng : traceOfMe) {
polylineOpt.add(latlng);
}
polylineOpt.color(Color.BLUE);
if (mPolyline != null) {
mPolyline.remove();
mPolyline = null;
}
if (mMaps != null) {
mPolyline = mMaps.addPolyline(polylineOpt);
} else {
}
if (mPolyline != null)
mPolyline.setWidth(7);
}
You will have to remove the marker from the map using googleMap.clear() and redraw it again in the new location.

JSON response Using Volley in a recycler view in Android app

I am trying to print a json response response in a recyclerview. my Recyclerview is like a expanded listView. And my json resone is like this:
{"Table1":
[
{"filedate":"Oct 26, 2016"},
{"filedate":"Oct 18, 2016"}
],
"Table2":
[{
"filedate":"Oct 18, 2016",
"file1":"12.txt"
},
{
"filedate":"Oct 26, 2016",
"file1":"acerinvoice.pdf"
}
]}
and I trying to print this json resonse using this code:
private void prepareListData() {
// Volley's json array request object
StringRequest stringRequest = new StringRequest(Request.Method.POST, REGISTER_URL,
new Response.Listener<String>() {
//I think problrm is here
#Override
public void onResponse(String response) {
try {
**JSONObject object = new JSONObject(response);
JSONArray jsonarray = object.getJSONArray("Table1");
JSONArray jsonarray1 = object.getJSONArray("Table2");
for (int i = 0; i < jsonarray.length(); i++) {
try {
JSONObject obj = jsonarray.getJSONObject(i);
String str = obj.optString("filedate").trim();
int lth = jsonarray1.length();
data.add(new ExpandableListAdapter.Item(ExpandableListAdapter.HEADER, str));
for (int j = 0; j < jsonarray1.length(); j++) {
try {
JSONObject obj1 = jsonarray1.getJSONObject(j);
String str1 = obj1.optString("filedate").trim();
data.add(new ExpandableListAdapter.Item(ExpandableListAdapter.CHILD, str1));
Toast.makeText(getApplicationContext(), str1, Toast.LENGTH_LONG).show();**
//if condition
} catch (JSONException e) {
// Log.e(TAG, "JSON Parsing error: " + e.getMessage());
}
}
// adding movie to movies array
} catch (JSONException e) {
Log.e("gdshfsjkg", "JSON Parsing error: " + e.getMessage());
}
}
Log.d("test", String.valueOf(data));
Toast.makeText(getApplicationContext(), (CharSequence) data, Toast.LENGTH_LONG).show();
} catch (JSONException e) {
e.printStackTrace();
}
// notifying list adapter about data changes
// so that it renders the list view with updated data
recyclerview.setAdapter(new ExpandableListAdapter(data));
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
}
}){
#Override
protected Map<String, String> getParams() {
Map<String, String> params = new HashMap<String, String>();
params.put(CLIENT, "4");
return params;
}
};
// Adding request to request queue
MyApplication.getInstance().addToRequestQueue(stringRequest);
}
ExpandableListAdapter
public class ExpandableListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
public static final int HEADER = 0;
public static final int CHILD = 1;
private List<Item> data;
public ExpandableListAdapter(List<Item> data) {
this.data = data;
}
#Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int type) {
View view = null;
Context context = parent.getContext();
float dp = context.getResources().getDisplayMetrics().density;
int subItemPaddingLeft = (int) (18 * dp);
int subItemPaddingTopAndBottom = (int) (5 * dp);
switch (type) {
case HEADER:
LayoutInflater inflater = (LayoutInflater) parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.list_header, parent, false);
ListHeaderViewHolder header = new ListHeaderViewHolder(view);
return header;
case CHILD:
TextView itemTextView = new TextView(context);
itemTextView.setPadding(subItemPaddingLeft, subItemPaddingTopAndBottom, 0, subItemPaddingTopAndBottom);
itemTextView.setTextColor(0x88000000);
itemTextView.setLayoutParams(
new ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
return new RecyclerView.ViewHolder(itemTextView) {
};
}
return null;
}
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
final Item item = data.get(position);
switch (item.type) {
case HEADER:
final ListHeaderViewHolder itemController = (ListHeaderViewHolder) holder;
itemController.refferalItem = item;
itemController.header_title.setText(item.text);
if (item.invisibleChildren == null) {
itemController.btn_expand_toggle.setImageResource(R.drawable.circle_minus);
} else {
itemController.btn_expand_toggle.setImageResource(R.drawable.circle_plus);
}
itemController.btn_expand_toggle.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (item.invisibleChildren == null) {
item.invisibleChildren = new ArrayList<Item>();
int count = 0;
int pos = data.indexOf(itemController.refferalItem);
while (data.size() > pos + 1 && data.get(pos + 1).type == CHILD) {
item.invisibleChildren.add(data.remove(pos + 1));
count++;
}
notifyItemRangeRemoved(pos + 1, count);
itemController.btn_expand_toggle.setImageResource(R.drawable.circle_plus);
} else {
int pos = data.indexOf(itemController.refferalItem);
int index = pos + 1;
for (Item i : item.invisibleChildren) {
data.add(index, i);
index++;
}
notifyItemRangeInserted(pos + 1, index - pos - 1);
itemController.btn_expand_toggle.setImageResource(R.drawable.circle_minus);
item.invisibleChildren = null;
}
}
});
break;
case CHILD:
TextView itemTextView = (TextView) holder.itemView;
itemTextView.setText(data.get(position).text);
break;
}
}
#Override
public int getItemViewType(int position) {
return data.get(position).type;
}
#Override
public int getItemCount() {
return data.size();
}
private static class ListHeaderViewHolder extends RecyclerView.ViewHolder {
public TextView header_title;
public ImageView btn_expand_toggle;
public Item refferalItem;
public ListHeaderViewHolder(View itemView) {
super(itemView);
header_title = (TextView) itemView.findViewById(R.id.header_title);
btn_expand_toggle = (ImageView) itemView.findViewById(R.id.btn_expand_toggle);
}
}
public static class Item {
public int type;
public String text;
public List<Item> invisibleChildren;
public Item() {
}
public Item(int type, String text) {
this.type = type;
this.text = text;
}
}
}
But this code print nothing in my recycler UI.It show only a empty layout.I have also tried to print the response in my log and it prints whole response together.I want to print table1 contents in headers and table2 contents in as child(items) with their respective headers.how to do this?If any other information needed please ask..
You should probably check your response first of everything. As per your requirements you should use HashMap and ArrayList. Follow these following steps:
1.Take a ArrayLsit and store child data of 1st heading and so on with index starting from 0.
2.Store headers in HashMap as key.
ex: HashMap<String,ArrayList<Data>> hm;
hm.put("your first heading string","related arraylist");
Then use ExpandableListView to arrange parent and child items.
please check your json response this is invalid json response first try to validate your json formate after try to decode and add in recycler view.
Check Your Response into Logcat also the Exception. I've tested the Response you've supplied that contains some unnecessary "," that may cause the Exception.
I have solve my problem to just change above code like this..
private void prepareListData() {
// Volley's json array request object
StringRequest stringRequest = new StringRequest(Request.Method.POST, REGISTER_URL,
new Response.Listener<String>() {
#Override
public void onResponse(String response) {
JSONObject object = null;
try {
object = new JSONObject(response);
} catch (JSONException e) {
e.printStackTrace();
}
JSONArray jsonarray = null;
JSONArray jsonarray1 = null;
try {
jsonarray = object.getJSONArray("Table1");
jsonarray1 = object.getJSONArray("Table1");
} catch (JSONException e) {
e.printStackTrace();
}
for (int i = 0; i < jsonarray.length(); i++) {
try {
JSONObject obj = jsonarray.getJSONObject(i);
//
String str = obj.optString("filedate").trim();
Log.d("test", str);
data.add(new ExpandableListAdapter.Item(ExpandableListAdapter.HEADER, str));
// Toast.makeText(getApplicationContext(), lth, Toast.LENGTH_LONG).show();
for (int j = 0; j < jsonarray1.length(); j++) {
try {
JSONObject obj1 = jsonarray1.getJSONObject(j);
String str1 = obj1.optString("filedate").trim();
String str3 = obj1.optString("category").trim();
String str2 = obj1.optString("file1").trim();
String str4 = obj1.optString("4").trim();
Toast.makeText(getApplicationContext(), "server data respone", Toast.LENGTH_LONG).show();
Toast.makeText(getApplicationContext(), "test"+str1, Toast.LENGTH_LONG).show();
if (str == str1) {
// data.add(new ExpandableListAdapter.Item(ExpandableListAdapter.CHILD, str1));
data.add(new ExpandableListAdapter.Item(ExpandableListAdapter.CHILD, str3));
data.add(new ExpandableListAdapter.Item(ExpandableListAdapter.CHILD, str2));
}
Toast.makeText(getApplicationContext(), str1, Toast.LENGTH_LONG).show();
//if condition
} catch (JSONException e) {
// Log.e(TAG, "JSON Parsing error: " + e.getMessage());
}
}
// adding movie to movies array
} catch (JSONException e) {
Log.e("gdshfsjkg", "JSON Parsing error: " + e.getMessage());
}
}
Log.d("test", String.valueOf(data));
// notifying list adapter about data changes
// so that it renders the list view with updated data
// adapterheader.notifyDataSetChanged();
recyclerview.setAdapter(new ExpandableListAdapter(data));
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
// VolleyLog.d(TAG, "Error: " + error.getMessage());
// hidePDialog();
}
}){
#Override
protected Map<String, String> getParams() {
Map<String, String> params = new HashMap<String, String>();
params.put(CLIENT, "4");
return params;
}
};
// Adding request to request queue
MyApplication.getInstance().addToRequestQueue(stringRequest);
}

MPAndroidChart multiple real time line chart - entries not added at correct xIndex

I modified a little bit the Real Time Line Chart example to show two LineChart like the code below.
Problem: the ViewPort is moving incorrectly does not work properly. It is moving much faster than real points (Entry) are added. In other words, the Entry get added in the wrong place and the ViewPort keeps moving right uncontrollably. It should move right only gradually as each Entry is added. Please help me to fix this one.
private int year = 2015;
SimpleDateFormat sdf = new SimpleDateFormat("hh:mm:ss.SSS");
private int[] mColors = {Color.BLUE,Color.YELLOW,Color.CYAN,Color.MAGENTA,Color.GREEN};
private int mCurrentColorIndex = 0;
private synchronized void addEntry(String id, float value) {
LineData data = mChart.getData();
if (data != null) {
ILineDataSet set = data.getDataSetByLabel(id,true);
//ILineDataSet set1 = data.getDataSetByIndex(0);
if (set == null) {
set = createSet(id, mColors[(mCurrentColorIndex++)%mColors.length ]);
data.addDataSet(set);
}
String xValue = sdf.format(new Date());
// add a new x-value first
data.addXValue(xValue);
set.addEntry(new Entry(value, set.getEntryCount(), 0));
// let the chart know it's data has changed
mChart.notifyDataSetChanged();
// limit the number of visible entries
mChart.setVisibleXRangeMaximum(30);
// mChart.setVisibleYRange(30, AxisDependency.LEFT);
// move to the latest entry
mChart.moveViewToX(data.getXValCount() - 31);
// this automatically refreshes the chart (calls invalidate())
// mChart.moveViewTo(data.getXValCount()-7, 55f,
// AxisDependency.LEFT);
}
}
private LineDataSet createSet(String label, int color) {
LineDataSet set = new LineDataSet(null, label);
set.setAxisDependency(AxisDependency.LEFT);
set.setColor(color);
set.setCircleColor(Color.WHITE);
set.setLineWidth(2f);
set.setCircleRadius(4f);
set.setFillAlpha(65);
set.setFillColor(color);
set.setHighLightColor(Color.rgb(244, 117, 117));
set.setValueTextColor(Color.WHITE);
set.setValueTextSize(9f);
set.setDrawValues(false);
return set;
}
private void feedMultiple() {
new Thread(new Runnable() {
#Override
public void run() {
for(int i = 0; i < 50; i++) {
runOnUiThread(new Runnable() {
#Override
public void run() {
addEntry("name1", (float)(Math.random() * 40) + 30f);
}
});
try {
Thread.sleep(35);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
new Thread(new Runnable() {
#Override
public void run() {
for(int i = 0; i < 100; i++) {
runOnUiThread(new Runnable() {
#Override
public void run() {
addEntry("name2", (float)(Math.random() * 40) + 30f);
}
});
try {
Thread.sleep(35);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
Resolved in the comments by #Tony with the following change:
//set.addEntry(new Entry(value, set.getEntryCount(), 0)); //incorrect
set.addEntry(new Entry(value, data.getXValCount(), 0)); //correct
Explanation:
A LineData is composed of multiple ILineDataSet:
set.getEntryCount() returns the number of y-values in one DataSet and is effectively equivalent to yvals.size().
data.getXValCount() returns the total number of x-values the ChartData object represents.
Since we wish to add an entry at the last x-index, we should use data.getXValCount()
NOTE:
In MPAndroidCharts 3.0.1 data.getXValCount() is no longer present. You can instead use data.getXMax() + 1 instead.