Witam,
Robie projekt Android i korzystam z chmury AWS. Proboje zmienic aplikacje AWS demo, ale mam pytanie: W main activity lacze sie z AWS i chcialbym utrzymac polaczenie w drugim activity, w ktorym mam zakladki. Czasami aplikacja sie wiesza i restartuje. dopiero sie ucze i nie wiem co jest problemem?
Moj projekt na gicie:
https://github.com/matszal/Android_App_4_FYP.git
utworz sobie jakas klase w ktorej bedziesz nawiazywal polaczenie do AWS. Zaimplmentuj intrfejs Parcelable w tej klasie.
Nastepnie przekaz instancje tej klasy do nasepnego Activity poprzez Bundle/Extras
Jeżeli to ma być współdzielone połączenie pomiędzy różne activity, to chyba przeniósłbym je do klasy typu service i wystawiał interfej przez bindera.
A jeszcze lepiej to poczytaj o Dependency Injecton, np. Dagger2
https://github.com/google/dagger
https://guides.codepath.com/android/dependency-injection-with-dagger-2
ogolnie na tej stronce masz bardzo duzo przykladow:
https://guides.codepath.com/android
Dziekuje wszystkim za rady i sugestie. zaraz zabieram sie do pracy i jak cos uda mi sie uporzadkowac, to napisze!
UPDATE:
Nie wiem jak udostepnic te polaczenie, zrobie wszytko w jednym activity. Dzieki za pomoc jeszcze raz pozdrawiam.
@Mateusz Szalkowski: musisz skorzystać z opcji którą podał Ci @nalik
Serwisy androidowe działają w tle. Odpalić je można międzyinnymi z activity. Ten serwis będzie trzymał połączenie z AWS niezależnie od tego w którym activity będziesz. Jak chcesz to zapodaj tutaj kod który piszesz.
Czesc @panryz! Wlasnie wzialem sie za probe zrobienia powiadomienia przy pomocy AWS, bo troche chcialem od tego odpoczac.
Ponizej wstawie kod, ktory probowalem napisac. Podziele go na main activity i tab1.
package com.example.mateusz.homesecurity;
import android.Manifest;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.os.StrictMode;
import android.support.annotation.NonNull;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import com.amazonaws.auth.CognitoCachingCredentialsProvider;
import com.amazonaws.mobileconnectors.iot.AWSIotKeystoreHelper;
import com.amazonaws.mobileconnectors.iot.AWSIotMqttClientStatusCallback;
import com.amazonaws.mobileconnectors.iot.AWSIotMqttLastWillAndTestament;
import com.amazonaws.mobileconnectors.iot.AWSIotMqttManager;
import com.amazonaws.mobileconnectors.iot.AWSIotMqttQos;
import com.amazonaws.regions.Region;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.iot.AWSIotClient;
import com.amazonaws.services.iot.model.AttachPrincipalPolicyRequest;
import com.amazonaws.services.iot.model.CreateKeysAndCertificateRequest;
import com.amazonaws.services.iot.model.CreateKeysAndCertificateResult;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.charset.Charset;
import java.security.KeyStore;
import java.util.UUID;
import permissions.dispatcher.NeedsPermission;
import permissions.dispatcher.OnNeverAskAgain;
import permissions.dispatcher.OnShowRationale;
import permissions.dispatcher.PermissionRequest;
import permissions.dispatcher.RuntimePermissions;
@RuntimePermissions
public class MainActivity extends AppCompatActivity{
static final String LOG_TAG = MainActivity.class.getCanonicalName();
private static String CUSTOMER_SPECIFIC_ENDPOINT; //cse
private static String COGNITO_POOL_ID; //cp_id
private static String AWS_IOT_POLICY_NAME; //policy
private static Regions MY_REGION = Regions.EU_WEST_1;
private static String KEYSTORE_NAME; //key_name
private static String KEYSTORE_PASSWORD; //key_pass;
private static String CERTIFICATE_ID; //cert_id
String clientId;
String keystorePath;
String keystoreName;
String keystorePassword;
KeyStore clientKeyStore = null;
String certificateId;
private String fileName = "/credentials_app.json";
//TextView keysWindow;
Button btnConnect;
Button btnDisconnect;
TextView tvClientId;
TextView tvStatus;
File sdcard = new File("sdcard/AWS_CREDENTIALS" + fileName);
static AWSIotClient mIotAndroidClient;
static AWSIotMqttManager mqttManager;
CognitoCachingCredentialsProvider credentialsProvider;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Allowing Strict mode policy for Nougat support
StrictMode.VmPolicy.Builder builder = new StrictMode.VmPolicy.Builder();
StrictMode.setVmPolicy(builder.build());
Toast.makeText(this, "App started succesfully!",
Toast.LENGTH_SHORT).show();
Log.i("info", "Done creating the app");
//check for storage access permissions
final MainActivity temp = this;
MainActivityPermissionsDispatcher.readStorageWithPermissionCheck(temp);
readStorage();
//Check if app has an access to internet
if (!AppStatus.getInstance(this).isOnline()) {
// Toast.makeText(this,"Please check your internet connection",Toast.LENGTH_LONG).show();
Log.v("Home", "############################You are not online!!!!");
//btnConnect.setEnabled(false);
}
tvClientId = (TextView) findViewById(R.id.tvClientId);
tvStatus = (TextView) findViewById(R.id.tvStatus);
btnConnect = (Button)findViewById(R.id.btnConnect);
btnConnect.setOnClickListener(connect);
btnConnect.setEnabled(false);
btnDisconnect = (Button)findViewById(R.id.btnDisconnect);
btnDisconnect.setOnClickListener(disconnect);
// MQTT client IDs are required to be unique per AWS IoT account.
// This UUID is "practically unique" but does not _guarantee_
// uniqueness.
clientId = UUID.randomUUID().toString();
tvClientId.setText(clientId);
// Initialize the AWS Cognito credentials provider
credentialsProvider = new CognitoCachingCredentialsProvider(
getApplicationContext(), // context
COGNITO_POOL_ID, // Identity Pool ID
MY_REGION // Region
);
Region region = Region.getRegion(MY_REGION);
// MQTT Client
mqttManager = new AWSIotMqttManager(clientId, CUSTOMER_SPECIFIC_ENDPOINT);
// Set keepalive to 10 seconds. Will recognize disconnects more quickly but will also send
// MQTT pings every 10 seconds.
mqttManager.setKeepAlive(10);
// Set Last Will and Testament for MQTT. On an unclean disconnect (loss of connection)
// AWS IoT will publish this message to alert other clients.
AWSIotMqttLastWillAndTestament lwt = new AWSIotMqttLastWillAndTestament("my/lwt/topic",
"Android client lost connection", AWSIotMqttQos.QOS0);
mqttManager.setMqttLastWillAndTestament(lwt);
// IoT Client (for creation of certificate if needed)
mIotAndroidClient = new AWSIotClient(credentialsProvider);
mIotAndroidClient.setRegion(region);
keystorePath = getFilesDir().getPath();
keystoreName = KEYSTORE_NAME;
keystorePassword = KEYSTORE_PASSWORD;
certificateId = CERTIFICATE_ID;
// To load cert/key from keystore on filesystem
try {
if (AWSIotKeystoreHelper.isKeystorePresent(keystorePath, keystoreName)) {
if (AWSIotKeystoreHelper.keystoreContainsAlias(certificateId, keystorePath,
keystoreName, keystorePassword)) {
Log.i(LOG_TAG, "Certificate " + certificateId
+ " found in keystore - using for MQTT.");
// load keystore from file into memory to pass on connection
clientKeyStore = AWSIotKeystoreHelper.getIotKeystore(certificateId,
keystorePath, keystoreName, keystorePassword);
btnConnect.setEnabled(true);
} else {
Log.i(LOG_TAG, "Key/cert " + certificateId + " not found in keystore.");
}
} else {
Log.i(LOG_TAG, "Keystore " + keystorePath + "/" + keystoreName + " not found.");
}
} catch (Exception e) {
Log.e(LOG_TAG, "An error occurred retrieving cert/key from keystore.", e);
}
if (clientKeyStore == null) {
Log.i(LOG_TAG, "Cert/key was not found in keystore - creating new key and certificate.");
new Thread(new Runnable() {
@Override
public void run() {
try {
// Create a new private key and certificate. This call
// creates both on the server and returns them to the
// device.
CreateKeysAndCertificateRequest createKeysAndCertificateRequest =
new CreateKeysAndCertificateRequest();
createKeysAndCertificateRequest.setSetAsActive(true);
final CreateKeysAndCertificateResult createKeysAndCertificateResult;
createKeysAndCertificateResult =
mIotAndroidClient.createKeysAndCertificate(createKeysAndCertificateRequest);
Log.i(LOG_TAG,
"Cert ID: " +
createKeysAndCertificateResult.getCertificateId() +
" created.");
// store in keystore for use in MQTT client
// saved as alias "default" so a new certificate isn't
// generated each run of this application
AWSIotKeystoreHelper.saveCertificateAndPrivateKey(certificateId,
createKeysAndCertificateResult.getCertificatePem(),
createKeysAndCertificateResult.getKeyPair().getPrivateKey(),
keystorePath, keystoreName, keystorePassword);
// load keystore from file into memory to pass on
// connection
clientKeyStore = AWSIotKeystoreHelper.getIotKeystore(certificateId,
keystorePath, keystoreName, keystorePassword);
// Attach a policy to the newly created certificate.
// This flow assumes the policy was already created in
// AWS IoT and we are now just attaching it to the
// certificate.
AttachPrincipalPolicyRequest policyAttachRequest =
new AttachPrincipalPolicyRequest();
policyAttachRequest.setPolicyName(AWS_IOT_POLICY_NAME);
policyAttachRequest.setPrincipal(createKeysAndCertificateResult
.getCertificateArn());
mIotAndroidClient.attachPrincipalPolicy(policyAttachRequest);
runOnUiThread(new Runnable() {
@Override
public void run() {
btnConnect.setEnabled(true);
}
});
} catch (Exception e) {
Log.e(LOG_TAG,
"Exception occurred when generating new private key and certificate.",
e);
}
}
}).start();
}
}
@NeedsPermission(Manifest.permission.READ_EXTERNAL_STORAGE)
void readStorage() {
try {
FileInputStream fis = new FileInputStream((sdcard));
String jsonStr = null;
try{
FileChannel fc = fis.getChannel();
MappedByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
jsonStr = Charset.defaultCharset().decode(bb).toString();
}catch(Exception e){
// Toast.makeText(this, "exception after reading json object!", Toast.LENGTH_SHORT).show();
}
finally {
fis.close();
}
JSONObject jsonObj = new JSONObject(jsonStr);
JSONObject data = jsonObj.getJSONObject("credentials");
CUSTOMER_SPECIFIC_ENDPOINT = data.getString("cse");
COGNITO_POOL_ID = data.getString("cp_id");
AWS_IOT_POLICY_NAME = data.getString("policy");
KEYSTORE_NAME = data.getString("key_name");
KEYSTORE_PASSWORD = data.getString("key_pass");
CERTIFICATE_ID = data.getString("cert_id");
} catch (IOException e) {
Toast.makeText(getApplicationContext(), "Error While reading file", Toast.LENGTH_SHORT).show();
} catch (JSONException e){
Toast.makeText(getApplicationContext(), "JSON exception", Toast.LENGTH_SHORT).show();
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
MainActivityPermissionsDispatcher.onRequestPermissionsResult(this, requestCode, grantResults);
}
@OnShowRationale(Manifest.permission.READ_EXTERNAL_STORAGE)
void readStorageRationale(final PermissionRequest request) {
new AlertDialog.Builder(this)
.setMessage("To read internal storage, enable Read Storage")
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
request.proceed();
}
})
.setNegativeButton("Deny", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
request.cancel();
}
})
.show();
}
@OnNeverAskAgain(Manifest.permission.READ_EXTERNAL_STORAGE)
void readStorageNever() {
Toast.makeText(this, "You have denied permission", Toast.LENGTH_SHORT).show();
}
public static class AppStatus {
private static AppStatus instance = new AppStatus();
static Context context;
ConnectivityManager connectivityManager;
NetworkInfo wifiInfo, mobileInfo;
boolean connected = false;
public static AppStatus getInstance(Context ctx) {
context = ctx.getApplicationContext();
return instance;
}
public boolean isOnline() {
try {
connectivityManager = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
connected = networkInfo != null && networkInfo.isAvailable() &&
networkInfo.isConnected();
return connected;
} catch (Exception e) {
System.out.println("CheckConnectivity Exception: " + e.getMessage());
Log.v("connectivity", e.toString());
}
return connected;
}
}
View.OnClickListener connect = new View.OnClickListener() {
boolean alreadyEcecuted = false;
@Override
public void onClick(final View v) {
Log.d(LOG_TAG, "clientId = " + clientId);
try {
mqttManager.connect(clientKeyStore, new AWSIotMqttClientStatusCallback() {
@Override
public void onStatusChanged(final AWSIotMqttClientStatus status,
final Throwable throwable) {
Log.d(LOG_TAG, "Status = " + String.valueOf(status));
runOnUiThread(new Runnable() {
@Override
public void run() {
if (status == AWSIotMqttClientStatus.Connecting) {
tvStatus.setText("Connecting...");
} else if (status == AWSIotMqttClientStatus.Connected) {
tvStatus.setText("Connected");
btnConnect.setEnabled(false);
if (!alreadyEcecuted){
W tym momencie po polaczeniu chcialem dodac intent i zaczac drugie activity
Intent intent = new Intent(v.getContext(), TabbedActivity.class);
v.getContext().startActivity(intent);
alreadyEcecuted = true;
}
} else if (status == AWSIotMqttClientStatus.Reconnecting) {
if (throwable != null) {
Log.e(LOG_TAG, "Connection error.", throwable);
}
tvStatus.setText("Reconnecting");
alreadyEcecuted = false;
} else if (status == AWSIotMqttClientStatus.ConnectionLost) {
if (throwable != null) {
Log.e(LOG_TAG, "Connection error.", throwable);
}
tvStatus.setText("Disconnected");
alreadyEcecuted = false;
btnConnect.setEnabled(true);
} else {
tvStatus.setText("Disconnected");
btnConnect.setEnabled(true);
}
}
});
}
});
} catch (final Exception e) {
Log.e(LOG_TAG, "Connection error.", e);
tvStatus.setText("Error! " + e.getMessage());
}
}
};
View.OnClickListener disconnect = new View.OnClickListener() {
@Override
public void onClick(View v) {
try {
mqttManager.disconnect();
} catch (Exception e) {
Log.e(LOG_TAG, "Disconnect error.", e);
}
}
};
}
A tak wyglada drugie activity
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import com.amazonaws.mobileconnectors.iot.AWSIotMqttNewMessageCallback;
import com.amazonaws.mobileconnectors.iot.AWSIotMqttQos;
import android.widget.EditText;
import android.widget.TextView;
import java.io.UnsupportedEncodingException;
import static com.example.mateusz.homesecurity.MainActivity.LOG_TAG;
import static com.example.mateusz.homesecurity.MainActivity.mqttManager;
/**
* Created by Mateusz on 25/03/2018.
*/
public class Tab1Fragment extends Fragment {
private static final String TAG = "Tab1Fragment";
//private Button btnTest1;
private Button btnPublish;
private Button btnClearAll;
private TextView incomingText;
private EditText outgoingText;
private String id;
private String endPoint;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.tab1_fragment, container, false);
subscribe();
btnPublish = (Button)view.findViewById(R.id.btnPublish);
btnPublish.setOnClickListener(publishClick);
btnClearAll = (Button)view.findViewById(R.id.btnClear);
btnClearAll.setOnClickListener(clearAll);
incomingText = (TextView)view.findViewById(R.id.incomingTxt);
outgoingText = (EditText)view.findViewById(R.id.outgoingTxt);
return view;
}
public void subscribe() {
final String topic = "mytopic/iot/led";
Log.d(LOG_TAG, "topic = " + topic);
try {
mqttManager.subscribeToTopic(topic, AWSIotMqttQos.QOS0, new AWSIotMqttNewMessageCallback() {
@Override
public void onMessageArrived(final String topic, final byte[] data) {
try {
String message = new String(data, "UTF-8");
Log.d(LOG_TAG, "Message arrived:");
Log.d(LOG_TAG, " Topic: " + topic);
Log.d(LOG_TAG, " Message: " + message);
incomingText.append(message+"\n");
} catch (UnsupportedEncodingException e) {
Log.e(LOG_TAG, "Message encoding error.", e);
}
}
});
} catch (Exception e) {
Log.e(LOG_TAG, "Subscription error.", e);
}
}
View.OnClickListener publishClick = new View.OnClickListener() {
@Override
public void onClick(View v) {
final String topic = "mytopic/iot/led";
final String msg = outgoingText.getText().toString();
try {
mqttManager.publishString(msg, topic, AWSIotMqttQos.QOS0);
} catch (Exception e) {
Log.e(LOG_TAG, "Publish error.", e);
}
}
};
View.OnClickListener clearAll = new View.OnClickListener() {
@Override
public void onClick(View view) {
incomingText.setText("");
outgoingText.setText("");
}
};
}
Jezeli potrzebujesz wiecej info, to pisz prosze i bardzo dziekuje Ci za chec pomocy!
Z tego co na szybko patrzę to całego tego try {} catch {}
z onCreate()
musiałbyś wepchać do klasy która rozszerza Service.
https://developer.android.com/training/run-background-service/create-service.html
Potem to drugie activity musi się do tego istniejącego serwisu zbindować.
@panryz: Wielkie dzieki! Jutro na spokojnie z tym zawalcze i dam znac jak to poszlo. Dzis poczytam dokumentacje i obejrze jakies tutki. Dzieki za pomoc!