I have an Android application, which has a lot of articles. If you open an article a new activity is created. Now there is a part in the activity which is always the same, but it send a request to the server to get the data. I was thinking to make a fragment which will load the data only once (probably in MainActivity) and show it to all activities. Is this possible and how do I do it?
I also tried creating a fragment, but it still loads the data every time a new activity is created. Here is the XML code.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<TextView
android:id="#+id/textView"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#000000" />
<!-- There is more layout, but I don't think it is needed for now -->
</RelativeLayout>
And Java
private class getMessage extends AsyncTask<Void , Void, Void>{
#Override
protected Void doInBackground(Void... params) {
DefaultHttpClient httpclient = new DefaultHttpClient();
HttpGet httppost = new HttpGet("http:///www.example.com");
HttpResponse response;
try {
response = httpclient.execute(httppost);
HttpEntity ht = response.getEntity();
BufferedHttpEntity buf = new BufferedHttpEntity(ht);
InputStream is = buf.getContent();
BufferedReader r = new BufferedReader(new InputStreamReader(is));
total = new StringBuilder();
String line;
while ((line = r.readLine()) != null) {
total.append(line + "\n");
}
}
catch (ClientProtocolException e) {}
catch (IOException e) {}
return null;
}
#Override
protected void onPostExecute(Void args){
try{
textView.setText(total.toString());
}
catch(Exception e){}
}
}
And the code to add the fragment
FragmentManager fragMan = getSupportFragmentManager();
android.support.v4.app.FragmentTransaction fragTransaction = fragMan.beginTransaction();
Fragment fragment = new Fragment();
fragTransaction.add(R.id.fragment_replace, fragment);
fragTransaction.commit();
Fragments belong to only one activity. After you commit() the transaction, that fragment "belongs" to that activity.
If you want a higher level sharing or network related data, I suggest you to implement it in a Bound Service and have activities or fragments to get this data directly from the Service
If you have only one activity in your application, it is possible. But you cant show the loaded fragment in many activities.
Only after adding the fragment to the container, you can attach and detach a fragment.
You are trying to cache data using Fragment, but as you can see at documentation:
A Fragment represents a behavior or a portion of user interface in an
Activity
source: Fragments
Fragment should be used to avoid "copy-paste" in user interface code.
But you are trying to cache the data from network. This is not mission of Fragment. This is not Tier when you should process data. At Fragment you should only load already cached data.
I can recomend you choose one of next solutions:
1). Use SQLite database to cache data.
If you want to cache data in SQLite, I recomend you use pattern, which Virgil Dobjanschi described at Google I/O conference in 2010(link to video here)
Also, I think this example may be helpful for implementing this pattern.
2). Use some network libraries, which can help you to cache data
Robospice - is a modular android library that makes writing asynchronous long running tasks easy. It is specialized in network requests, supports caching and offers REST requests out-of-the box using extension modules.
link: Robospice
example project: Robospice+Retrofit
Short description how to cache:
getSpiceManager().execute(githubRequest, "github", DurationInMillis.ONE_MINUTE, new ListContributorRequestListener());
"github" - is a key. DurationInMillis.ONE_MINUTE - time while cached data will be actual. This means, that if you are executed this request first time, data will be loaded from network. If you are executed this request second time during 1 minute, then data will be loaded from local cache.
Possible values of DurationInMillis from docs:
**Field Summary**
static long ALWAYS
Deprecated.
static long ALWAYS_EXPIRED
Data in cache will never be returned, a network call will always be performed.
static long ALWAYS_RETURNED
Data in cache will always be returned.
static long NEVER
Deprecated.
static long ONE_DAY
static long ONE_HOUR
static long ONE_MINUTE
static long ONE_SECOND
static long ONE_WEEK
OkHttp - from docs:
OkHttp is an HTTP client that’s efficient by default:
HTTP/2 and SPDY support allows all requests to the same host to share
a socket.
Connection pooling reduces request latency (if SPDY isn’t
available).
Transparent GZIP shrinks download sizes.
Response caching avoids the network completely for repeat requests.
link: OkHttp
example project: samples
Short description how to cache:
// Create an HTTP client that uses a cache on the file system. Android applications should use
// their Context to get a cache directory.
OkHttpClient okHttpClient = new OkHttpClient();
File cacheDir = new File(System.getProperty("java.io.tmpdir"), UUID.randomUUID().toString());
HttpResponseCache cache = new HttpResponseCache(cacheDir, 1024);
okHttpClient.setResponseCache(cache);
Full example here
Related
I am developing a camera app. I want to take pictures and send them to Server.
I have 3 Classes.
SimpleCamera - handles camera and gets images in byte[] form
SendInfo - handles HTTP request
MainActivity - middleman for above to happen
When I open MainActivity a new instance of SimpleCamera is created and preview is reflected on a textureView. When I click a button on MainActivity getImageBytes method of SimpleCamera returns image data as a byte Array. Then I create an instance of SendInfo for sending this data to server.
The problem starts here: I trigger getImageBytes() and move imageBytes to my byte Array. Then put this array into request body in SendInfo like below.
private void clickFunciton(){
byte[] imageBytes = simpleCamera.getImageBytes();
SendInfo si = new SendInfo();
si.imageBytes = imageBytes;
si.send();
}
But si.send() block is triggered before getImageBytes(). That's why I get Array is null error. What approach should I consider?
I have a Map:
Map<String, String> noidung = new HashMap<>();
The Map receives data from Firebase and I show them in a Gridview. Everything worked well.
But when the phone goes offline, I want the data I have loaded to remain on the Gridview.
My idea is to store the Map noidung to a file (I think SharedPreference) to use offline. I have tried very much solutions but failed.
Take a look at this:
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
From the documentation:
Firebase apps automatically handle temporary network interruptions for you. Cached data will still be available while offline and your writes will be resent when network connectivity is recovered. Enabling disk persistence allows our app to also keep all of its state even after an app restart. We can enable disk persistence with just one line of code.
https://firebase.google.com/docs/database/android/offline-capabilities
In addition, you can keep specific locations in sync:
DatabaseReference scoresRef = FirebaseDatabase.getInstance().getReference("scores");
scoresRef.keepSynced(true);
Setting persistence enabled has to be the very first call to the Firebase API. So before you do any queries/etc. A good location is in your Application subclass:
public class MainApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
FirebaseDatabase.getInstance().setPersistenceEnabled(true);
}
Don't forget to update your manifest accordingly:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="my.package" >
...
<application android:name=".MainApplication">
...
</application>
</manifest>
It's really that easy. And that is what Firebase makes so awesome :-)
I have written a Java app that synchronises Google Groups on our Google Apps for Education domain (similar in function to Google Apps School Directory Sync, but customised for some of our specific needs).
The synchronisation works, but it is slow because it is performing each task individually. I know that there are API interfaces for batching operations, but I can't find any examples of how this is implemented with the Java API.
The code I'm using looks similar to this (authentication and other setup is taken care of elsewhere):
try
{
Member m = new Member ();
m.setEmail (member);
m.setRole ("MEMBER");
service.members ().insert (group, m).execute ();
}
catch (Exception e)
{
// ERROR handling
}
Instead of executing these operations one-by-one, I would like to batch them instead. Can anyone tell me how?
Look here: Batch Java API
For example:
BatchRequest batch = new BatchRequest(httpTransport, httpRequestInitializer);
batch.setBatchUrl(new GenericUrl(/*your customized batch URL goes here*/));
batch.queue(httpRequest1, dataClass, errorClass, callback);
batch.queue(httpRequest2, dataClass, errorClass, callback);
batch.execute();
Remember, that:
The body of each part is itself a complete HTTP request, with its own
verb, URL, headers, and body. The HTTP request must only contain the
path portion of the URL; full URLs are not allowed in batch requests.
UPDATE
Look also here, how to build batch with Google Batch API:
https://github.com/google/google-api-java-client
UPDATE 2
Try something like this:
// Create the Storage service object
Storage storage = new Storage(httpTransport, jsonFactory, credential);
// Create a new batch request
BatchRequest batch = storage.batch();
// Add some requests to the batch request
storage.objectAccessControls().insert("bucket-name", "object-key1",
new ObjectAccessControl().setEntity("user-123423423").setRole("READER"))
.queue(batch, callback);
storage.objectAccessControls().insert("bucket-name", "object-key2",
new ObjectAccessControl().setEntity("user-guy#example.com").setRole("READER"))
.queue(batch, callback);
storage.objectAccessControls().insert("bucket-name", "object-key3",
new ObjectAccessControl().setEntity("group-foo#googlegroups.com").setRole("OWNER"))
.queue(batch, callback);
// Execute the batch request. The individual callbacks will be called when requests finish.
batch.execute();
From here: Batch request with Google Storage Json Api (JAVA)
I am most concerned about Performance issue and don't want users to wait for progress.
I have a chatActivity, where i show a ListView.
Here i send a chatMessage
Chats chat = new Chats(chatBox.getText().toString(),Chats.TYPE_MINE, dt.format(now));
chat.personId = chatee.getMyId();
chat.isDelievered = Chats.DELIEVERED_NONE;
chats.add(chat);
mAdapter.notifyDataSetChanged();
Notice that Chat delievery is set to NONE Right now. So basically the message is being added to the Chat List even its not delivered yet.
Now on back thread here is what's happening
It takes few seconds to send message where i do this
boolean bool = sendMessage(m);
if (bool)
chatee.isDelievered = Chats.DELIEVERED_DONE; (MESSAGE SENT)
if (chatee.isDelievered == Chats.DELIEVERED_DONE)
{
app.mDbHelper.saveMessage(chatee); // SAVING TO DATABASE
Intent i = new Intent(Constants.REFRESH_NOTIF).putExtra("refresh",Constants.REFRESH_NOTIF);
context.sendBroadcast(i);
}
It will send a broadcast to the activity.
Now here is the problem.
Broadcast call this function
public void callUIMethodForRefresh(Intent intent)
{
String ref = intent.getStringExtra("refresh");
if (ref == null)
{
}
else if (ref.equals(Constants.REFRESH_NOTIF))
{
}
}
Here i am confused of how can I reset that previous Chat object added to my List.
Points to be noted , i can be sending messages at a very fast speed and the refresh could be called for an old message whereas a new message is already typed.
ONE way is i make a For loop and check for all the "ChatList" array for the message sent and then replace its delivery notice, but again this is very low performance incase i have 1000+ objects in the list.
Is there any way, i can attach the sqlite database with my listView adapter that automatically detects the changes and reset the listView etc and etc?
What could be the best strategies here to avoid performance issues.
I would suggest looking into ContentProviders and Loaders (specifically a CusorLoader). Combining these with a CursorAdapter, you can use the ContentProvider which inserts/deletes/updates your sqlite database and notifies your loader to reload it's dataset and update the CursorAdapter/ListView.
I have a very simple program http downloading program as following. The file is very small, like 200K.
The problem is that when I use 3G connection, sometimes one download will be stucked for a very long time. But I can watch youtube very well with 3G connection which means the 3G network is good. Is there anything wrong with the code?
There is no problem when I use wifi connection.
for (int chunkno = 0; chunkno < 10000000; ++chunkno)
{
try
{
AndroidHttpClient client = AndroidHttpClient.newInstance("Android");
HttpGet request = new HttpGet("http://ipaddress/vbr_100.mp4");
HttpResponse response = client.execute(request);
recvbytes = response.getEntity().getContentLength();
File f = new File(Environment.getExternalStoragePublicDirectory("bill"), "f");
if (!f.exists())
{
f.createNewFile();
}
response.getEntity().writeTo(new FileOutputStream(f));
}
catch (IOException ex)
{
}
}
I would recommend you to use android DownloadManager package, which takes care of all issues related to huge files download.
Copied from the Android document site:
The download manager is a system service that handles long-running HTTP downloads. Clients may request that a URI be downloaded to a particular destination file. The download manager will conduct the download in the background, taking care of HTTP interactions and retrying downloads after failures or across connectivity changes and system reboots.
A very good example of using DownloadManager is provided here.
Hope this helps !!