Get information of object in mainactivity from class - android

I would like to use the information of 'result' in the XMLRPCMethod. When the thread is finished the correct data is in the result object.
This is a code snipped from my OpenerpRPC.java class.
class XMLRPCMethod extends Thread {
private String method;
private Object[] params;
private Handler handler;
public Object result;
private OpenerpRpc callBack;
public XMLRPCMethod(String method, OpenerpRpc callBack) {
this.method = method;
this.callBack = callBack;
handler = new Handler();
}
public void call() {
call(null);
}
public void call(Object[] params) {;
this.params = params;
start();
}
#Override
public void run() {
try {
result = client.callEx(method, params);
handler.post(new Runnable() {
public void run() {
try {
callBack.resultcall(result);
} catch (XMLRPCException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
});
} catch (final XMLRPCFault e) {
handler.post(new Runnable() {
public void run() {
Log.d("Test", "error", e);
}
});
} catch (final XMLRPCException e) {
handler.post(new Runnable() {
public void run() {
Throwable couse = e.getCause();
if (couse instanceof HttpHostConnectException) {
Log.d(TAG, "error"+uri.getHost());
} else {
Log.d("Test", "error", e);
}
Log.d("Test", "error", e);
}
});
}
}
}
My result call in the OpenerpRpc class looks like:
public void resultcall(Object result) throws XMLRPCException{
allres=result;
if (rtype.equals("login")){
//Isn't impossible cast the result var with (String) because cause crash..why?
userid=""+result;
}
if (rtype.equals("read")){
//Isn't impossible cast the result var with (String) because cause crash..why?
// userid=""+result;
}
// name of callback function to use in parent class (MainActivity) for receive data
this.parent.oerpcRec(rtype,allres);
}
This is how i can receive the data in mainactivity
#SuppressWarnings("unchecked")
public void oerpcRec(String rtype,Object res) throws XMLRPCException{
if (rtype=="login"){
connector.setModel("res.users");
Object[] Ids = {Integer.parseInt(connector.userid)};
// set here the fields you wont loads
Object[] values={"name"};
connector.Read(Ids,values);
}
if(rtype=="read"){
Object[] ret=(Object[])res;
Map<String, Object> map1 = (Map<String, Object>) ret[0];
if(ret.length > 1){
}
}
}
But how can i get this information in my mainactivity? I only get the information of the login id value. When I put a breakpoint in the thread it only goes to the function resultcall when I try to login.
...
public void onClick(View v) {
try {
//here set user and pass for login
connector.Login(USER,PASS);
Object[] ids = {31,30,28,26};
Object[] params ={"partner_id","tax_line","section_id","invoice_line"};
connector.Read(ids,params);
//get information of openERP for specific id's
} catch (XMLRPCException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

Use an interface
public interface MyListener {
public void callback(Object result);
}
Your MainActivity must implement the interface
public class MyActivity extends Activity implements MyListener {
...
...
...
#override
public void callback(Object result) {
// getting the result value.
}
}
So when your thread finish, execute the callback() method:
MyListener ml;
ml.callback(result);
and the callback() method of you MainActivity will receive the object.

Related

How can I wait for an object filled asynchronously in Android UI thread without blocking it?

I have a singleton to handle the registration and elimination of an entity Profilo ( a Profile).
This entity is set by passing an identifier and gathering information on the server in an async way.
My problem is that when I have to return my instance of profilo if it's not still loaded it will return null.
public class AccountHandler {
private static AccountHandler istanza = null;
Context context;
private boolean logged;
private Profilo profilo;
private AccountHandler(Context context) {
this.context = context;
//initialization
//setting logged properly
assignField(this.getName());
}
}
public static AccountHandler getAccountHandler(Context context) {
if (istanza == null) {
synchronized (AccountHandler.class) {
if (istanza == null) {
istanza = new AccountHandler(context);
}
}
}
return istanza;
}
public void setAccount(String nickname, String accessingCode) {
logged = true;
assignField(nickname);
}
//other methods
private void assignField(String nickname) {
ProfiloClient profiloClient = new ProfiloClient();
profiloClient.addParam(Profilo.FIELDS[0], nickname);
profiloClient.get(new JsonHttpResponseHandler() {
#Override
public void onSuccess(int statusCode,
Header[] headers,
JSONArray response) {
JSONObject objson = null;
try {
objson = (JSONObject) response.getJSONObject(0);
} catch (JSONException e) {
e.printStackTrace();
}
AccountHandler accountHandler = AccountHandler.getAccountHandler(context);
// Profilo is created with a JSONObject
// **setProfilo is called in async**
**accountHandler.setProfilo(new Profilo(objson));**
}
});
}
private void setProfilo(Profilo profilo) {
this.profilo = profilo;
}
public Profilo getProfilo() {
if( logged && profilo == null)
//How can I wait that profilo is loaded by the JsonHttpResponseHandler before to return it
return this.profilo;
}
}
Instead of calling getProfilo you could use a callback mechanism in which the AccountHandler class notifies the caller when the profile has been loaded. e.g.
public void setAccount(String nickname, String accessingCode, MyCallback cb) {
assignField(nickname, cb);
}
private void assignField(String nickname, MyCallback cb) {
....
accountHandler.setProfilo(new Profilo(objson));
cb.onSuccess(this.profilo);
}
Create an inner Interface MyCallback (rename it) in your AccountHandler class
public class AccountHandler {
public interface MyCallback {
void onSuccess(Profilo profile);
}
}
Now whenever you call setAccount you will pass the callback and get notified when the profile is available e.g.
accountHandler.setAccount("Test", "Test", new AccountHandler.MyCallback() {
void onSuccess(Profilio profile) {
// do something with the profile
}
}
I added, as #Murat K. suggested, an interface to my Class that will provide a method to be call with the object when it is ready to be used.
public class AccountHandler {
public interface Callback {
void profiloReady(Profilo profilo);
}
}
This method is called in getProfilo in a Handler that makes recursive calls to getProfilo until profilo is ready to be used, then it call the callback method which class is passed as argument of getProfilo.
public void getProfilo(final Callback Callback) {
if( logged && (profilo == null || !profilo.isReady() ) {
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
getProfilo(Callback);
}
}, 500);
}else
Callback.profiloReady(profilo);
}
Example of getProfilo call
public class ProfiloCall implements AccountHandler.MyCallback {
#Override
public void profiloReady(Profilo profilo) {
//Use profilo as needed
//EXECUTED ONLY WHEN PROFILO IS READY
}
public void callerMethod() {
//useful code
accountHandler.getProfilo(this);
//other useful code
}
}

How to fix "android.view.ViewRootImpl$CalledFromWrongThreadException"

I want to fix error as follows:
"android.view.ViewRootImpl$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views."
here are my code.
public class MainActivity extends Activity {
#SuppressLint("NewApi") #Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
setContentView(R.layout.activity_main);
onShowMessage();
}
public void removeContent() {
LinearLayout list = (LinearLayout) findViewById(R.id.linearlayout_list);
list.removeAllViews();
}
public void onShowMessage() {
Thread myThread = new Thread(new Runnable() {
#Override
public void run() {
String id = "id1";
String message = "message1";
String response = HTTPUtils.HTTPPost(Global.MESSAGE_URL,
"id", id,
"message", message);
process(response);
}
});
myThread.start();
}
private void process(String response) {
if (response == null || response.equals("")) {
return;
} else {
try {
JSONObject json = null;
try {
json = FbUtil.parseJson(response);
} catch (FacebookError e) {
showErrorMessage();
}
if (json.has("exception")) {
showErrorMessage();
return;
} else {
Global.list = JsonParser.getInfo(json);
removeContent();
initView();
return;
}
} catch (JSONException e) {
}
return;
}
}
}
error occur on removeContent();
please help me.
You are updating Views in a different thread
removeContent();
initView();
Call this two methods in a UI thread like.
runOnUiThread(new Runnable() {
#Override
public void run() {
removeContent();
initView();
}
});

AsyncTask, doInBackground doesn't seem to work

I have that AsyncTask code
public class DiceTask extends AsyncTask<Socket, Void, int[]> {
private int[] arrayFromServer = new int[8];
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected int[] doInBackground(Socket...params) {
Socket soc = params[0];
try {
ObjectInputStream ois = new ObjectInputStream(soc.getInputStream());
int[] tempArray = (int[]) (ois.readObject());
return tempArray;
} catch (IOException | ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
#Override
protected void onProgressUpdate(Void...arg1) {
}
#Override
protected void onPostExecute(int[] result) {
arrayFromServer = result;
}
public int[] getTempDice() {
return arrayFromServer;
}
}
where is called this way into my main thread.
rollDiceButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
rollDiceButton.setEnabled(false);
rollDice();
task.execute(socket);
tempArray = task.getTempDice();
printDice(tempArray,pDice);
clickableDice(pDice);
}
});
where I am getting a null tempArray. If I change my onPreExecute to this
#Override
protected void onPreExecute() {
super.onPreExecute();
for(int i = 0; i < arrayFromServer.length; i++) {
arrayFromServer[i] = 1;
}
}
I am getting my dice as it should, all are one. The code I am running into the rollDice() is this
public void rollDice() {
try {
DataOutputStream sout = new DataOutputStream(socket.getOutputStream());
String line = "dice";
PrintStream out = new PrintStream(sout);
out.println(line);
} catch (UnknownHostException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
}
}
and I can see the results in the server.
You don't need to implement onPostExecute in your AsyncTask class definition. You also don't need the getTempDice function. You just need to override onPostExecute in an anonymous class and run your UI code in it.
rollDiceButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
rollDiceButton.setEnabled(false);
rollDice();
task = new DiceTask() {
#Override
public void onPostExecute(int[] result) {
tempArray = result;
printDice(tempArray,pDice);
clickableDice(pDice);
}
}.execute(socket);
}
});
Children of AsyncTask run in parallel with main Thread, you are trying access the attribute arrayFromServer right after to start the Thread. It's recommended you use a callback to retried the value wanted, making sure you get the value after Thread is done.
Making the follow changes can solve your problem. Let me know if you understand.
public class DiceTask extends AsyncTask<Socket, Void, int[]> {
public interface Callback {
void onDone(int[] arrayFromServer);
}
private Callback mCallback;
public DiceTask(Callback c) {
mCallback = c;
}
#Override
protected int[] doInBackground(Socket...params) {
Socket soc = params[0];
try {
ObjectInputStream ois = new ObjectInputStream(soc.getInputStream());
int[] tempArray = (int[]) (ois.readObject());
return tempArray;
} catch (IOException | ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
}
#Override
protected void onPostExecute(int[] result) {
mCallback.onDone(result);
}
}
rollDiceButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
rollDiceButton.setEnabled(false);
rollDice();
new DiceTask(new Callback() {
public void onDone(int[] tempArray) {
printDice(tempArray,pDice);
clickableDice(pDice);
}
}).execute(socket);
}
});

AsyncTask onPostExecute() not called in Unit Test Case

I've seen a bunch of posts related to this, but none seem to have the same issue I'm getting. GetBusinessRulesTask extends AsyncTask. When I execute this in a unit test case the onPostExecute() never gets called. However, if I use the real client code then onPostExecute() is called everytime. Not sure what I'm doing wrong here.
Test Case:
package com.x.android.test.api;
import java.util.concurrent.CountDownLatch;
import android.test.ActivityInstrumentationTestCase2;
import android.test.UiThreadTest;
import android.widget.Button;
import com.x.android.api.domain.businessrule.BusinessRules;
import com.x.android.api.exception.NetworkConnectionException;
import com.x.android.api.tasks.GetBusinessRulesTask;
import com.x.android.test.activity.SimpleActivity;
public class GetBusinessRulesTaskTest
extends
ActivityInstrumentationTestCase2<SimpleActivity> {
SimpleActivity mActivity;
Button mButton;
public GetBusinessRulesTaskTest() {
super("com.x.android.test.activity", SimpleActivity.class);
}
#Override
protected void setUp() throws Exception {
super.setUp();
mActivity = this.getActivity();
mButton = (Button) mActivity
.findViewById(com.x.android.test.activity.R.id.b1);
}
public void testPreconditions() {
assertNotNull(mButton);
}
#UiThreadTest
public void testCallBack() throws Throwable {
final CountDownLatch signal = new CountDownLatch(1);
final GetBusinessRulesTask task = (GetBusinessRulesTask) new GetBusinessRulesTask(
new GetBusinessRulesTask.Receiver<BusinessRules>() {
#Override
public void onReceiveResult(BusinessRules rules, Exception e) {
assertNotNull(rules);
assertNull(e);
signal.countDown();// notify the count down latch
}
});
task.start(mActivity.getApplicationContext());
try {
signal.await();// wait for callback
} catch (InterruptedException e1) {
fail();
e1.printStackTrace();
}
}
}
OnPostExecute:
#Override
protected void onPostExecute(AsyncTaskResponse<O> response) {
Log.d(TAG, "onPostExecuted");
if (mReceiver != null) {
mReceiver.onReceiveResult(response.getResponse(), response.getException());
}
}
DoInBackground:
#Override
protected AsyncTaskResponse<O> doInBackground(I... params) {
Log.d(TAG, "doInBackgroundr");
try {
Uri uri = createUri(params);
mBaseRequest = new GetLegacyRequest(uri);
String json = mBaseRequest.executeRequest();
O response = deserializeJson(json);
Log.d(TAG, "Returning AsyncTaskResponse");
return new AsyncTaskResponse<O>(response, null);
} catch (Exception e) {
Log.e(TAG, "Error", e);
/*
AsyncTaskResponse<O> maintenance = ReadBusinessControlledPropertiesTask.blockingCall(mServiceLocatorUrl);
if(maintenance.getException() == null) {
MaintenanceException mExcep = new MaintenanceException( maintenance.getResponse());
if (mExcep.isUnderMaintenance())
return new AsyncTaskResponse(null,mExcep);
}*/
return new AsyncTaskResponse<O>(null, e);
}
}
Start method()
public AsyncTask<Void, Void, AsyncTaskResponse<BusinessRules>> start(
Context context) throws NetworkConnectionException {
super.start(context);
Log.d(TAG, "start");
return execute();
}
FOUND THE ISSUE. Don't make your AsyncTask final and put it inside the runnable.
The fix:
public void testCallBack() throws Throwable {
final CountDownLatch signal = new CountDownLatch(1);
// Execute the async task on the UI thread! THIS IS KEY!
runTestOnUiThread(new Runnable() {
#Override
public void run() {
try {
GetBusinessRulesTask task = (GetBusinessRulesTask)new GetBusinessRulesTask(new GetBusinessRulesTask.Receiver<BusinessRules>() {
#Override
public void onReceiveResult(
BusinessRules rules, Exception e) {
assertNotNull(rules);
assertNull(e);
signal.countDown();// notify the count downlatch
}
});
task.start(mActivity.getApplicationContext());
} catch (Exception e) {
Log.e(TAG, "ERROR", e);
fail();
}
}
});
try {
signal.await();// wait for callback
} catch (InterruptedException e1) {
fail();
e1.printStackTrace();
}
}
FOUND THE ISSUE. Don't make your AsyncTask final and put it inside the runnable.
The fix:
public void testCallBack() throws Throwable {
final CountDownLatch signal = new CountDownLatch(1);
// Execute the async task on the UI thread! THIS IS KEY!
runTestOnUiThread(new Runnable() {
#Override
public void run() {
try {
GetBusinessRulesTask task = (GetBusinessRulesTask)new GetBusinessRulesTask(new GetBusinessRulesTask.Receiver<BusinessRules>() {
#Override
public void onReceiveResult(
BusinessRules rules, Exception e) {
assertNotNull(rules);
assertNull(e);
signal.countDown();// notify the count downlatch
}
});
task.start(mActivity.getApplicationContext());
} catch (Exception e) {
Log.e(TAG, "ERROR", e);
fail();
}
}
});
try {
signal.await();// wait for callback
} catch (InterruptedException e1) {
fail();
e1.printStackTrace();
}
}

Comments on my MVP pattern for Android

I am planning to use MVP pattern for my new Android project. I have done some sample code and I would like to know, have I implemented it correctly? Please give comments on the code and also post your suggestions.
my activity class I am extending it from my BaseView class and I am implementing an interface. this activity simply calls an webservice in a new thread and updates the value in the textview.
public class CougarTestView extends BaseView implements ICougarView,
OnClickListener {
CougarTestPresenter _presenter;
public String activityName = "CougarHome";
/** Called when the activity is first created. */`enter code here`
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState, activityName);
setContentView(R.layout.main);
_presenter = new CougarTestPresenter(this);
getSubmitBtn().setOnClickListener(this);
getCallInfoBtn().setOnClickListener(this);
}
private Button getCallInfoBtn() {
return (Button) findViewById(R.id.btn_callinfo);
}
public void setServiceValue(String retVal) {
// TODO Auto-generated method stub
getResultLabel().setText(retVal);
setPbar(false);
// toastMsg(retVal);
}
public void ResetPbar() {
getProgressBtn().setProgress(0);
}
public void setProcessProgress(int progress) {
if (getProgressBtn().getProgress() < 100) {
getProgressBtn().incrementProgressBy(progress);
} else {
setPbar(false);
}
}
private TextView getResultLabel() {
return (TextView) findViewById(R.id.result);
}
private Button getSubmitBtn() {
return (Button) findViewById(R.id.btn_triptype);
}
private ProgressBar getProgressBtn() {
return (ProgressBar) findViewById(R.id.pgs_br);
}
public void setPbar(boolean visible) {
if (!visible) {
getProgressBtn().setVisibility(View.GONE);
} else
getProgressBtn().setVisibility(View.VISIBLE);
}
#Override
public void setHttpResult(String retVal) {
// TODO Auto-generated method stub
setServiceValue(retVal);
}
private void toastMsg(String msg) {
Toast.makeText(this, msg, Toast.LENGTH_LONG).show();
}
public void onClick(View v) {
// TODO Auto-generated method stub
switch (v.getId()) {
case R.id.btn_triptype: {
try {
_presenter.valueFromService(RequestType.CallInfo, 0);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
break;
}
default:
setServiceValue("default");
}
}
}
My activity class: in my activity class i am having a textview and a button. when i press the button , it call the webservice to get the data in the presenter class. the presenter class calls the webservice parses the response and sets the value in the textview of the activity.
My presenter class
public class CougarTestPresenter {
ICougarView mIci;
RequestType mRtype;
public String result= "thisi s result i";
Handler mHandle;
public CougarTestPresenter(ICougarView ici) {
mIci = ici;
}
public void valueFromService(RequestType type, int x) throws Exception{
String url = getURLByType(type);
// GetServiceresult service = new GetServiceresult();
// service.execute(url);
Handler handle = new Handler() {
public void handleMessage(Message msg) {
switch (msg.what) {
case Globals.IO_EXPECTION: {
Toast.makeText(mIci.getContext(), msg.toString(),
Toast.LENGTH_LONG).show();
NetworkConnectivityListener connectivityListener = NetworkConnectivityListener
.getInstace();
mHandle = CustomHandler.getInstance(mIci.getContext(),
connectivityListener, mIci);
connectivityListener.registerHandler(mHandle,
Globals.CONNECTIVITY_MSG);
connectivityListener.startListening(mIci.getContext());
mIci.setPbar(false);
}
break;
case Globals.RHAPSODY_EXCEPTION:{
ExceptionInfo exInfo =null;
try {
exInfo = Utility.ParseExceptionData(msg.obj.toString());
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mIci.setServiceValue(exInfo.Message + exInfo.Type +exInfo.Detail);
// new HandleRhapsodyException(mIsa, exInfo);
}
break;
default: {
Toast.makeText(mIci.getContext(), msg.toString(),
Toast.LENGTH_LONG).show();
mIci.setServiceValue(msg.obj.toString());
}
}
}
};
ServiceResult thread = new ServiceResult(handle, url);
mIci.setPbar(true);
thread.start();
}
public String getURLByType(RequestType type) {
// TODO Auto-generated method stub
switch (type) {
case CallInfo: {
return ("www.gmail.com");
}
case TripType: {
return ("www.google.com");
}
default:
return ("www.cnet.com");
}
}
private class ServiceResult extends Thread {
Handler handle;
String url;
public ServiceResult(Handler handle, String url) {
this.handle = handle;
this.url = url;
}
public void run() {
sendExceptionLog(handle);
}
}
public void sendExceptionLog(Handler handle) {
DebugHttpClient httpClient = new DebugHttpClient();
HttpGet get = new HttpGet(
"https://192.168.194.141/TripService/service1/");
try {
HttpResponse response = httpClient.execute(get);
HttpEntity r_entity = response.getEntity();
String xmlString = EntityUtils.toString(r_entity);
// setdvrid.setText(xmlString + " "
// + response.getStatusLine().getStatusCode());
httpClient.getConnectionManager().shutdown();
if (response.getStatusLine().getStatusCode() != 200) {
handle.sendMessage(Message.obtain(handle, Globals.RHAPSODY_EXCEPTION,
xmlString));
result= Utility.ParseExceptionData(xmlString).Message;
}
else
{
handle.sendMessage(Message.obtain(handle, Globals.SERVICE_REPONSE,
response.getStatusLine().getStatusCode()
+ response.getStatusLine().getReasonPhrase()
+ xmlString));
}
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
handle.sendMessage(Message.obtain(handle, Globals.OTHER_EXPECTION,
e.getMessage().toString() + "she"));
} catch (IOException e) {
// TODO Auto-generated catch block
handle.sendMessage(Message.obtain(handle, Globals.IO_EXPECTION, e
.getMessage().toString() + "he"));
} catch (Exception e) {
handle.sendMessage(Message.obtain(handle, Globals.OTHER_EXPECTION,
e.getMessage().toString() + "it"));
}
}
the below interface is implemented in the activity class and the instance of the activity class is sent as interface object to the constructor of the presenter class.
my view interface
public interface ICougarView {
public void setServiceValue(String retVal);
public void setProcessProgress(int progress);
public void setPbar(boolean b);
public void ResetPbar();
public Context getContext();
}
Sorry for the late :)
I've use MVP on Android this way.
Activities are presenters. Every presenter has a link to model(s) (sometimes it is services, sometimes not, depending from the task) and to view(s). I create custom view and set it as the content view for activity.
See:
public class ExampleModel {
private ExampleActivity presenter;
public ExampleModel(ExampleActivity presenter) {
this.presenter = presenter;
}
//domain logic and so on
}
public class ExampleActivity extends Activity {
private ExampleModel model;
private ExampleView view;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
model = new ExampleModel(this);
view = new ExampleView(this);
setContentView(view);
}
// different presenter methods
}
public class ExampleView extends LinearLayout {
public ExampleView(Context context) {
super(context);
}
}
Also, I've discussed this topic here.
I should warn you, that Activity shouldn't be considered as the view. We had very bad expirience with it, when we wrote with PureMVC which considered Activity as view component. Activity is excellently suitable for controller/presenter/view model (I've tried all of them, I like MVP the most), it has excellent instrumentation for managing the views (View, Dialog and so on) while it's not a view itself.

Categories

Resources