Here is the problem:
private void doSomething() {
String[][] data = new String[h][w];
Message msg = null;
Thread t = new Thread() {
public void run() {
for(int i=0; i<max; i++) {
data = doLongCalculationOnBackground(i);
msg = messageHandler.obtainMessage();
msg.obj = data;
messageHandler.sendMessage(msg);
}
}
};
t.start();
}
private Handler messageHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
doUpdateUI(msg.obj); // error right here!!!
}
};
private doUpdateUI(String[][] data) {
// do update UI work.
}
Eclipse alerts that doUpdateUI(msg.obj) is not applicable for the arguments (Object).
So how can i obtain the string matrix sent by Message object? Please don't suggest me use Async Task.
I'm stupid, just cast argument msg.obj to String[][]:
doUpdateUI((String[][]) msg.obj);
Related
I use Looper.prepare and Looper.loop in Runnable's run function. But the problem is that the thread not loop at all, the Runnable just run one time. In Activity1, I use three Runnable threads, all looping. Two threads get Data and pictures from net constantly through "while" loop(needn't update UI), one thread select data and pic from local sqlite constantly through "Looper". The data is:
protected void onCreate(Bundle savedInstanceState) {
......
new Thread(getMessageTask).start();
getMessageHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
i++;
System.out.println("niuanmata" + i); //one appear the first one
try {
ArrayList<Map<String, String>> listMessages = (ArrayList<Map<String, String>>)msg.obj;
boolean listchange = true;
if (oldMessages.size() != 0) {
if (listMessages.size() == oldMessages.size()) {
for (int i = 0; i < listMessages.size(); i++) {
Map<String, String> oldmessage = (Map<String, String>) oldMessages.get(i);
Map<String, String> newmessage = (Map<String, String>) listMessages.get(i);
if ((oldmessage.get("mID") != newmessage.get("mID")) || (oldmessage.get("mainContent") != newmessage.get("mainContent")) || (oldmessage.get("deadLine") != newmessage.get("deadLine"))) {
break;
}
if (i == (listMessages.size() - 1)) {
listchange = false;
}
}
}
}
if (listchange) {
SimpleAdapter adapter = new SimpleAdapter(MainActivity.this, listMessages, R.layout.layout_invites,
new String[]{"mID", "creater", "mainContent", "deadLine", "mtype", "createrLogo"},
new int[]{R.id.tv_list_type, R.id.tv_list_name, R.id.tv_list_inviteword, R.id.tv_list_invitedate, R.id.tv_list_inviteid, R.id.iv_list_logo});
lvMessage.setAdapter(adapter);
oldMessages = listMessages;
}
} catch (Exception e) {
Toast.makeText(MainActivity.this, "wrong: " + e.toString(), Toast.LENGTH_SHORT).show();
return;
}
}
};
......
lvMessage.setOnItemClickListener(new AdapterView.OnItemClickListener(){
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) { //when creater click, update the message; when others click, reset the alarm
Toast.makeText(MainActivity.this, "ok" , Toast.LENGTH_SHORT).show();
}
});
}
.........
Runnable synchroDataTask = new Runnable() {
#Override
public synchronized void run() {
//data syschno
while (IOHelper.loopjudge()) {
{
AccountsDB adb = new AccountsDB(MainActivity.this);
String thelastupdate = adb.getLastUpdate(account.getChatNO());
Calendar calendar = IOHelper.StringToCalendar(thelastupdate);
calendar.add(Calendar.MINUTE, -30);
String accountData = synchroDataWebservice(account.getChatNO(), IOHelper.CalendarToString(calendar)); //get the datas of the account synchroly
AccountBLL.saveDBofWebString(accountData, MainActivity.this, account); //use static method to save the DB string as SQLite data
}
}
.........
#Override
public synchronized void run() {
while (IOHelper.loopjudge()) {
......
}
.......
Runnable getMessageTask = new Runnable() {
#Override
public synchronized void run() {
Looper.prepare();
//while (IOHelper.loopjudge() && (!stopThread)) {
MessageDB messagedb = new MessageDB(MainActivity.this);
List<MessageMain> messages = messagedb.getMessageByChatNO(account.getChatNO());
ArrayList<Map<String, String>> listMessages = setMessaageListToMap(messages);
Message msg = Message.obtain();
msg.obj = listMessages;
getMessageHandler.sendMessageDelayed(msg, 1000);
//}
Looper.loop();
}
};
......
In my limited experience with android, I use while to do the Loop in getMessageTask , because the data and UI's listview need to be updated constantly. But the listview can not be clicked. Then change to Looper, but the the UI's listview can't be updated constantly....
The answer is that I misunderstand the meaning of Looper, think the Looper.prepare() and Looper.loop() as the while() loop, then make the mistake.
Looper.prepare() and Looper.loop() just means that this thread can be looped, but I must write while loop or for loop by myself.
I have a String variable, and I set it's value inside a thread, since it's using a netwok operation.
How can I access the values stored in the Strings?
public class HomeActivity extends AppCompatActivity {
// Initialize AWS DynamoDB Client
public static AmazonDynamoDBClient ddbClient;
public static DynamoDBMapper mapper;
public static Aqua aqua;
// App details
public static String a = "A";
public static String b;
public static Boolean c;
public static String d;
public static String e;
public static String f;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
// Initialize the Amazon Cognito credentials provider
CognitoCachingCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider(
getApplicationContext(),
"******", // Identity Pool ID
Regions.**** // Region
);
// Initialize AWS DynamoDB
ddbClient = new AmazonDynamoDBClient(credentialsProvider);
mapper = new DynamoDBMapper(ddbClient);
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
try {
// Get app details
aqua = mapper.load(Aqua.class, a);
b = aqua.getB();
c = aqua.getC();
d = aqua.getD();
e = aqua.getE();
f = aqua.getF();
} catch (Exception e) {
Log.e("error", e.getMessage());
}
}
});
thread.start();
}
}
Use ExecutorService and submit Callable (below assumes you want the data that is stored inside b,c,d,e,f):
ExecutorService exec = Executors.newSingleThreadExecutor();
Future<String[]> future = exec.submit(new Callable<String[]>() {
#Override
public String[] call() {
try {
// Get app details
aqua = mapper.load(Aqua.class, a);
b = aqua.getB();
c = aqua.getC();
d = aqua.getD();
e = aqua.getE();
f = aqua.getF();
} catch (Exception e) {
Log.e("error", e.getMessage());
}
return new String[] {b, c, d, e, f};
}
});
// ... b will be at value[0], c at value[1]
String[] value = future.get();
Declare the string globally in your Activity/Fragment. This way you can acces it from everywhere.
You could also use handler.sendMessage(message); with your String as message to send it whenever your Thread has finished or whenever you want to. You can then retrieve your String int
protected Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
String status = (String) msg.obj;
Log.i("Got a new message", "MESSAGE: "+status);
}
};
Hope it helps :)
here is my hander:
public Handler handler = new Handler(){
#Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
String mmsg = msg.getData().getByteArray("msg").toString();
Toast.makeText(clientActivity.this, mmsg,Toast.LENGTH_LONG).show();
}
};
I send data from separate thread:
public class client implements Runnable
{
private void showtoast(byte[] msgtoshow){
try {
Bundle mbundle = new Bundle();
Message greeting = new Message();
mbundle.putByteArray("msg", msgtoshow);
greeting.setData(mbundle);
handler.sendMessage(greeting);
}catch(Exception e){
Log.d("error",e.getMessage());
}
}
public void run()
{
msgstrng = "this is supposed to be some text";
showtoast(msgstrng.getBytes());
}
}
Instead of line that I send in msgstng I toast some [B#411dd11] which is always different. I guess it's timestamp or smth. how to get that String value msgstng?
Actually more important for me is to get bytes array, as I'll send bitmaps from socket to UI if i learn this issue
The problem seems to be the way you are getting the string in your Handler.
Try something like this:
String mmsg = new String(msg.getData().getByteArray("msg"));
I am having problems with updating the TextView, I used the Handler method to pass the message to the UI. My application receives data(type integers) true io stream and shows in TextView.
My Activity class looks like this:
public class DeviceView extends Activity {
TextView dataX;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.device_view);
dataX = (TextView) findViewById(R.id.datax);
handler = new Handler() {
#Override
public void handleMessage(Message msg) {
dataX.setText(String.valueOf(msg.arg1));
}
};
}
}
I also have a separate class it extends Thread:
public class IOThread extends Thread {
public void run() {
byte[] buffer = new byte[1024];
int data;
while (true) {
try {
data = in.read(buffer);
Message message= Message.obtain();
message.arg1= data;
DeviceView.handler.sendMessage(message);
} catch (IOException ex) {
break;
}
}
}
}
Do I have to make a separate variable type String and point it to variable data and at last calling the count? Would that be enough to update TextView?
Can you try using an interface. Let the Activity implement it, pass it to the IOThread class. Once you get the result, pass the result to the Activity.
Interface named InterfaceData
public void getData(int data);
public class DeviceView extends Activity implements InterfaceData{
TextView dataX;
Handler handler;
IOThread ioThread;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.device_view);
handler = new Handler();
ioThread = new IOThread(this);
dataX = (TextView) findViewById(R.id.datax);
}
#Override
public void getData(int data){
handler.postDelayed(new Runnable(){
public void run(){
dataX.setText(data);
};
},100);
}
}
> Thread class
public class IOThread extends Thread {
InterfaceData interfaceData;
public IOThread(InterfaceData interfaceData){
this.interfaceData = interfaceData;
}
public void run() {
byte[] buffer = new byte[1024];
int data;
while (true) {
try {
data = in.read(buffer);
interfaceData.getData(data);
} catch (IOException ex) {
break;
}
}
}
}
I have found my problem it was not the Handler issue. THe code i posted at the beginning is coorect. The problem lyis on the way i read the received bytes[] array from the InputStream. I have tested by sending an integer int numbers = (int) 2 and when print this receivd data in terminal in Android app, it receivs only 1, even if i send int 3 or 4, i stil receive 1.
So i preceiated your example code #dcanh121 , but my question is actualy how do i read properly the integers that the server sends?
public void run() {
byte[] buffer = new byte[1024];
int data;
while (true) {
try {
data = in.read(buffer);
Log.d(TAG + data, "test");
Message message = Message.obtain();
message.arg1 = data;
Log.d(TAG + message.arg1, "test");
DeviceView.handler.sendMessageDelayed(message, 100);
} catch (IOException ex) {
Log.e(TAG_IOThread, "disconnected", ex);
break;
}
}
}
I have written some code to do a httpGet and then return the JSON back to the main thread. Sometimes though the server is down and I want to report back to the main thread that the server is down but don't know how to do it properly using the handler.
My code looks like this:
public class httpGet implements Runnable {
private final Handler replyTo;
private final String url;
public httpGet(Handler replyTo, String url, String path, String params) {
this.replyTo = replyTo;
this.url = url;
}
#Override
public void run() {
try {
// do http stuff //
} catch (ClientProtocolException e) {
Log.e("Uh oh", e);
//how can I report back with the handler about the
//error so I can update the UI
}
}
}
Send a message to the handler, with some error code, for example:
Message msg = new Message();
Bundle data = new Bundle();
data.putString("Error", e.toString());
msg.setData(data);
replyTo.sendMessage(msg);
In the handler's handleMessage implementation handle this message.
The handler should look like this:
Handler handler = new Handler() {
#Override
public void handleMessage(Message msg) {
Bundle data = msg.getData();
if (data != null) {
String error = data.getString("Error");
if (error != null) {
// do what you want with it
}
}
}
};
#Override
public void run() {
try {
// do http stuff //
} catch (ClientProtocolException e) {
Log.e("Uh oh", e);
//how can I report back with the handler about the
//error so I can update the UI
// you can use handleMessage(Message msg)
handler.sendEmptyMessage(-1) <-- sample parameter
}
}
Get the Message from Runnable here,
Handler handler = new Handler() {
public void handleMessage(Message msg) {
if(msg.what == -1) {
// report here
}
}
};
Besides handler you can use runOnUiThread,
#Override
public void run() {
try {
// do http stuff //
} catch (ClientProtocolException e) {
Log.e("Uh oh", e);
//how can I report back with the handler about the
//error so I can update the UI
runOnUiThread(new Runnable() {
#Override
public void run() {
// report here
}
}
}
}