Android Studio BLE:如何发送Charsequence接收在一个片段从串行到一个新的活动显示和绘图在应用



我是Android Studio的新手,刚刚学习了面向对象编程。我的项目需要我在开源代码上构建一些东西。我真的很纠结于这个特例。最初,一旦手机连接到BLE设备,手机将继续接收它发送的数据,并且数据将通过receiveText.append(TextUtil)由activity_main打印出来。toCaretString(msg, newline.length() != 0));在TerminalFragment。因此,我创建了一个新的recyclerview,将其添加到activity_main2中,并在TerminalFragment中创建了一个新的menuItem (R.id.plot),因此,当用户单击该menuItem时,它将引导他到activity_main2(同时数据继续流向手机)。我想接收(字节[]数据)在TerminalFragment也发送数据到activity_main2,并在activity_main2的recyclerview中打印出来。有人知道怎么做吗?最简单的方法是什么?感谢。

TerminalFragment

package de.kai_morich.simple_bluetooth_le_terminal;
import android.app.Activity;
import android.app.AlertDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.text.Editable;
import android.text.Spannable;
import android.text.SpannableStringBuilder;
import android.text.method.ScrollingMovementMethod;
import android.text.style.ForegroundColorSpan;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
import android.widget.EditText;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
public class TerminalFragment extends Fragment implements ServiceConnection, SerialListener {
private MenuItem menuItem;
private enum Connected { False, Pending, True }
private String deviceAddress;
private SerialService service;
private TextView receiveText;
private TextView sendText;
private TextUtil.HexWatcher hexWatcher;
private Connected connected = Connected.False;
private boolean initialStart = true;
private boolean hexEnabled = false;
private boolean pendingNewline = false;
private String newline = TextUtil.newline_crlf;
/*
* Lifecycle
*/
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
//Register with activity
// You must inform the system that your app bar fragment is participating in the population of the options menu.
// tells the system that your fragment would like to receive menu-related callbacks.
setRetainInstance(true);
deviceAddress = getArguments().getString("device");
}
@Override
public void onDestroy() {
if (connected != Connected.False)
disconnect();
getActivity().stopService(new Intent(getActivity(), SerialService.class));
super.onDestroy();
}
@Override
public void onStart() {
super.onStart();
if(service != null)
service.attach(this);
else
getActivity().startService(new Intent(getActivity(), SerialService.class)); // prevents service destroy on unbind from recreated activity caused by orientation change
}
@Override
public void onStop() {
if(service != null && !getActivity().isChangingConfigurations())
service.detach();
super.onStop();
}
@SuppressWarnings("deprecation") // onAttach(context) was added with API 23. onAttach(activity) works for all API versions
@Override
public void onAttach(@NonNull Activity activity) {
super.onAttach(activity);
getActivity().bindService(new Intent(getActivity(), SerialService.class), this, Context.BIND_AUTO_CREATE);
}
@Override
public void onDetach() {
try { getActivity().unbindService(this); } catch(Exception ignored) {}
super.onDetach();
}
@Override
public void onResume() {
super.onResume();
if(initialStart && service != null) {
initialStart = false;
getActivity().runOnUiThread(this::connect);
}
}
@Override
public void onServiceConnected(ComponentName name, IBinder binder) {
service = ((SerialService.SerialBinder) binder).getService();
service.attach(this);
if(initialStart && isResumed()) {
initialStart = false;
getActivity().runOnUiThread(this::connect);
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
service = null;
}
/*
* UI
*/
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_terminal, container, false);
receiveText = view.findViewById(R.id.receive_text);                          // TextView performance decreases with number of spans
receiveText.setTextColor(getResources().getColor(R.color.colorRecieveText)); // set as default color to reduce number of spans
receiveText.setMovementMethod(ScrollingMovementMethod.getInstance());
sendText = view.findViewById(R.id.send_text);
hexWatcher = new TextUtil.HexWatcher(sendText);
hexWatcher.enable(hexEnabled);
sendText.addTextChangedListener(hexWatcher);
sendText.setHint(hexEnabled ? "HEX mode" : "");
View sendBtn = view.findViewById(R.id.send_btn);
sendBtn.setOnClickListener(v -> send(sendText.getText().toString()));
return view;
}
@Override
public void onCreateOptionsMenu(@NonNull Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_terminal, menu);
menu.findItem(R.id.hex).setChecked(hexEnabled);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.clear) {
receiveText.setText("");
return true;
} if (id == R.id.plot){
Intent intent = new Intent(getActivity(), MainActivity2.class);
startActivity(intent);

return true;
}else if (id == R.id.newline) {
String[] newlineNames = getResources().getStringArray(R.array.newline_names);
String[] newlineValues = getResources().getStringArray(R.array.newline_values);
int pos = java.util.Arrays.asList(newlineValues).indexOf(newline);
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle("Newline");
builder.setSingleChoiceItems(newlineNames, pos, (dialog, item1) -> {
newline = newlineValues[item1];
dialog.dismiss();
});
builder.create().show();
return true;
} else if (id == R.id.hex) {
hexEnabled = !hexEnabled;
sendText.setText("");
hexWatcher.enable(hexEnabled);
sendText.setHint(hexEnabled ? "HEX mode" : "");
item.setChecked(hexEnabled);
return true;
} else {
return super.onOptionsItemSelected(item);
}
}
/*
* Serial + UI
*/
private void connect() {
try {
BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
BluetoothDevice device = bluetoothAdapter.getRemoteDevice(deviceAddress);
status("connecting...");
connected = Connected.Pending;
SerialSocket socket = new SerialSocket(getActivity().getApplicationContext(), device);
service.connect(socket);
} catch (Exception e) {
onSerialConnectError(e);
}
}
private void disconnect() {
connected = Connected.False;
service.disconnect();
}
private void send(String str) {
if(connected != Connected.True) {
Toast.makeText(getActivity(), "not connected", Toast.LENGTH_SHORT).show();
return;
}
try {
String msg;
byte[] data;
if(hexEnabled) {
StringBuilder sb = new StringBuilder();
TextUtil.toHexString(sb, TextUtil.fromHexString(str));
TextUtil.toHexString(sb, newline.getBytes());
msg = sb.toString();
data = TextUtil.fromHexString(msg);
} else {
msg = str;
data = (str + newline).getBytes();
}
SpannableStringBuilder spn = new SpannableStringBuilder(msg + 'n');
spn.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.colorSendText)), 0, spn.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
receiveText.append(spn);
service.write(data);
} catch (Exception e) {
onSerialIoError(e);
}
}
private void receive(byte[] data) {
if(hexEnabled) {
receiveText.append("Hello" + TextUtil.toHexString(data) + 'n');
} else {
String msg = new String(data);
if(newline.equals(TextUtil.newline_crlf) && msg.length() > 0) {
// don't show CR as ^M if directly before LF
msg = msg.replace(TextUtil.newline_crlf, TextUtil.newline_lf);
// special handling if CR and LF come in separate fragments
if (pendingNewline && msg.charAt(0) == 'n') {
Editable edt = receiveText.getEditableText();
if (edt != null && edt.length() > 1)
edt.replace(edt.length() - 2, edt.length(), "");
}
pendingNewline = msg.charAt(msg.length() - 1) == 'r';
}
receiveText.append(TextUtil.toCaretString(msg, newline.length() != 0)); //print out data
}
}
private void status(String str) {
SpannableStringBuilder spn = new SpannableStringBuilder(str + 'n');
spn.setSpan(new ForegroundColorSpan(getResources().getColor(R.color.colorStatusText)), 0, spn.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
receiveText.append(spn);
}
/*
* SerialListener
*/
@Override
public void onSerialConnect() {
status("connected");
connected = Connected.True;
}
@Override
public void onSerialConnectError(Exception e) {
status("connection failed: " + e.getMessage());
disconnect();
}
@Override
public void onSerialRead(byte[] data) {// receive data
receive(data); // send data to printout
}
@Override
public void onSerialIoError(Exception e) {
status("connection lost: " + e.getMessage());
disconnect();
}
}

activity_main2.xml(新活动接口)

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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=".MainActivity2">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar2"
android:layout_width="0dp"
android:layout_height="?attr/actionBarSize"
android:layout_marginStart="1dp"
android:layout_marginEnd="1dp"
android:background="?attr/colorPrimary"
android:theme="?attr/actionBarTheme"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<FrameLayout
android:id="@+id/plotframelayout"
android:layout_width="336dp"
android:layout_height="453dp"
android:layout_marginStart="16dp"
android:layout_marginTop="23dp"
android:layout_marginEnd="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/toolbar2">
</FrameLayout>
<FrameLayout
android:id="@+id/recyclerviewframelayout"
android:layout_width="339dp"
android:layout_height="172dp"
android:layout_marginStart="34dp"
android:layout_marginTop="14dp"
android:layout_marginEnd="34dp"
android:layout_marginBottom="13dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/plotframelayout">
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/dataflow"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

MainActivity2.java (new activity)

package de.kai_morich.simple_bluetooth_le_terminal;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.widget.Toast;
import java.util.ArrayList;
public class MainActivity2 extends AppCompatActivity {
Fragment CustomFragment;
private ArrayList<Data> dataList;
private RecyclerView recyclerView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main2);
Toolbar toolbar = findViewById(R.id.toolbar2);
setSupportActionBar(toolbar);
recyclerView = findViewById(R.id.dataflow);
dataList = new ArrayList<>();
receiveData();
setAdapter();
}
private void receiveData(){
dataList.add(new Data(""));
}
private void setAdapter() {
recyclerAdapter adapter = new recyclerAdapter(dataList);
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(getApplicationContext());
recyclerView.setLayoutManager(layoutManager);
recyclerView.setItemAnimator(new DefaultItemAnimator());
recyclerView.setAdapter(adapter);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.menu_plot, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.dataplot:
Toast.makeText(this, "dataplot", Toast.LENGTH_SHORT).show();
replaceFragment(new DataPlotFragment());
return true;
case R.id.fft:
Toast.makeText(this, "FFT", Toast.LENGTH_SHORT).show();
replaceFragment(new FftFragment());
return true;
case R.id.data:
Toast.makeText(this, "DATA", Toast.LENGTH_SHORT).show();
finish();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void replaceFragment(Fragment fragment){
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.plotframelayout,fragment);
fragmentTransaction.commit();
}

}

list_data

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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="wrap_content">
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="25dp"
android:layout_marginTop="20dp"
android:layout_marginBottom="20dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

recyclerAdapter

package de.kai_morich.simple_bluetooth_le_terminal;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.ArrayList;
import java.util.List;
public class recyclerAdapter extends RecyclerView.Adapter<recyclerAdapter.MyViewHolder>{
private ArrayList<Data> dataList;
public recyclerAdapter(ArrayList<Data> dataList){
this.dataList = dataList;
}
public class MyViewHolder extends RecyclerView.ViewHolder{
private TextView dataTxt;
public MyViewHolder(final View view){
super(view);
dataTxt = view.findViewById(R.id.textView2);
}
}
@NonNull
@Override
public recyclerAdapter.MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_data, parent, false);
return new MyViewHolder(itemView);
}
@Override
public void onBindViewHolder(@NonNull recyclerAdapter.MyViewHolder holder, int position) {
String data = dataList.get(position).getData();
holder.dataTxt.setText(data);
}
@Override
public int getItemCount() {
return dataList.size();
}

}

Data.java

package de.kai_morich.simple_bluetooth_le_terminal;
public class Data {
private String data;
public Data(String data) {
this.data = data;
}
public String getData() {
return data;
}
}

不确定这是否有效。我仍在尝试实现getExtra()部分。我修改了接收器()。如果你发现什么不合理的地方,请批评我。

TerminalFragment

private void receive(byte[] data) {
if(hexEnabled) {
receiveText.append("Hello" + TextUtil.toHexString(data) + 'n');
} else {
String msg = new String(data);
if(newline.equals(TextUtil.newline_crlf) && msg.length() > 0) {
// don't show CR as ^M if directly before LF
msg = msg.replace(TextUtil.newline_crlf, TextUtil.newline_lf);
// special handling if CR and LF come in separate fragments
if (pendingNewline && msg.charAt(0) == 'n') {
Editable edt = receiveText.getEditableText();
if (edt != null && edt.length() > 1)
edt.replace(edt.length() - 2, edt.length(), "");
}
pendingNewline = msg.charAt(msg.length() - 1) == 'r';
}
receiveText.append(TextUtil.toCaretString(msg, newline.length() != 0)); //print out data
output = receiveText.toString(); // CharSequence to String
Intent intent = new Intent(getActivity(), MainActivity2.class);
intent.putExtra("output",output); // send data to next activity, MainActivity2
}
}

最新更新