Android send data from TCP thread to different Activities using Handlers - android

I have a MainActivity the default start up Activity which creates a TCP worker thread.
This TCP thread receives some data from the server and passes it to the current Activity on display say there are two more Activities called Activity1 and Activity2 which will display the received data.
How do i achive this using Handlers ?
Here is a outline of what I have...please suggest solution or change everything if I am completely wrong.
public class MainActivity extends Activity
{
public static TCPFunctions tcp = null;
public static Handler handler;
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
handler = new Handler();
tcp = new TCPFunctions(this, handler);
tcp.start();
}
}
----------------------------------------TCP Thread Class---------------------------------
public class TCPFunctions extends Thread
{
public Handler handler;
//socket and io streams are here and they work properly
Public TCPFunctions(MainActivity main, Handler _handler)
{
this.main = main;
handler = _handler;
}
public void run()
{
Intent showActivity1 = new Intent(main, Activity1.class);
main.startActivity(showActivity1);
while(true)
{
directories = new Vector<String>();
directories = (Vector<String>) inputStream.readObject();
Message msg = Message.obtain();
msg.obj = directories;
handler.sendMessage(msg);
directories = null;
}
}
}
now say in Activity1 I want this directories object...
Lets say my Activity1 has a button which when pressed sends a request to the server to get the directories object...which is received by the TCP thread...now how do I get this in Activity1 and update the UI...
Basically the directories object is a Vetor of Strings and I want to display the strings on a ListView contained in the Activity1/Activity2
public class Activity1 extends Activity implements OnClickListener,OnItemClickListener
{
private ListView directoryList;
private Button rootButton;
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.fileexplorer);
directoryList = (ListView) findViewById(R.id.directories);
rootButton.setOnClickListener(this);
directoryList.setOnItemClickListener(this);
}
public void onClick(View v)
{
switch(v.getId())
{
case R.id.root_button:
Log.d(TAG, "FileExplorer: Root Button Pressed");
//request for directories made here
break;
}
}
// What should be the Handler code to get the directories ?
}

First: The handler executes runnables and handles messages in the thread that created it. So if you want Activity1 to react to data from TCPFunctions, you have two options. Either:
-MainActivity, which created the handler in your current code, needs to react to the message, get the data, and send it along to Activity1
-Or Activity1 needs to be the one to create the handler.
In either case, the core answer to your question of how to react to a sent message, is that you need to override the handleMessage() method by subclassing the handler. Here's a boilerplate snippet you can use (pulled from one of the sample apps on the Android developer website)
mUpdateHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
String chatLine = msg.getData().getString("msg");
addChatLine(chatLine);
}
};

Related

Get variable from MainActivity in OnHandleIntent

I´m pretty new in android. I have made communication between two Apps with BroadcastReceiver and intentServices .
The thing is, I want to send information to the app2 from app1. In app1 I need to access a variable which is in MainActivity.class , I need to send it to servicev.class (the service where the intent is handled) but the variable "res" is null when I access it, why does that happen? (App2 calls app1 onHandleIntent and it breaks in res.getOtp() ) I try to create an extra setter getter class and also an intent but getIntent() does not work inside onHandleIntent... how can I achieve to pass res.getOTP (string) ? I really dont want to use SQLite
servicev:
public class servicev extends IntentService {
private static final int RESULT_OK = 1;
protected ResultReceiver mReceiver;
public servicev() {
super("yeah");
}
#Override
protected void onHandleIntent(Intent intent) {
//I receive here the intent from app2 and I need to response with res.getOTP()
helper h = new helper();
String val = intent.getStringExtra("foo");
Intent in = new Intent("com.banorte.bem.movil.veriToken.SendBroadcast");
in.putExtra("resultCode", this.RESULT_OK);
in.putExtra("resultValue", "My Result Value. Passed in: " + h.getRes().getOtp()); //h here is null... setter and getter approach does not work... maybe sqlite could work but it is necesary?
sendBroadcast(in);
}
}
MainActivity:
public class MainActivity extends AppCompatActivity {
VTTokenAPI api;
TextView textView;
Button button;
EditText input;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AndroidSetup.getInstance().init(this);
helper h = new helper();
api = new VTTokenAPI("FFFFFF");
res = api.getStatus();
res.getOtp(); //correct value
h.setRes(res);
setContentView(R.layout.activity_main);
}
}
helper:
public class helper {
public VTResult getRes() {
return res;
}
public void setRes(VTResult res) {
this.res = res;
}
VTResult res;
}
You are trying to instantiate a new MainActivity which is not the same as the running activity but a new instance.
If you need your IntentService to be able to get data from a running Activity you have options such as using SharedPreferences or SQLite. Instead of keeping the data in memory try to persist it in some database in the onCreate and then try to read it from the storage during handleIntent

How can I add more item to ListView through service?

public class MainActivity {
private MyListViewHelper mTimelineHelper;
#Override
protected void onCreate(Bundle savedInstanceState) {
mListViewHelper = new MyListViewHelper();
mListViewHelper.createListView();
startService(new Intent(this, MyService.class));
}
}
MyService class:
public class MyService extends Service {
private int mCount = 0;
public static final long NOTIFY_INTERVAL = 10 * 1000;
private static MyListViewHelper mListViewHelper;
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
// cancel if already existed
if (mTimer != null) {
mTimer.cancel();
} else {
// recreate new
mTimer = new Timer();
}
// schedule task
mTimer.scheduleAtFixedRate(new TimeDisplayTimerTask(), 0, NOTIFY_INTERVAL);
}
#Override
public void onDestroy() {
mTimer.cancel();
}
private class TimeDisplayTimerTask extends TimerTask implements LocationListener {
#Override
public void run() {
mHandler.post(new Runnable() {
#Override
public void run() {
//DO SOMETHING HERE
...........
mCount++;
if(mCount==4){
mListViewHelper = new MyListViewHelper()
mListViewHelper.addItemToList("ABCD");
}
}
});
public boolean isMainActivityRunning(string packageName) {
ActivityManager activityManager = (ActivityManager)getSystemService (Context.ACTIVITY_SERVICE);
List<RunningTaskInfo> tasksInfo = activityManager.getRunningTasks(Integer.MAX_VALUE);
for (int i = 0; i < tasksInfo.size(); i++) {
if(tasksInfo.get(i).baseActivity.getPackageName.toString().equals(packageName)
return true;
}
return false;
}
}
}
MyListViewHelper class:
public class MyListViewHelper {
private ListView mListView;
private ArrayList<String> mArrayList;
public MyListViewHelper () {
}
public void createListView(){
mArrayList = new ArrayList<String>();
mListView = (ListView) activity.findViewById(R.id.listView1);
// I make a short version,so we suppose adapter is already prepared here
mListView.setadapter(adapter);
}
public void addItemToList(String myString){
mArrayList.add(myString);
adapter.notifiDateSetChanged();
}
}
What I want is for every 10 seconds, service will do something, and then if it do that 4 times, I will add one item to ListView. I forgot to save logcat before change it back to the time before I edited, so there is no logcat, sorry for that. But I'm pretty sure there is nothing wrong with others and the problem is just somewhere in the code above since I'm leanring Android and I don't have much knowledge about Service. Please teach me to fix that!
You could use EventBus to tell your Activity that the Service is updating the list.
For example...
Your Activity:
public void onEventMainThread(ListUpdateEvent event) {
mList.add(event.getValue());
mAdapter.notifyDataSetChanged();
}
Your Service:
EventBus.getDefault().post(new ListUpdateEvent("Value to add"));
ListUpdateEvent is a simple POJO that lets you share data. Using onEventMainThread allows you to automatically protect the list from being updated on a background thread.
Here is info about how to send messages from services to activity components. So you just need to send data about new list item.
Have you tried changing adapter.notifiDateSetChanged(); to adapter.notifyDataSetChanged();
And by the way, the best way to update your activity via service is to register a broadcast receiver in your activity's onResume() and send a broadcast from your service when you want to update the activity and put your data as an extra. Don't forget to unregister() your receiver in onPause() and to declare your service in the Manifest.
You can read more about data flow from service via broadcast to activity here http://www.truiton.com/2014/09/android-service-broadcastreceiver-example/
You can't. It is not possible to update UI components in an Activity from a Service. Or, if you'd find a way to do that, I would say it is a bad idea*.
I think the EventBus implementation of Knosses is a good idea. I would like to suggest an implementation using a database, Loaders and Broadcasts.
The Activity with the ListView would use a CursorLoader to get the list content from the data source. The Service would add the items to the database each NOTIFY_INTERVAL and send out a Broadcast. The Activity would register a BroadcastReceiver that listens to the Broadcasts send by the Service, on receiving a Broadcast in the Activity, call getLoaderManager().restartLoader(), so the content in the ListView will refresh.
Edit:
* Let me elaborate a bit on that; as you can also bind a Service to your Activity. In that case, it is perfectly valid to update a UI component through the binding.

pause an activity meanwhile another one is running

I would like to get voice recognition using just one method.
In order to do that i've created 3 classes
the main class
public class Index extends Activity {
private Button boton;
private EditText texto;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_index);
boton = (Button)findViewById(R.id.boton);
texto = (EditText) findViewById(R.id.texto);
boton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View arg0) {
texto.setText(IVRecognition.getInstancia().getComando(Index.this));
}
});
}
}
the intermediate
public class IVRecognition {
//*******************singleton********************
private static IVRecognition instancia;
private IVRecognition (){}
public static IVRecognition getInstancia(){
if (instancia==null) instancia = new IVRecognition();
return instancia;
}
//************************************************
public static String resultado = null;
public String getComando(Context content){
Intent intent = new Intent(content, VRecognition.class);
content.startActivity(intent);
//pause here untill VRecognition.onActivityResult is executed
return resultado;
}
}
and the recognition one
public class VRecognition extends Activity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
startRecognition();
}
public void startRecognition (){
Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
intent.putExtra(RecognizerIntent.EXTRA_CALLING_PACKAGE,this.getPackageName());
startActivityForResult(intent, 1 /*VOICE_RECOGNITION_REQUEST_CODE*/);
}
#Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode == 1 /*VOICE_RECOGNITION_REQUEST_CODE*/ && resultCode == RESULT_OK){
ArrayList<String> result = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
IVRecognition.getInstancia().resultado = result.get(0);
}
this.finish();
}
}
The problem is that when I call VRecognition activity using content.startActivity(intent); the execution of the aplication keeps on going, so the variable called resultado has null value until onActivityResult is executed, which results in a null return value.
Hope you can help me. Cheers
Ian's answer is good. But from your comment, I'd recommend using an IntentService and the BroadcastManager. That way you don't need the intermediate activity. You call the startService(intent) from any activity that wants the VR result (and implements BroadcastReceiver). Then the IntentService calls startActivityForResult(intent,1) and Broadcasts the result.
More info:
http://developer.android.com/training/run-background-service/index.html
It sounds like you want to pause execution until voice recognition is complete. You may want to rethink this; you're calling getComando() from your UI thread, so your application UI will be frozen until recognition is complete. In the (probably quite likely) event that recognition takes more than five seconds, the system will pop up an Application Not Responding dialog. (Also, since you're implementing getComando() by starting another activity within your process, blocking the UI thread in getComando() would prevent recognition from ever running.)
The right way to do this is to use a completion callback. For instance, you could create an IVRecognitionListener interface:
public interface IVRecognitionListener {
public void onRecognitionComplete(String resultado);
}
and pass an instance of that to getComando(). Then instead of just setting IVRecognition.resultado in onActivityResult(), you could call onRecognitionComplete() to notify the caller of the result.

Android - Calling an ordinary object method from an activity

First, I am an android rookie, so my solution ways can be found awkward, and i am open to suggestions.
I am trying to create a game manager object that handles all transitions between activities. And my purpose is that while in an activity, menuOut method will call the changeActivity method of GameManager object with nextActivity argument and changeActivity will start that Activity. I am getting errors consistently, and did not find a solution.
Here is my source codes:
GameManager:
public class GameManager{
public SplashScreen splash = new SplashScreen();
public MainScreen main = new MainScreen();
public LoadingScreen load = new LoadingScreen();
Context tempContext;
public GameManager(Context base) {
super();
tempContext = base;
}
public void start(){
createScreens();
Intent intent = new Intent(tempContext, splash.getClass());
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
tempContext.startActivity(intent);
}
public void createScreens() {
//here is the method that i am trying to find a solution
((SplashScreen)splash.getContext()).setGameClass(this);
((MainScreen)main.getContext()).setGameClass(this);
((LoadingScreen)load.getContext()).setGameClass(this);
}
public void changeMenu(MenuType nextMenu, MenuType previousMenu){
Intent intent2;
switch(nextMenu){
case MAIN_SC:
tempContext = main.getContext();
intent2.setClass(tempContext, main.getClass());
intent2.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
tempContext.startActivity(intent2);
case GAME_LOADING_SC:
tempContext = load.getContext();
intent2.setClass(tempContext, load.getClass());
intent2.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
tempContext.startActivity(intent2);
default:
break;
}
}
}
And here is SplashScreen activity:
public class SplashScreen extends Activity {
public Context context = this;
public GameManager gameman;
private static final int SPLASH_DURATION = 4000;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
splash();
menuOut();
}
public Context getContext() {
return this;
}
public void splash() {
LinearLayout ll = new LinearLayout(this);
ll.setOrientation(LinearLayout.HORIZONTAL);
ll.setBackgroundResource(R.drawable.game_loop_splash);
setContentView(ll);
Handler handler = new Handler();
// run a thread after 2 seconds to start the home screen
handler.postDelayed(new Runnable() {
#Override
public void run() {
finish();
}
}, SPLASH_DURATION);
}
public void setGameClass(GameManager game){
gameman = game;
}
private void menuOut(){
gameman.changeMenu(MenuType.GAME_LOADING_SC, MenuType.GAME_SPLASH_SC);
this.onDestroy();
}
}
I can not return to the GameManager and call the changeMenu method.
I am very exhausted to get null pointer exceptions.
Any idea?
From what I read, you are trying to implement a singleton pattern. There are two ways I'd recommend to do that on android:
Extend the Application class, register your class in the manifest and use getApplication() in your activities to get access to it:
// In MyApplicationSubclass.java:
public final class MyApplicationSubclass extends Application {
/* ... */
public void myMethod() {
// insert some code here
}
/* ... */
}
// From your Activity:
((MyApplicationSubclass) this.getApplication()).myMethod();
Use a "normal" java singleton pattern, e.g. use a private constructor and keep one static instance within your GameManager class (this is the way the Android docs recommend, but I personally prefer the first way when having something that is logically bound to the Application).
Also, if you're only using your central class to do static stuff, you can just mark all its method as static and access them directly. Transfer Context objects as parameters to these methods, and you should be able to start activities without any static variables (which are sometimes hard to implement properly in Android, as your VM might get restarted from time to time).

Whats wrong with my Thread()-code?

I have a question regarding an Android application. I want to, later on, create a game and i am currently trying out classes and functions that I need to understand.
At the moment im trying to get a grip of how to use threads in a good way, but my application is "force closing" when i touch the button.
For this test application, all have on the screen is one TextView and one button.
The button is calling threadStart() when pressed. (onClick in xml)
And what i want it to do is to create a thread which increases the variable value by 1 and then report to the UI thread which then update the textview with the new value.
Can someone see what i am doing wrong with this small pice of code?
package com.weldeborn.tc;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.widget.TextView;
public class ThreadCounter extends Activity {
TextView txtCounter1;
int value=0;
final Handler mHandler = new Handler();
final Runnable mUpdateResults = new Runnable() {
public void run() {
updateResult();
}
};
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
txtCounter1 = (TextView) findViewById(R.id.counter1);
}
protected void threadStart() {
Thread t = new Thread() {
public void run() {
doSomething();
mHandler.post(mUpdateResults);
}
};
t.start();
}
private void doSomething() {
value = value+1;
}
private void updateResult() {
txtCounter1.setText(value);
}
}
My code is based on an example from Android Developer: The Common Tasks and how to do them section under the "Handling Expensive Operations in the UI Thread" heading.
I am thankful for any help.
setText doesn't work correctly when you pass an integer, directly. Try converting it to String before:
txtCounter1.setText(String.valueOf(value));
Also, check this answer about the usage of threads that need to update the UI.
if threadStart is your onClick the signature needs to be
public void threadStart(View v)

Categories

Resources