I am using a source for image loading from url. The image links are stored in a json file and the json file to be hosted in a server. But I want the json file to store locally may be in assets or drawable.
My problem is if i use asset manager, it has to use stream manager and stream manager does not sit with url, which is realated with a context to load image url.
If i change the url of config_wallpaper_manifest_url to loacal asset url, ie. example.json, the same never loads.
what would be the possible solution for this? thanks.
public void loadData (Bundle savedInstanceState) {
// Check Network State
if (!NetworkUtil.getNetworkState(this)) {
final RetryFragment fragment = RetryFragment.getFragmentWithMessage("No connection");
this.addFragment(fragment, RetryFragment.TAG, true);
return;
}
if (savedInstanceState == null || savedInstanceState.get(KEY_LIST_DATA) == null) {
final String url = super.getResources().getString(R.string.config_wallpaper_manifest_url);
if (url != null && URLUtil.isValidUrl(url)) {
// Add Loading Fragment
final LoadingFragment fragment = new LoadingFragment();
this.addFragment(fragment, LoadingFragment.TAG, true);
// Load Data
final RestClientHandler handler = new RestClientHandler(this);
RestClient.get(this, url, handler);
}
} else {
Log.i(TAG, "Restored Instance");
this.mData = (ArrayList<NodeCategory>) savedInstanceState.get(KEY_LIST_DATA);
this.mPosition = savedInstanceState.getInt(KEY_LIST_POSITION);
if (this.mPosition != -1) {
mIgnoreSelection = true;
}
this.configureActionBar();
}
}
JSON is basically text. store it in app's internal memory. Or in a SQLite database. Have a look at this:
Creating folder in internal Memory to save files and retrieve them later
Related
I'm currently creating an app that needs to download a couple of videos then save the local path of it on a SQLite database.
At first, I wanted to get the URL of the video I downloaded but I can't seem to find anything that discusses about it. I tried to get COLUMN_MEDIAPROVIDER_URI and COLUMN_URI from the intent passed on the BroadcastReceiver for DownloadManager.ACTION_DOWNLOAD_COMPLETE but they return null.
Then I found about EXTRA_DOWNLOAD_ID. But if I use that, I still need to use something like a new HashMap that got the EXTRA_DOWNLOAD_ID of my download and the id of the video on my SQLite database for checking which is which.
I'm fine with that but I want to know if there's an easier way to do the thing I want.
I did this using OkHttp, as follows:
OkHttpClient client = new OkHttpClient();
Request request = new Request.Builder()
.url(YOUR_URL)
.build();
client.newCall(request).enqueue(new Callback() {
#Override
public void onFailure(Call call, IOException e) {
// ERROR MESSAGE
}
#Override
public void onResponse(Call call, Response response) throws IOException {
if (response.isSuccessful()) {
response.body().byteStream(); // byteStream with your result.
}
}
});
Another thing, maybe would be better if you store the videos on memory and just the address in your SQLite.
Using the code below from the SO question here
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (DownloadManager.ACTION_DOWNLOAD_COMPLETE.equals(action)) {
// get the DownloadManager instance
DownloadManager manager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
DownloadManager.Query q = new DownloadManager.Query();
Cursor c = manager.query(q);
if(c.moveToFirst()) {
do {
String name = c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME));
Log.i("DOWNLOAD LISTENER", "file name: " + name);
} while (c.moveToNext());
} else {
Log.i("DOWNLOAD LISTENER", "empty cursor :(");
}
c.close();
}
}
and saving the download id on my ArrayList I was able to make a simpler way to check which download is finished.
I modified it to look like this for my use case.
Cursor c = dlMgr.query(new DownloadManager.Query());
boolean found = false;
if(c.moveToFirst()) {
do {
String dlFilePath = c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME));
int dlId = Integer.parseInt( c.getString(c.getColumnIndex(DownloadManager.COLUMN_ID)) );
for(int x = 0; x < vidArrLst.size(); x++){
VideoAd va = vidArrLst.get(x);
if(va.getDownloadId() == dlId){
dbHelper.updateLocalPath(va.getVideoId(), dlFilePath);
va.setLocalPath(dlFilePath);
found = true;
break;
}
}
} while (c.moveToNext() && !found);
} else {
Log.d(TAG, "empty cursor :(");
}
UPDATE:
Sometimes this method will show that 2 downloads finished with the same file name which results to a video item to not have a local path. What I did is check if the local path is empty, download id is greater than 0, and if the download id is still downloading before playing a video so I can redownload a video and fix the gap and play the local file the next time the video needs to be played.
I am overriding this method for my WebView. And I am using the proper domain. When debugging using an Android simulator I only see a partial list of all of the cookies. The one in particular I'm requiring the value of isn't listed. Any suggestions? Source code below.
public override void OnPageFinished(WebView view, string url)
{
base.OnPageFinished(view, url);
_cookieManager.Flush();
string customerId = null;
var cookies = _cookieManager.GetCookie(Constants.DCH_DOMAIN);
Log.Info(TAG, string.Format("Cookies retrieved as {0}.", cookies));
if (cookies != null)
{
string[] tempList = cookies.Split(';');
foreach (var pair in tempList)
{
if (pair.Contains("wishlist_customer_id"))
{
string[] tempPair = pair.Split('=');
customerId = tempPair[1];
if (customerId != null)
{
Log.Info(TAG, string.Format("Customer ID retrieved as {0}.", customerId));
PCLStorage(customerId);
}
}
}
}
UPDATE There is another domain that stores cookies as part of this web session. No different in path, HTML, same site, secure, etc. between the four cookies. I'll attach what Chrome on my workstation looks like, showing these four cookies. Then I'll attach what my Android simulator's device log looks like, where I output the cookie collection based on the subclassed WebViewClient. Only two of the four cookies appear to be there. I inserted a SystemClock.Sleep(5000) before retrieving the cookies, in order to give them a chance to fully populate as well.
Chrome session
WebViewClient session
you should do cookied synchronization before load url to ensure complete cookie data like :
_cookieManager.flush ();
webView.loadUrl(url);
then get cookies int the OnPageFinished method :
public override void OnPageFinished(WebView view, string url)
{
base.OnPageFinished(view, url);
string customerId = null;
var cookies = _cookieManager.GetCookie(url);
Log.Info(TAG, string.Format("Cookies retrieved as {0}.", cookies));
if (cookies != null)
{
string[] tempList = cookies.Split(';');
foreach (var pair in tempList)
{
if (pair.Contains("wishlist_customer_id"))
{
string[] tempPair = pair.Split('=');
customerId = tempPair[1];
if (customerId != null)
{
Log.Info(TAG, string.Format("Customer ID retrieved as {0}.", customerId));
PCLStorage(customerId);
}
}
}
}
Thanks to Leo Zhu the issue has been resolved. Apparently before I load the WebView URL I needed to flush the CookieManager instance. This resulted in all of the cookies for this particular resource to appear and be available for querying. Hope that this might help anyone else who runs into a similar challenge!
im using the Google Drive API to save(use as backup) a database there, its working nice, but just if i use the ROOT
the Api Call:
MetadataChangeSet metadataChangeSet = new MetadataChangeSet.Builder()
......build();
Drive.DriveApi.getRootFolder(mGoogleApiClient)
.createFile(mGoogleApiClient, metadataChangeSet, result.getDriveContents())
.setResultCallback(fileCallback);
CallBack to Save the file:
final public ResultCallback < DriveFolder.DriveFileResult > fileCallback = new
ResultCallback < DriveFolder.DriveFileResult > () {
#Override
public void onResult(DriveFolder.DriveFileResult result) {
if (!result.getStatus().isSuccess()) {
return;
}
Log.i(TAG, "Successfull !");
}
};
i know that i must get the Folder, but if i do this, i need to do a CallBack to call another callback and then save?
isnt any way to directly do .createNewFile inside the FOLDER? without doing another Query for folder, check if the folder exist than create the folder, than use the DriveID, than create the file?
Remember, that in the GooDrive universe, the tree structure (folder, subfolder, ...) is a mirage. The Drive is a flat system of objects (files, folders) where one of the metadata fields is a 'set of parent IDs', that actually forms the notion of parentobject - childobject structure. Actually the classic tree (one parent many children) is not even enforced, so a child object can 'appear' in more that one parent.
This fact explains that you CAN NOT create an OS type of path in one shot. The objects (parents) must be created before their IDs can be plugged into child objects' metadata.
So the only way to do it, is to do what you say:
if folder exists
return it's ID
else
return ID of newly created one
create a child object with parent's ID
... and here is an example how I create a structure of type:
/ MYROOT / 2015 / 2015-12
(where MYROOT, 2015 , 2015-12 are subfloders the Drive root)
new Thread(new Runnable() {
#Override
public void run() {
DriveId Id = getFolder( getFolder( getFolder(
Drive.DriveApi.getRootFolder(mGAC).getDriveId(), "MYROOT"),
"2015",
"2015-12"
);
}
}).start();
GoogleApiClient mGAC;
DriveId getFolder(DriveId parentId, String titl) {
DriveId dId = null;
if (parentId != null && titl != null) try {
ArrayList<Filter> fltrs = new ArrayList<>();
fltrs.add(Filters.in(SearchableField.PARENTS, parentId));
fltrs.add(Filters.eq(SearchableField.TITLE, titl));
fltrs.add(Filters.eq(SearchableField.MIME_TYPE, "application/vnd.google-apps.folder"));
Query qry = new Query.Builder().addFilter(Filters.and(fltrs)).build();
MetadataBuffer mdb = null;
DriveApi.MetadataBufferResult rslt = Drive.DriveApi.query(mGAC, qry).await();
if (rslt.getStatus().isSuccess()) try {
mdb = rslt.getMetadataBuffer();
if (mdb.getCount() > 0)
dId = mdb.get(0).getDriveId();
} catch (Exception ignore) {}
finally { if (mdb != null) mdb.close(); }
if (dId == null) {
MetadataChangeSet meta = new Builder().setTitle(titl).setMimeType(UT.MIME_FLDR).build();
DriveFolderResult r1 = parentId.asDriveFolder().createFolder(mGAC, meta).await();
DriveFolder dFld = (r1 != null) && r1.getStatus().isSuccess() ? r1.getDriveFolder() : null;
if (dFld != null) {
MetadataResult r2 = dFld.getMetadata(mGAC).await();
if ((r2 != null) && r2.getStatus().isSuccess()) {
dId = r2.getMetadata().getDriveId();
}
}
}
} catch (Exception e) { e.printStackTrace(); }
return dId;
}
In the 'mdb.get(0).getDriveId()' area, you can see how hacky it gets when you try to impose a classic tree structure on the Drive. The search here can return multiple objects with the same name, so I use the first one. There should be some kind of error reporting here.
As you can see it is possible to replace callbacks with the 'await()' method, flattening the code into a classic DOS style spaghetti code as long as you place the whole sequence off-UI thread (asynctask, thread, ....)
Still, more elegant (IMO) option to accomplish this is to use recursive call from the result callback.
fromPath(Drive.DriveApi.getRootFolder(mGAC).getDriveId(), "MYROOT/2015/2015-12/file.jpg");
....
void fromPath(final DriveId parentId, final String path) {
if (parentId != null && path != null) {
final int idx = path.indexOf('/');
if (idx < 0) {
// reached last path item - probably file name
// CREATE FILE WITH patentID AND QUIT
return; //--- DONE -------------------->>>
}
final String titl = path.substring(0, idx);
ArrayList<Filter> fltrs = new ArrayList<>();
fltrs.add(Filters.in(SearchableField.PARENTS, parentId));
fltrs.add(Filters.eq(SearchableField.TITLE, titl));
fltrs.add(Filters.eq(SearchableField.MIME_TYPE, UT.MIME_FLDR));
Query qry = new Query.Builder().addFilter(Filters.and(fltrs)).build();
Drive.DriveApi.query(mGAC, qry).setResultCallback(new ResultCallback<DriveApi.MetadataBufferResult>() {
#Override
public void onResult(DriveApi.MetadataBufferResult rslt) {
MetadataBuffer mdb = null;
if (rslt != null && rslt.getStatus().isSuccess()) {
try {
mdb = rslt.getMetadataBuffer();
for (Metadata md : mdb) {
if (md.isTrashed()) continue;
fromPath(md.getDriveId(), path.substring(idx + 1));
return; //+++ first found, NEXT +++++++>>>
}
} finally { if (mdb != null) mdb.close(); }
}
MetadataChangeSet meta = new Builder().setTitle(titl).setMimeType(UT.MIME_FLDR).build();
parentId.asDriveFolder().createFolder(mGAC, meta)
.setResultCallback(new ResultCallback<DriveFolderResult>() {
#Override
public void onResult(DriveFolderResult rslt) {
DriveFolder dFld = rslt != null && rslt.getStatus().isSuccess() ? rslt.getDriveFolder() : null;
if (dFld != null) {
dFld.getMetadata(mGAC).setResultCallback(new ResultCallback<MetadataResult>() {
#Override
public void onResult(MetadataResult rslt) {
if (rslt != null && rslt.getStatus().isSuccess()) {
fromPath(rslt.getMetadata().getDriveId(), path.substring(idx + 1));
return; //+++ created, NEXT +++++++>>>
}
}
});
}
}
});
}
});
}
}
A WORD OF CAUTION:
As I called this sequence repeatedly, using the last DriveId (like 2015-12) as a parent of a JPEG image file, I have experienced weird behavior, like suddenly getting a 'null' result from 'Drive.DriveApi.getRootFolder(mGAC).getDriveId()'. It shouldn't happen and I assume it is a bug in GDAA. I contribute this to the fact that the DriveId used inside GDAA is 'invalid' until the folder gets committed and the ResourceId is resolved in underlying REST Api. Unfortunately, there is no completion event available for folder creation, so I resolved this by calling this sequence only once in onConnected() and caching the '2015-12's DriveId for later use as a parent of the image JPEG files.
Actually you can see it here (createTree() method) with text file on the tail, but the moment I switched the TEXT to JPEG, all hell broke lose.
Good Luck
Well, I have been working in a app to display news headings and contents from the site http://www.myagdikali.com
I am able to extract the data from 'myagdikali.com/category/news/national-news/' but there are only 10 posts in this page and there are links to other pages as 1,2,3... like myagdikali.com/category/news/national-news/page/2.
All I need to know is, how do I extract news from every possible pages under /national_news ? Is it even possible using Jsoup ?
Till now my code to extract data from a single page is:
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_all, container, false);
int i = getArguments().getInt(NEWS);
String topics = getResources().getStringArray(R.array.topics)[i];
switch (i) {
case 0:
url = "http://myagdikali.com/category/news/national-news";
new NewsExtractor().execute();
break;
.....
[EDIT]
private class NewsExtractor extends AsyncTask<Void, Void, Void> {
String title;
#Override
protected Void doInBackground(Void... params) {
while (status == OK) {
currentURL = url + String.valueOf(page);
try {
response = Jsoup.connect(currentURL).execute();
status = response.statusCode();
if (status == OK) {
Document doc = response.parse();
Elements urlLists = doc.select("a[rel=bookmark]");
for (org.jsoup.nodes.Element urlList : urlLists) {
String src = urlList.text();
myLinks.add(src);
}
title = doc.title();
}
} catch (IOException e) {
e.printStackTrace();
}
page++;
}
return null;
}
EDIT:
While trying to extract data from single page without loop, I can extract the data. But after using while loop, I get the error stating No adapter attached.
Actually I am loading the extracted data in the RecyclerView and onPostExecute is like this:
#Override
protected void onPostExecute(Void aVoid) {
layoutManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layoutManager);
myRecyclerViewAdapter = new MyRecyclerViewAdapter(getActivity(),myLinks);
recyclerView.setAdapter(myRecyclerViewAdapter);
}
Since you know the URL of the pages you need - http://myagdikali.com/category/news/national-news/page/X (where X is the page number between 2 and 446), you can loop through the URLs. You'll also need to use the Jsoup's response, to make sure that the page exists (the number 446 can be changed - I believe that it increases).
The code should be something like this:
final String URL = "http://myagdikali.com/category/news/national-news/page/";
final int OK = 200;
String currentURL;
int page = 2;
int status = OK;
Connection.Response response = null;
Document doc = null;
while (status == OK) {
currentURL = URL + String.valueOf(page); //add the page number to the url
response = Jsoup.connect(currentURL)
.userAgent("Mozilla/5.0")
.execute(); //you may add here userAgent/timeout etc.
status = response.statusCode();
if (status == OK) {
doc = response.parse();
//extract the info. you need
}
page++;
}
This is of course not fully working code - you'll have to add try-catch sentences, but the compiler will help you.
Hope this helps you.
EDIT:
1. I've editted the code - I've had to send a userAgent string in order to get response from the server.
2. The code runs on my machine, it prints lots of ????, because I don't have the proper fonts installed.
3. The error you're getting is from the Android part - something to do with your views. You haven't posted that piece of code...
4. Try to add the userAgent, it might solve it.
5. Please add the error and the code you're running to the original question by editting it, it's much more readable.
I'm looking at making a change in an app I'm working on (it's based off of this: http://goo.gl/rDBXVl) from loading a cloud based resource to a local based resource. I'm not particularly sure how I would go about doing this. I want to go from pulling a JSON file off the internet to pulling the JSON from my Assets folder.
I located the area in the app where it pulls the URL and loads the JSON but am unsure of what changes to make at this point.
public void loadData (Bundle savedInstanceState) {
// Check Network State
if (!NetworkUtil.getNetworkState(this)) {
final RetryFragment fragment = RetryFragment.getFragmentWithMessage("No connection");
this.addFragment(fragment, RetryFragment.TAG, true);
return;
}
if (savedInstanceState == null || savedInstanceState.get(KEY_LIST_DATA) == null) {
final String url = super.getResources().getString(R.string.config_wallpaper_manifest_url);
if (url != null && URLUtil.isValidUrl(url)) {
// Add Loading Fragment
final LoadingFragment fragment = new LoadingFragment();
this.addFragment(fragment, LoadingFragment.TAG, true);
// Load Data
final RestClientHandler handler = new RestClientHandler(this);
RestClient.get(this, url, handler);
}
} else {
Log.i(TAG, "Restored Instance");
this.mData = (ArrayList<NodeCategory>) savedInstanceState.get(KEY_LIST_DATA);
this.mPosition = savedInstanceState.getInt(KEY_LIST_POSITION);
if (this.mPosition != -1) {
mIgnoreSelection = true;
}
this.configureActionBar();
}
}
You have another option,
just save json in sharedpreferences. so easily read and write it.
Save sharedpreferences code bellow.
/**
* write SharedPreferences
* #param context
* #param name, name of preferences
* #param value, value of preferences
*/
public static void writePreferences(Context context,String name,String value)
{
SharedPreferences setting= context.getSharedPreferences("Give_your_filename", Context.MODE_PRIVATE);
SharedPreferences.Editor editor=setting.edit();
editor.putString(name, value);
editor.commit();
}