0

In my app I have a custom View which extends SurfaceView class. I need to pass it to another thread but after findViewById() it's still null. My code:

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

// Widgets
LinearLayout channelCheckboxesLinearLayout;
Spinner channelsSpinner;
Button showButton, removeButton, saveToPdfButton;
ProgressBar progressBar;
TextView progressBarTextView;

SurfaceViewToDraw surfaceViewToDraw;

public static ArrayList<Integer>[] channelsArrayList;
public static boolean asyncTaskFinished = false;
HashSet<Integer> currentlyDisplayedChannels;
Integer selectedChannel;

final String LOG_TAG = "ChannelCheck";

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    channelCheckboxesLinearLayout = findViewById(R.id.channels_checkboxes_linear_layout);
    channelsSpinner = findViewById(R.id.spinner_channels);
    showButton = findViewById(R.id.show_chart);
    showButton.setOnClickListener(this);
    removeButton = findViewById(R.id.remove_chart);
    removeButton.setOnClickListener(this);
    saveToPdfButton = findViewById(R.id.savetopdf_button);
    saveToPdfButton.setOnClickListener(this);
    progressBar = findViewById(R.id.progress_bar);
    progressBarTextView = findViewById(R.id.progress_bar_textview);
    surfaceViewToDraw = findViewById(R.id.surface_view_to_draw);

    currentlyDisplayedChannels = new HashSet<>();

    channelsArrayList = new ArrayList[12];
    for (int i = 0; i < 12; i++) {
        channelsArrayList[i] = new ArrayList<>();
    }

    readFile();

    final Integer[] channelNums = new Integer[]{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12};
    ArrayAdapter<Integer> adapter = new ArrayAdapter<>(this, android.R.layout.simple_spinner_item, channelNums);
    channelsSpinner.setAdapter(adapter);
}

@Override
public void onClick(View v) {
    int id = v.getId();
    if (id == R.id.show_chart) {
    }
}


private void readFile() {
    new ReadFromFileAsyncTask(progressBar, progressBarTextView, showButton, getBaseContext(), surfaceViewToDraw).execute();
    if (asyncTaskFinished) {
        showButton.setEnabled(true);
    }
}

private void permissionRequest() {
    if (ContextCompat.checkSelfPermission(getBaseContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE)
            != PackageManager.PERMISSION_GRANTED) {
        String[] permissions = {Manifest.permission.WRITE_EXTERNAL_STORAGE};
        if (android.os.Build.VERSION.SDK_INT > 23)
            requestPermissions(permissions, 0);
    }
}

}

activity_main.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
tools:context=".MainActivity"
android:layout_height="match_parent">
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    >

    <LinearLayout
        android:id="@+id/channels_checkboxes_linear_layout"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:gravity="center_vertical"
        android:layout_marginRight="10dp"
        android:layout_marginLeft="10dp"
        android:layout_weight="1">

        <TextView
            android:text="@string/channels"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <Spinner
            android:id="@+id/spinner_channels"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp">

        </Spinner>

        <Button
            android:id="@+id/show_chart"
            android:text="show"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

        <Button
            android:id="@+id/remove_chart"
            android:text="remove"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content" />

    </LinearLayout>

    <pl.an.pietras.ecgreader.SurfaceViewToDraw
        android:id="@+id/surface_view_to_draw"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_weight="23" />

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical"
        android:layout_marginRight="10dp"
        android:layout_marginLeft="10dp"
        android:layout_weight="1">

        <Button
            android:id="@+id/savetopdf_button"
            android:text="save to pdf"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

    </LinearLayout>

</LinearLayout>
<RelativeLayout
    android:id="@+id/relative_progress_bar"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ProgressBar
        android:id="@+id/progress_bar"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_centerInParent="true"
        android:layout_gravity="center"/>

    <TextView
        android:id="@+id/progress_bar_textview"
        android:text="Reading file"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="10dp"
        android:layout_above="@+id/progress_bar"
        android:textColor="@color/colorAccent"
        android:layout_centerHorizontal="true"/>

</RelativeLayout>
</FrameLayout>

SurfaceViewToDraw class

public class SurfaceViewToDraw extends SurfaceView implements SurfaceHolder.Callback {

SurfaceHolder holder;
int height;
int width;
float mmToPx;
int[] channelsPositions;
Paint minorGridLinesPaint;
Paint majorGridLinesPaint;
Paint descriptionsPaint;
Paint referencePulsePaint;
Paint signalPaint;
int channels = 12;
final int descriptionsXPos = 15;
final int referencePulseXMargin = 5;
final int referencePulseYMargin = 5;
final float distanceBeetweenSamples;
final float mVtopx = 10 / 100 * mmToPx;
final float signalInitPosX = descriptionsXPos + 15;
float signalPosX;
float[] initPathsY;

public SurfaceViewToDraw(Context context, AttributeSet attrs) {
    super(context);
    holder = getHolder();
    holder.addCallback(this);
    mmToPx = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_MM, 1, getResources().getDisplayMetrics());
    distanceBeetweenSamples = 25 / 128 * mmToPx;
    minorGridLinesPaint = new Paint();
    minorGridLinesPaint.setColor(Color.parseColor("#9c9c9c"));

    majorGridLinesPaint = new Paint();
    majorGridLinesPaint.setColor(Color.parseColor("#595959"));

    descriptionsPaint = new Paint();
    descriptionsPaint.setColor(Color.BLACK);
    descriptionsPaint.setTextSize(20);
    descriptionsPaint.setStrokeWidth(2);

    referencePulsePaint = new Paint();
    referencePulsePaint.setColor(Color.parseColor("#cc0000"));
    referencePulsePaint.setStyle(Paint.Style.STROKE);
    referencePulsePaint.setStrokeWidth(3);

    signalPaint = new Paint();
    signalPaint.setColor(Color.BLACK);
    signalPaint.setStrokeWidth(3);
    signalPaint.setStyle(Paint.Style.STROKE);
}

@Override
public void surfaceCreated(SurfaceHolder holder) {
    height = getHeight();
    width = getWidth();

    setChannelsPositions(channels);
    Canvas canvas = getHolder().lockCanvas();
    canvas.drawARGB(255, 255, 179, 102);
    drawGridlines(canvas);
    drawDescriptions(canvas);
    canvas.drawPath(drawReferencePulse(), referencePulsePaint);
    getHolder().unlockCanvasAndPost(canvas);
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {

}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {

}

private void drawGridlines(Canvas canvas) {
    float gridLine = 0;
    int i = 0;
    // Drawing horizontal lines
    while (gridLine < height) {
        i++;
        gridLine += mmToPx;
        if (!(i % 5 == 0)) {
            canvas.drawLine(0, gridLine, width, gridLine, minorGridLinesPaint);
        } else {
            canvas.drawLine(0, gridLine, width, gridLine, majorGridLinesPaint);
        }
    }

    gridLine = 0;
    i = 0;
    // Drawing vertical lines
    while (gridLine < width) {
        i++;
        gridLine += mmToPx;
        if (!(i % 5 == 0)) {
            canvas.drawLine(gridLine, 0, gridLine, height, minorGridLinesPaint);
        } else {
            canvas.drawLine(gridLine, 0, gridLine, height, majorGridLinesPaint);
        }
    }
}

public void setChannelsPositions(int channels) {
    int distanceBeetwenChannels = height / channels;
    int initPos = distanceBeetwenChannels / 2;
    channelsPositions = new int[channels];
    for (int i = 0; i < channels; i++) {
        channelsPositions[i] = initPos + i * distanceBeetwenChannels;
    }
}

public void doDraw() {
    Canvas canvas = getHolder().lockCanvas();
    canvas.drawARGB(255, 255, 179, 102);
    drawGridlines(canvas);
    drawDescriptions(canvas);
    canvas.drawPath(drawReferencePulse(), referencePulsePaint);
    drawPath(canvas);
    getHolder().unlockCanvasAndPost(canvas);
}

public void drawDescriptions(Canvas canvas) {
    for (int i = 0; i < channels; i++) {
        canvas.drawText(String.valueOf(i), descriptionsXPos, channelsPositions[i], descriptionsPaint);
    }
}

public Path drawReferencePulse() {
    Path path = new Path();
    path.moveTo(referencePulseXMargin, height - referencePulseYMargin);
    path.lineTo(referencePulseXMargin + 5, height - referencePulseYMargin);
    path.lineTo(referencePulseXMargin +5, height - referencePulseYMargin - mmToPx * 10);
    path.lineTo(referencePulseXMargin + mmToPx * 5, height - referencePulseYMargin - mmToPx *10);
    path.lineTo(referencePulseXMargin + mmToPx * 5, height -referencePulseYMargin);
    path.lineTo(referencePulseXMargin + mmToPx * 5 + 5, height - referencePulseYMargin);
    return path;
}

private void drawPath(Canvas canvas) {
    signalPosX = signalInitPosX;
    Path[] signalPaths = new Path[channels];
    for (int i = 0; i < channels; i++) {
        signalPaths[i] = new Path();
    }

    initPathsY(signalPaths, canvas);
    drawPaths(signalPaths, canvas);
}

private void initPathsY(Path[] signalPaths, Canvas canvas) {
    initPathsY = new float[channels];
    for (int i = 0; i < channels; i++) {
        initPathsY[i] = channelsPositions[i] - channelsArrayList[i].get(0);
        signalPaths[i].moveTo(signalInitPosX, initPathsY[i]);
        Log.d("SurfaceViewToDraw", "" + initPathsY[i]);
    }
}

private void drawPaths(Path[] signalPaths, Canvas canvas) {
    int samples = channelsArrayList[0].size();
    for (int i = 1; i < samples; i++) {
        signalPosX += distanceBeetweenSamples;
        for (int j = 0; j < channels; j++) {
            signalPaths[i].lineTo(signalPosX, channelsArrayList[j].get(i));
        }

    }
    for (int i = 0; i < channels; i++) {
        canvas.drawPath(signalPaths[i], signalPaint);
    }
}

}

After surfaceViewToDraw = findViewById(R.id.surface_view_to_draw); the surfaceViewToDraw is still null and I don't know why. Can someone tell me what's wrong with my code?

Thanks.

Piotr
  • 71
  • 12

0 Answers0