Search code examples
javaandroidarraylistcrashdialogfragment

Trouble accessing an ArrayList<String> from MainActivity in my DialogFragment


I need to be able to pass my ScannedDevicesListItemDialog.java class indexes from an ArrayList (ScannedDevicesArrayList) in my MainActivity.java class.

I tried creating a function (getScannedDevicesArrayList) in my MainActivity.java class for returning the ArrayList, and then calling that function in the onClick of my dialog. However while running the program, as soon as I click on an item in my dialog, the app crashes.

How can I reference this ArrayList from MainActivity.java in my dialog to be able to do something simple with it, such as printing an index of it to the console when clicking an item from the dialog?

MainActivity.java

package com.august.customtisensortagclient;

import android.Manifest;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.app.Dialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothManager;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanResult;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.AsyncTask;
import android.support.v4.app.DialogFragment;
import android.support.v4.app.Fragment;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.method.ScrollingMovementMethod;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;

import java.io.StringBufferInputStream;
import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {


    BluetoothManager mBluetoothManager;
    BluetoothAdapter mBluetoothAdapter;
    BluetoothLeScanner mBluetoothScanner;
    TextView console;
    Button clear_button;
    public ArrayList<String> scannedDevicesArrayList = new ArrayList<String>();
    int scannedDevicesArrayListTop = -1;
    private final static int REQUEST_ENABLE_BT = 1;
    private static final int PERMISSION_REQUEST_COARSE_LOCATION = 1;
    ArrayAdapter<String> myArrayAdapter;
    ListView list;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        console = (TextView) findViewById(R.id.Console);
        console.append("Console is working...\n");
        registerClearButton();




        // Functional code

        setupBluetooth();
        startScanning();
        registerScannedDevicesListCallback();

        // Test code


    }

    public void clearConsole(){
        console.setText("Console is working...\n");
        scannedDevicesArrayList.clear();
        myArrayAdapter.notifyDataSetChanged();
        scannedDevicesArrayListTop = -1;
    }

    private void registerScannedDevicesListCallback() {
        list = (ListView) findViewById(R.id.myListView);
        list.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                TextView textView = (TextView) view;
                DialogFragment newFragment = new ScannedDevicesListItemDialog();
                newFragment.show(getSupportFragmentManager(), "ScannedDevicesListItemDialog");

            }
        });
    }

    private void registerClearButton(){
        clear_button = (Button) findViewById(R.id.clear_button);
        clear_button.setOnClickListener(new View.OnClickListener() {
            public void onClick(View v) {
                clearConsole();
            }
        });
    }

    public void addDeviceToScannedDevicesList() {
        list = (ListView) findViewById(R.id.myListView);
        myArrayAdapter = new ArrayAdapter<String>(this,
                R.layout.my_list_view_items, scannedDevicesArrayList);
        list.setAdapter(myArrayAdapter);
    }

    public void setupBluetooth() {
        // Get BluetoothAdapter
        final BluetoothManager bluetoothManager =
                (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        mBluetoothAdapter = bluetoothManager.getAdapter();
        // Get BluetoothLeScanner
        mBluetoothScanner = mBluetoothAdapter.getBluetoothLeScanner();
        // Make sure Bluetooth is enabled
        if (mBluetoothAdapter != null && !mBluetoothAdapter.isEnabled()) {
            Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableIntent, REQUEST_ENABLE_BT);
        }
        // Make sure location is enabled
        if (this.checkSelfPermission(Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
            final AlertDialog.Builder builder = new AlertDialog.Builder(this);
            builder.setTitle("This app needs location access");
            builder.setMessage("Please grant location access so this app can detect peripherals.");
            builder.setPositiveButton(android.R.string.ok, null);
            builder.setOnDismissListener(new DialogInterface.OnDismissListener() {
                @Override
                public void onDismiss(DialogInterface dialog) {
                    requestPermissions(new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
                            PERMISSION_REQUEST_COARSE_LOCATION);
                }
            });
            builder.show();
        }
    }

    // Device scan callback.
    private ScanCallback leScanCallback = new ScanCallback() {
        @Override
        public void onScanResult(int callbackType, ScanResult result) {
            while (!scannedDevicesArrayList.contains(result.getDevice().getAddress()) && (result.getRssi() > -55)){
                    scannedDevicesArrayList.add(result.getDevice().getAddress());
                    scannedDevicesArrayListTop++;
                    addDeviceToScannedDevicesList();
                    console.append(Integer.toString(result.getRssi()));
            }
        }
    };

    public ArrayList<String> getScannedDevicesArrayList(){
        return scannedDevicesArrayList;
    }

    public int getScannedDevicesArrayListTop() {
        return scannedDevicesArrayListTop;
    }

    public void startScanning() {
        AsyncTask.execute(new Runnable() {
            @Override
            public void run() {
                mBluetoothScanner.startScan(leScanCallback);
            }
        });
    }

    public void stopScanning() {
        AsyncTask.execute(new Runnable() {
            @Override
            public void run() {
                mBluetoothScanner.stopScan(leScanCallback);
            }
        });
    }

    @Override
    public void onRequestPermissionsResult(int requestCode,
                                           String permissions[], int[] grantResults) {
        switch (requestCode) {
            case PERMISSION_REQUEST_COARSE_LOCATION: {
                if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                    System.out.println("coarse location permission granted");
                } else {
                    final AlertDialog.Builder builder = new AlertDialog.Builder(this);
                    builder.setTitle("Functionality limited");
                    builder.setMessage("Since location access has not been granted, " +
                            "this app will not be able to discover beacons when in the background.");
                    builder.setPositiveButton(android.R.string.ok, null);
                    builder.setOnDismissListener(new DialogInterface.OnDismissListener() {

                        @Override
                        public void onDismiss(DialogInterface dialog) {
                        }

                    });
                    builder.show();
                }
                return;
            }
        }
    }


}

ScannedDevicesListItemDialog.java

package com.august.customtisensortagclient;

import android.app.AlertDialog;
import android.app.Dialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.DialogFragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;

import java.util.ArrayList;


public class ScannedDevicesListItemDialog extends DialogFragment {


    String[] options = {"Left", "Right"};


    @Override
    public Dialog onCreateDialog(Bundle savedInstanceState) {
        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
        builder.setTitle("Connect as Left or Right?")
                .setItems(options, new DialogInterface.OnClickListener() {
                    public void onClick(DialogInterface dialog, int which) {
                        MainActivity mainActivity = new MainActivity();
                        ArrayList<String> thisScannedDevicesArrayList = mainActivity.getScannedDevicesArrayList();
                        ((MainActivity)getActivity()).console.setText("Worked");
                        ((MainActivity)getActivity()).console.setText(thisScannedDevicesArrayList.get(0));
                    }
                });
        return builder.create();
    }
}

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 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"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <RelativeLayout
        android:layout_width="match_parent"
        android:layout_height="0dp"
        tools:layout_editor_absoluteX="16dp"
        tools:layout_editor_absoluteY="0dp">

        <TextView
            android:id="@+id/Console"
            android:layout_width="272dp"
            android:layout_height="46dp"
            android:layout_alignParentBottom="true"
            android:layout_centerHorizontal="true"
            android:layout_marginBottom="200dp" />

        <ImageView
            android:id="@+id/imageView"
            android:layout_width="wrap_content"
            android:layout_height="70dp"
            android:layout_alignParentBottom="true"
            android:scaleType="fitCenter"
            app:srcCompat="@mipmap/gruneisen_logo" />

        <Button
            android:id="@+id/clear_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_alignParentBottom="true"
            android:layout_alignStart="@+id/Console"
            android:layout_marginBottom="131dp"
            android:text="CLEAR" />

        <ListView
            android:id="@+id/myListView"
            android:layout_width="match_parent"
            android:layout_height="379dp" />
    </RelativeLayout>
</android.support.constraint.ConstraintLayout>

my_list_view_items.xml

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:textSize="44sp">

</TextView>

Solution

  • MainActivity mainActivity = new MainActivity();
    

    is not how you access an Activity. It's not how you access an already-created class, either, but that's another issue.

    With that code, you're creating a new instance of MainActivity, not getting the one that currently exists. That means your ArrayList is null, because it was never initialized.

    To access your list, use the getActivity() function, which will get the instance of the Fragment's parent Activity, and cast it to MainActivity:

    MainActivity mainActivity = (MainActivity) getActivity();