I'm calling an Async class from my main activity class. When the POST has been executed I want to return the result back to the main activity.
public class MainActivity extends Activity implements OnClickListener, AsyncResponse{
public Context context;
PostKey asyncTask = new PostKey(context);
public void onCreate(Bundle savedInstanceState) {
asyncTask.delegate = this;
}
public void onClick(View v) {
asyncTask.delegate = this;
new PostKey(context).execute(keyValue);
}
public void processFinish(String output){
//this you will received result fired from async class of onPostExecute(result) method.
Log.d("Result", output);
}
}
public class PostKey extends AsyncTask<String, String, String> {
public AsyncResponse delegate = null;
public Context context;
public PostKey(Context context){
this.context = context.getApplicationContext();
}
#Override
protected String doInBackground(String... params) {
return postData(params[0]);
}
#Override
protected void onPostExecute(String result){
this.context = context.getApplicationContext();
delegate = (AsyncResponse) context;
}
delegate.processFinish(result);
}
public interface AsyncResponse {
void processFinish(String output);
}
Whenever I try to run the app I immediately get a fatal error caused by a nullpointer exception. The nullpointer refers to the following:
public PostKey(Context context){
this.context = context.getApplicationContext();
}
&
PostKey asyncTask = new PostKey(context);
In the second case I can get that context is empty, but I have to pass the variable here.
Activity is already a Context, so you don't to keep a reference to it. Just use this. On the other hand the Activity has to go through its lifecycle before you can use the context. Remove
public Context context;
PostKey asyncTask = new PostKey(context);
and add
PostKey asyncTask = new PostKey(this);
in your onCreate. And please, add super.onCreate(savedInstanceState); as first thing in your onCreate
Hello Oryna you passing null context value as in parameter just replace these lines with this
new PostKey(context).execute(keyValue);
to
new PostKey(MainActivity.this).execute(keyValue);
and the constructor for the async task replace the code
public PostKey(Context context){
this.context = context.getApplicationContext();
}
with
public PostKey(Context context){
this.context = context;
}
try to use this.context = getApplicationContext(); instead
Related
How do I create a method inside onCreate() method? When I am creating its showing error:
Syntax error on token void # expected
And if method can not be created inside onCreate() method than please tell me how do I create a method outside the onCreate() and pass mContext and mActivity from the onCreate() method.
public class MainActivity extends Activity{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
yourmethod();
}
public void yourmethod(){
// your code here
}
}
public class MainActivity extends Activity {
//Declare a class variable to use in this class
public <data-type> mContext;
public <data-type> mActivity;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mContext = <Your value>;
mActivity = <Your value>;
myMethod (mContext , mActivity);
}
private void myMethod (<data-type> mContext, <data-type> mActivity) {
/*
Your Code Goes Here
*/
}
}
*Note that tags like should be replaced by actual types without inequality signs, such as "int" and "short".
I have this setup
MainActivity Class creates BTHandler which is a utility class. It passes activity context and application context.
public class MainActivity extends Activity implements View.OnClickListener{
protected void onCreate(Bundle savedInstanceState) {
...
currentBT = new BTHandle(this, MainActivity.this);
}
public Handler handler = new Handler() {
#Override
public void handleMessage(android.os.Message msg) {
...
super.handleMessage(msg);
}
};
}
This is the Utiliy class. It uses both context for some computation and when is required it creates ConnectThread, to start a connection with a BT device. It passes the activity context so ConnectThread can send a message through the Handler.
class BTHandle {
private final Context mainActivityContext;
private final Activity mainActivity;
...
public BTHandle(final Context context, final Activity activity){
mainActivityContext = context;
mainActivity = activity;
}
f(){
ConnectThread connectAsClient = new ConnectThread(mainActivityContext, BTDevice, mBluetoothAdapter, BTUuid);
new Thread(connectAsClient).start();
}
}
And Finally here comes the error. This is ConnectThread. I want to send a message from here to MainActivity. But compiler says it cant resolve handler. So I'm guessing the context doesn't come trough it.
public class ConnectThread implements Runnable {
private final Context mainActivity;
public ConnectThread(Context context, BluetoothDevice device, BluetoothAdapter adapter, UUID BT_UUID) {
...
mainActivity = context;
}
#Override
public void run() {
...
Message completeMessage = mainActivity.handler.obtainMessage(555, "CONNECTED");
completeMessage.sendToTarget();
}
}
How can I pass the context in the right way so ConnectThread can see handler?
You can either pass in the MainActivity object all the way down to ConnectRunnable i.e :
private final MainActivity mainActivity;
public ConnectThread(MainActivity context, BluetoothDevice device,
BluetoothAdapter adapter, UUID BT_UUID) {
...
mainActivity = context;
}
Or change your call to:
Message completeMessage =
((MainActivity)(Activity)mainActivity)).handler.obtainMessage(555, "CONNECTED");
Also, your handler is bound to leak memory.
Have a look at this for the fix: How to Leak a Context: Handlers & Inner Classes
You can also define a public and static MainActvity variable and use it in your other class :
public class MainActivity extends Activity implements View.OnClickListener{
public static MainActivity mainActivity;
protected void onCreate(Bundle savedInstanceState) {
...
mainActivity = this;
currentBT = new BTHandle(this, MainActivity.this);
}
public Handler handler = new Handler() {
#Override
public void handleMessage(android.os.Message msg) {
...
super.handleMessage(msg);
}
};
}
and in your other class :
public class ConnectThread implements Runnable {
private MainActivity mainActivity;
public ConnectThread(Context context, BluetoothDevice device, BluetoothAdapter adapter, UUID BT_UUID) {
...
mainActivity = MainActivity.mainActivity;
}
#Override
public void run() {
...
Message completeMessage = mainActivity.handler.obtainMessage(555, "CONNECTED");
completeMessage.sendToTarget();
}
}
I have service, which gets data from API and sends this data to BroadcastReceiver class. Also, I create interface OnReceiveListener, which used in Activity. Look at the code here:
Activity:
public class StartActivity extends AppCompatActivity
implements MyBroadcastReceiver.OnReceiveListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_start);
MyBroadcastReceiver receiver = new MyBroadcastReceiver();
receiver.setOnReceiveListener(this);
LocalBroadcastManager.getInstance(this).registerReceiver(receiver,
new IntentFilter(MyBroadcastReceiver.START));
...
}
#Override
public void onReceive(Intent intent) {
// Do smth here
}
}
MyBroadcastReceiver:
public class MyBroadcastReceiver extends BroadcastReceiver {
public static final String START = "com.example.myapp.START";
public static final String GET_LINKS = "com.example.myapp.GET_LINKS";
private OnReceiveListener onReceiveListener = null;
public interface OnReceiveListener {
void onReceive(Intent intent);
}
public void setOnReceiveListener(Context context) {
this.onReceiveListener = (OnReceiveListener) context;
}
#Override
public void onReceive(Context context, Intent intent) {
if(onReceiveListener != null) {
onReceiveListener.onReceive(intent);
}
}
}
Service isn't important on this question.
---- Question ----
So, what's problem: I want to use this receiver in fragment, but when it sets context - I get exception "enable to cast". What I should to do on this case?
Here is my code in fragment:
public class MainFragment extends Fragment
implements MyBroadcastReceiver.OnReceiveListener {
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
MyBroadcastReceiver myBroadcastReceiver = new MyBroadcastReceiver();
myBroadcastReceiver.setOnReceiveListener(getContext());
LocalBroadcastManager.getInstance(getContext()).registerReceiver(myBroadcastReceiver,
new IntentFilter(MyBroadcastReceiver.GET_LINKS));
}
#Override
public void onReceive(Intent intent) {
// Do smth here
}
}
Your MainFragment class implements your OnReceiveListener interface, not its Context as returned by getContext(). Instead of passing a Context object into setOnReceiveListener(), try directly passing an OnReceiveListener instance. Then your fragment and activity can both call setOnReceiveListener(this).
you don't need to dynamically register the receiver. i believe you must have registered it in manifest using <receiver> tag.
this is not required:
LocalBroadcastManager.getInstance(getContext()).registerReceiver(myBroadcastReceiver,
new IntentFilter(MyBroadcastReceiver.GET_LINKS));
and about callback registering listener, instead of using getContext() use MainFragment.this like this:
myBroadcastReceiver.setOnReceiveListener(MainFragment.this);
After searching for hours for the appropriate way to implement such a solution to this problem, I've found a way finally. It is based on RussHWolf's answer. The complete solution with code is below:
In this way, a setListener() method is exposed so that Fragment or Activity can set the listener by sending an instance of IStatusChangeListener.
public class StatusChangeReceiver extends BroadcastReceiver {
private IStatusChangeListener listener;
public void setListener(IStatusChangeListener listener) {
this.listener = listener;
}
#Override
public void onReceive(Context context, Intent intent) {
if (NetworkUtil.isNetworkConnected()) {
listener.onConnected();
} else {
listener.onDisconnected();
}
}
}
This is the interface:
public interface IStatusChangeListener {
void onConnected(String status);
void onDisonnected(String status);
}
Now, it is required to have an instance of IStatusChangeListener interface instead of implementing the IStatusChangeListener interface. And then, pass this instance of IStatusChangeListener to setListener() method.
public class MainFragment extends Fragment { //Not implementing the interface
private IStatusChangeListener listener = new IStatusChangeListener() {
#Override
void onConnected(String status) {
//some log here
}
#Override
void onDisonnected(String status) {
//some log here
}
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
StatusChangeReceiver r = new StatusChangeReceiver();
r.setListener(listener); // pass the IStatusChangeListener instance
LocalBroadcastManager.getInstance(getContext()).registerReceiver(r, new IntentFilter("connectionStatus"));
}
}
Note: Always use LocalBroadcastManager if you register BroadcastReceiver from Fragment.
I want to generate a TextView inside AsyncTask's onPostExecute like this :
protected class AsyncTranslator extends AsyncTask<String, JSONObject, String>
{
#Override
protected String doInBackground(String... params) {
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
#Override
protected void onPostExecute(String mymeaning) {
TextView myView = new TextView(this);
myView.setText(Html.fromHtml(myString));
}
}
But it gives error telling me that this cannot be applied to AsyncTranslator.
Can you tell me how I can generate textViews inside AsyncTask onPostExecute? Thanks.
From the documentation the possible constructors are
TextView(Context context)
TextView(Context context, AttributeSet attrs)
TextView(Context context, AttributeSet attrs, int defStyleAttr)
TextView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes)
but you are doing
TextView myView = new TextView(this);
inside AsyncTranslator which is incorrect.
You can easily create a TextView inside your AsyncTask if you have a reference to your context. See this thread to get a reference to your context.
EDIT
It seems that you already have a reference to your context, so just do
TextView myView = new TextView(context);
In AsyncTask you shouldn't make operations on base UI thread and here you are trying to do it. Try to create new Interface which lets you to pass the result.
public interface asyncTaskInterface {
public void printEditText();
}
Then in your AsyncTask:
protected class AsyncTranslator extends AsyncTask<String, JSONObject, String>
{
public asyncTaskInterface delegate;
#Override
protected String doInBackground(String... params) {
}
#Override
protected void onPreExecute() {
super.onPreExecute();
Toast.makeText(context, "Please wait.", Toast.LENGTH_SHORT).show();
}
#Override
protected void onPostExecute(String mymeaning) {
delegate.printEditText();
}
}
In your result class you have to implement the interface and pass the class to your async task as delegate:
public class myClassActivity implements asyncTaskInterface ...
before you will call async task assign the delegate:
AsyncTranslator translator = new AsyncTranslator();
translator.delegate = this;
translator.execute();
At the end in your activity overwrite the method from your intrface and build in it the TextView.
First create an interface like this:
public interface onTextViewCreatedListener {
public void onTextViewCreated(TextView tv);
}
Then change your AsyncTranslator class like this
protected class AsyncTranslator extends AsyncTask<String, JSONObject, String>
{
private onTextViewCreatedListener onTextViewCreatedListener;
public AsyncTranslator(onTextViewCreatedListener onTextViewCreatedListener){
this.onTextViewCreatedListener = onTextViewCreatedListener;
}
#Override
protected String doInBackground(String... params) {
}
#Override
protected void onPreExecute() {
super.onPreExecute();
Toast.makeText(context, "Please wait.", Toast.LENGTH_SHORT).show();
}
#Override
protected void onPostExecute(String mymeaning) {
//since you have passed context to Toast in onPreExecute use that context here also.
TextView myView = new TextView(context);
myView.setText(Html.fromHtml(myString));
if(onTextViewCreatedListener!=null){
onTextViewCreatedListener.onTextViewCreated(myView);
}
}
}
and then use AsyncTranslator class in your activity class like this:
AsyncTranslator asyncTranslator = new AsyncTranslator(new onTextViewCreatedListener() {
#Override
public void onTextViewCreated(TextView tv) {
//you can use your created textview here
}
});
that context should be passed from your activity where you are going to call aynctask.execute()
I have two classes; the first is an asynctask and the other is an ConnectionDetector class
which contains the code shown here (3rd step),
public class myTask extends AsyncTask<String,Void,String>{
private Context context;
ConnectionDetector connectiondetector = new ConnectionDetector(context);
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
//CHECK INTERNET CONNECTION
if(connectiondetector.isConnectingToInternet()){ //method from connectiondetector.java
//do something
}
}
when I run this code I get a null pointer exception at the if statement.
is it because of the context, how do I fix this?
the asynctask class is called from a different activity ( partosrecord.class )
Pass context to the constructor of oyur asynctask from your activity class
new myTask(ActivityName.this).execute(params);
In your asynctask
public class myTask extends AsyncTask<String,Void,String>{
ConnectionDetector connectiondetector
Context mcontext;
public myTask(Context context)
{
mcontext= context;
connectiondetector = new ConnectionDetector(mcontext);
}
#Override
protected void onPreExecute() {
super.onPreExecute();
if(connectiondetector.isConnectingToInternet()){
//dosomething
}
}
Code where u call asynctask:-
myTask site = new myTask(this);
site.execute();
or use this below code on AsyncTask
public class myTask extends AsyncTask<String,Void,String>{
private Context context;
ConnectionDetector connectiondetector
public myTask(Context con)
{
context=con;
connectiondetector = new ConnectionDetector(context);
}
#Override
protected void onPreExecute() {
// TODO Auto-generated method stub
super.onPreExecute();
//CHECK INTERNET CONNECTION
if(connectiondetector.isConnectingToInternet()){ //method from connectiondetector.java
//do something }
}