I am trying to create a Java Android application to print with a Bluetooth printer (Start sm 300 ti).
The code looks something like:
Thread t = new Thread() {
#RequiresApi(api = Build.VERSION_CODES.O)
public void run() {
OutputStream os = bluetoothSocket.getOutputStream();
os.write(something1);
os.write(something1);
....
//close os
os.close();
....
}
The problem is that I need to know when OutputStream finished the print(os.write function ) job, because some data don't arrive at the Bluetooth Printer (for example, if I print a bitmap image)
Currently, I added a sleep function before os.close().
Related
I have been stuck with one problem. I need some people which check a part of my code and help me with problem and critize my code (I write code but I haven't people which can say this is wrong or something in this pattern)
Generally.
My service get message from bluetooth (HC-05) and I can see values in Log.d, in service.
A part code of my service which get message.
private class ConnectedThread extends Thread{
private final BluetoothSocket bluetoothSocket;
private final InputStream inputStream;
private final OutputStream outputStream;
public ConnectedThread(BluetoothSocket socket){
Log.d(TAG,"ConnectedThread: Starting");
bluetoothSocket=socket;
InputStream tmpInput = null;
OutputStream tmpOutput = null;
try{
tmpInput = bluetoothSocket.getInputStream();
tmpOutput = bluetoothSocket.getOutputStream();
}catch (IOException e){
e.printStackTrace();
active=false;
}
inputStream=tmpInput;
outputStream=tmpOutput;
}
#Override
public void run() {
byte[] buffer = new byte[1024];
int bytes;
while(active){
try {
bytes = inputStream.read(buffer);
final String comingMsg = new String(buffer,0,bytes);
Log.d(TAG,"InputStream: " + comingMsg);
new Handler(Looper.getMainLooper()).post(new Runnable() {
#Override
public void run() {
Message message = new Message();
message.obj = comingMsg;
message.what = 1; // I need it to prevent NullObjReference
Log.d(TAG,"Handler run(): " + message.obj);
mHandler.sendMessage(message);
}
});
}catch (IOException e){
Log.e(TAG,"Write: Error reading input." + e.getMessage());
active=false;
break;
}
}
}
...some code is hidden because it is diploma thesis
}
The problem is get message every time from this service to another activity where all is happen.
I tried a lot of things (with Threads,Looper,runOnUiThread, handleMessage and callback), checked a lot of posts in stackoverflow and I tried to combine with my project but all time I had nullobjectreference (for that i tried to use msg.what to check) , black screen when tried to move to my home activity (it is main) and update my textView or typical crash app.
Now I want only to get message from service to textview. When everything starts working fine, I want to parse string (for example 3 first chars) and send message to one of six textviews.
A part of codes from onCreate before method runThread() is started:
Log.d(TAG,"Check intent - result");
if(getIntent().getIntExtra("result",0)==RESULT_OK){
mDevice = getIntent().getExtras().getParcelable("bonded device");
startConnection(mDevice,MY_UUID);
Log.d(TAG,"Check is active service ");
checkIfActive();;
}
Log.d(TAG,"Check intent - connect_to_paired");
if(getIntent().getIntExtra("connect_to_paired",0)==RESULT_OK){
mDevice = getIntent().getExtras().getParcelable("bonded_paired_device");
startConnection(mDevice,MY_UUID);
Log.d(TAG,"Check is active service ");
checkIfActive();
}
public void checkIfActive(){
Log.d(TAG,"CheckIfActive: Started");
while(myBluetoothService.active!=true) {
Log.d(TAG,"CheckIfActive() active is "+ myBluetoothService.active);
if (myBluetoothService.active) {
Log.d(TAG, "CheckIfActive: Running method runOnUiThread - myBluetoothService.active is "+myBluetoothService.active);
runThread();
}
}
}
Method runThread() which should work everytime after connected with bluetooth device:
public void runThread(){
//I used there Thread but when connection was fail,
// method created multiply threads when I tried to connect next time
runOnUiThread(new Runnable() {
#Override
public void run() {
handler = new Handler(Looper.getMainLooper()){
#Override
public void handleMessage(Message msg) {
while (true) {
switch (msg.what) {
//when is one, service has messages to send
case 1:
String message = myBluetoothService.mHandler.obtainMessage().toString();
rearLeft.setText(message);
break;
default:
super.handleMessage(msg);
}
}
}
};
}
});
}
UPDATE:
Is it good idea ? Maybe I can put JSON Object to service to send message and in the HomeActivity, I can try get values from JSON. Is it fast ? I send a lot of data, because bluetooth receive data of distance from 4 ultrasound sensors in 4 times in lasts until few milliseconds, everytime.
Here is screen how sees my data in service when I have debug logs.
Next idea, but still nothing:
HomeActivity (my main)
public void runThread(){
runOnUiThread(new Runnable() {
#Override
public void run() {
//Looper.prepare();
new Handler() {
#Override
public void handleMessage(Message msg) {
rearLeft.setText(msg.obj.toString());
}
};
//Looper.loop();
//Log.d(TAG, myBluetoothService.mHandler.getLooper().toString());
//rearLeft.setText(myBluetoothService.mHandler.getLooper().toString());
}
});
}
Service which should send data from bluetooth to UI Thread is the same (Check first code).
Screen from HomeActivity where you can see 6 text views. Now I want put all text to one view which will be refresh by get next message.
Ok this post a bit help me to solve problem:
Sending a simple message from Service to Activity
Maybe this link could help another people.
Thanks for help, now understand why i should use broadcast receiver to do this.
I'm new to Android and I want to copy a big file (approx. 2GB) chosen by the user(so I guess it should have permissions by default) to the internal memory. I already have the permissions added in AndroidManifest but I don't know how (and if I need to) use the Android FileProivder. I would also like to know how this process can happen on another thread such that the app is not blocked during the process and it can show the progress.
You could use a foreground service to do this and make sure the process doesn't get interrupted.
Build the service:
public class CopyService extends Service {
#Override
public void onCreate() {
}
#Override
public int onStartCommand(final Intent intent, int flags, int startId) {
// Run the moving code here
return START_NOT_STICKY;
}
}
It's important that you launch it as a foreground service (add permission in manifest), so it doesn't get destroyed after some time. You'll be required to add a notification then, which you can use for progress.
Read further on services: https://developer.android.com/guide/components/services
As #blackapps pointed out it would be wise decision to check the permission and only start the service if it's granted. I usually check if the permission is granted, if not I request it, if it is I follow. Then I check for it once again so I can see if the user granted it or not.
Google has a great article on how to request permissions:
https://developer.android.com/training/permissions/requesting
How to move the file though? Here is the code I use in my own app:
private static void moveFile(File from, File to) {
InputStream inputStream;
OutputStream outputStream;
try {
inputStream = new FileInputStream(from);
outputStream = new FileOutputStream(to);
byte[] buffer = new byte[1024];
while (inputStream.read(buffer) > 0) {
outputStream.write(buffer);
}
inputStream.close();
outputStream.close();
// You may wish not to do this if you want to keep the original file
from.delete();
Log.i(LOG_TAG, "File copied successfully");
} catch (IOException e) {
e.printStackTrace();
}
// Stop service here
}
The code you'd like to run inside the service should be placed inside onStartCommand()
Due to the breaking changes in Android WebRTC client's example, I'm looking for the code-example which shows how to add and work with DataChannel in Android. I need to just send "Hello Worlds" via DataChannel between 2 Android devices. Here's the old code:
https://chromium.googlesource.com/external/webrtc/stable/talk/+/master/examples/android/src/org/appspot/apprtc/AppRTCDemoActivity.java#177
It uses some classes and interfaces which don't exist in the new version anymore.
So how can I add support of DataChannel to my Android WebRTC application, send and receive a text through it?
I added DataChannel in a project with an older version of webrtc. I looked at the most up to date classes and it seems the methods and callbacks are still there, so hopefully it will work for you.
Changes to PeerConnectionClient:
Create DataChannel in createPeerConnectionInternal after isInitiator = false;:
DataChannel.Init dcInit = new DataChannel.Init();
dcInit.id = 1;
dataChannel = pc.createDataChannel("1", dcInit);;
dataChannel.registerObserver(new DcObserver());
Changes to onDataChannel:
#Override
public void onDataChannel(final DataChannel dc) {
Log.d(TAG, "onDataChannel");
executor.execute(new Runnable() {
#Override
public void run() {
dataChannel = dc;
String channelName = dataChannel.label();
dataChannel.registerObserver(new DcObserver());
}
});
}
Add the channel observer:
private class DcObserver implements DataChannel.Observer {
#Override
public void onMessage(final DataChannel.Buffer buffer) {
ByteBuffer data = buffer.data;
byte[] bytes = new byte[data.remaining()];
data.get(bytes);
final String command = new String(bytes);
executor.execute(new Runnable() {
public void run() {
events.onReceivedData(command);
}
});
}
#Override
public void onStateChange() {
Log.d(TAG, "DataChannel: onStateChange: " + dataChannel.state());
}
}
I added onReceivedDataevents to PeerConnectionEvents interface and all the events are implemented in the CallActivity so I handle the data received on the channel from there.
To send data, from CallActivity:
public void sendData(final String data) {
ByteBuffer buffer = ByteBuffer.wrap(data.getBytes());
peerConnectionClient.getPCDataChannel().send(new DataChannel.Buffer(buffer, false));
}
I only took a quick look at the new classes and made minor changes to my code, I hope it will work for you with no more changes.
Good luck
I'm sorry that I have a question to the code from Guy S.
In your code, there are two following statements in both createPeerConnectionInternal() and onDataChannel().
dataChannel.registerObserver(new DcObserver());
I think it may cause twice registrations. Is it correct??
I mean, before making a call, it created a dataChannal and registered an Observer. Then.. if there is a call comes in, the onDataChannel called, then the dataChannel point to dc and register again??
My application has a lot of optional data that can be downloaded so I decided to use a Service to handle all the downloads in the background, So I started learning it and here is where i got:
public class DownloadService extends IntentService{
public DownloadService() {
super("DownloadService");
}
#Override
protected void onHandleIntent(Intent intent) {
String URL=intent.getStringExtra("DownloadService_URL");
String FileName=intent.getStringExtra("DownloadService_FILENAME");
String Path=intent.getStringExtra("DownloadService_PATH");
try{
URL url = new URL(URL);
URLConnection conexion = url.openConnection();
conexion.connect();
InputStream input = new BufferedInputStream(url.openStream());
OutputStream output = new FileOutputStream(Path+FileName);
byte data[] = new byte[1024];
int count = 0;
while ((count = input.read(data)) != -1) {
output.write(data);
}
output.flush();
output.close();
input.close();
}
catch(Exception e){ }
}
}
The code from the main activity:
Intent ServiceIntent = new Intent(this,DownloadService.class);
ServiceIntent.putExtra("DownloadService_URL", "the url...");
ServiceIntent.putExtra("DownloadService_FILENAME", "Test1.rar");
ServiceIntent.putExtra("DownloadService_PATH", "/sdcard/test/");
startService(ServiceIntent);
Is the code used to download the files correct? Am I using the Service correctly?
I want to download a lot of files.. So should I startService for each different URL?
I would like to inform the user of the percentage done.. But the Service doesnt have a UI. Should I do that in the notification bar?
Thanks.
Is the code used to download the files correct?
I don't like the use of concatenation to create fully-qualified file paths (use the appropriate File constructor). Catching exceptions and not doing anything with them is a really bad idea. On Android 2.3 and higher, you should consider using DownloadManager.
Otherwise, it's probably OK for basic stuff.
I want to download a lot of files.. So should I startService for each different URL?
That should work fine. Note that they will be downloaded one at a time, as IntentService has only one background thread.
I would like to inform the user of the percentage done.. But the Service doesnt have a UI. Should I do that in the notification bar?
That would be one solution. A variation on that would be to have the service send an ordered broadcast, to be picked up by your activity if it is still on-screen or by a BroadcastReceiver that would do the Notification. Here is a blog post with more on that, and here is a tiny sample application demonstrating the concept.
I am trying to create a Java Client-Server Program, where the Server is running on a Windows PC, and the Client is running on an Android 2.2 Phone.
The Connection is okay. Sending Data from the Phone to the PC works also fine.
Just receiving Data on the Phone crashes the program.
I am using DataInputStream and DataOutputStream to read/write through the Socket.
//Thread on the Phone
public void run() {
while (RUN) {
if (socket != null && socket.isConnected()) {
try {
//Crash
String text = dis.readUTF();
myTextView.setText(text);
} catch (IOException ex) {
//ErrorHandling
}
}
}
}
I want to receive a String from the server and then show it in a TextView.
Any Ideas? I am already setting this permission:
<uses-permission android:name="android.permission.INTERNET" />
do i need any other permissions? Thanks.
you can't set text on your UI if you're not in the UI thread.
do this...
add:
Runnable showmessage = new Runnable() {
public void run() {
myTextView.setText(membervariabletext);
}
};
and from your thread, after the readUTF(), call "runOnUiThread(showmessage);"
I would ensure that your Data Input Stream is initiated correctly:
Socket s = new Socket(serverAddress, port);
DataInputStream dis = new DataInputStream(s.getInputStream());
Otherwise, here's a link for example code where someone uses InputStreamReader() and OutputStreamWriter() to make a server and client for Android.
https://thinkandroid.wordpress.com/2010/03/27/incorporating-socket-programming-into-your-applications/